diff --git a/.github/actions/delete-deployments/action.yml b/.github/actions/delete-deployments/action.yml new file mode 100644 index 00000000000..20b7d0eefe5 --- /dev/null +++ b/.github/actions/delete-deployments/action.yml @@ -0,0 +1,59 @@ +name: Delete Deployments +description: Delete deployments by env and ref +inputs: + environment: + required: true + description: The Github environment to filter deployments by + ref: + required: true + description: The ref to filter deployments by + dry-run: + required: false + description: Whether to actually delete deployments or not + github-token: + description: "The Github token to use for authentication" + required: true + default: ${{ github.token }} + num-of-pages: + required: false + description: The number of pages (of 100 per page) to fetch deployments from, set to 'all' to fetch all deployments + default: "all" + starting-page: + required: false + description: The page to start fetching deployments from, only valid if num-of-pages is set to a number + repository: + required: false + description: The owner and repository name to delete deployments from, defaults to the current repository, ex. 'smartcontractkit/chainlink' + default: ${{ github.repository }} + +runs: + using: composite + steps: + - uses: pnpm/action-setup@c3b53f6a16e57305370b4ae5a540c2077a1d50dd #v2.2.4 + with: + version: ^8.0.0 + + - uses: actions/setup-node@v3 + with: + node-version: "18" + cache: "pnpm" + cache-dependency-path: "./.github/actions/delete-deployments/pnpm-lock.yaml" + + - name: Install dependencies + shell: bash + run: pnpm i --prod + working-directory: "./.github/actions/delete-deployments" + + - name: Run deployment deleter + shell: bash + run: pnpm start + env: + NUM_OF_PAGES: ${{ inputs.num-of-pages }} + STARTING_PAGE: ${{ inputs.starting-page }} + GITHUB_TOKEN: ${{ inputs.github-token }} + ENVIRONMENT: ${{ inputs.environment }} + REF: ${{ inputs.ref }} + DRY_RUN: ${{ inputs.dry-run }} + OWNER: ${{ inputs.owner }} + REPOSITORY: ${{ inputs.repository }} + working-directory: "./.github/actions/delete-deployments" diff --git a/.github/actions/delete-deployments/index.ts b/.github/actions/delete-deployments/index.ts new file mode 100644 index 00000000000..e38f1957d21 --- /dev/null +++ b/.github/actions/delete-deployments/index.ts @@ -0,0 +1,232 @@ +import { Octokit } from "@octokit/action"; +import { info, warning, isDebug } from "@actions/core"; +import { throttling } from "@octokit/plugin-throttling"; +import { retry } from "@octokit/plugin-retry"; + +async function main() { + const { + dryRun, + environment, + numOfPages, + owner, + ref, + repo, + debug, + startingPage, + } = getInputs(); + const octokit = getOctokit(debug); + + const deployments = await getDeployments({ + octokit, + owner, + repo, + environment, + ref, + paginateOptions: { + numOfPages, + startingPage, + }, + }); + const deploymentIds = deployments.map((d) => d.id); + if (dryRun) { + info(`Dry run: would delete deployments (${deploymentIds.length})`); + return; + } + + info(`Deleting deployments (${deploymentIds.length})`); + const deleteDeployments = deploymentIds.map(async (id) => { + const sharedArgs = { + owner, + repo, + deployment_id: id, + request: { + retries: 0, + }, + }; + + const setStatus = await octokit.repos + .createDeploymentStatus({ + ...sharedArgs, + state: "inactive", + }) + .then(() => true) + .catch((e) => { + warning( + `Marking deployment id ${id} to "inactive" failed: ${e.message}` + ); + return false; + }); + if (!setStatus) return false; + + return octokit.repos + .deleteDeployment({ + ...sharedArgs, + }) + .then(() => true) + .catch((e) => { + warning(`Deleting deployment id ${id} failed: ${e.message}`); + return false; + }); + }); + + const processed = await Promise.all(deleteDeployments); + const succeeded = processed.filter((p) => !!p); + info( + `Successfully deleted ${succeeded.length}/${processed.length} deployments` + ); +} +main(); + +function getInputs() { + const debug = !!(process.env.DEBUG || isDebug()); + + const dryRun = process.env.DRY_RUN === "true"; + + const environment = process.env.ENVIRONMENT; + if (!environment) throw new Error("ENVIRONMENT not set"); + + const ref = process.env.REF; + + const repository = process.env.REPOSITORY; + if (!repository) throw new Error("REPOSITORY not set"); + const [owner, repo] = repository.split("/"); + + const rawStartingPage = process.env.STARTING_PAGE; + + let startingPage: number | undefined; + if (rawStartingPage) { + startingPage = parseInt(rawStartingPage); + if (isNaN(startingPage)) { + throw new Error(`STARTING_PAGE is not a number: ${rawStartingPage}`); + } + if (startingPage < 0) { + throw new Error( + `STARTING_PAGE must be a positive integer or zero: ${rawStartingPage}` + ); + } + info(`Starting from page ${startingPage}`); + } + + const rawNumOfPages = process.env.NUM_OF_PAGES; + let numOfPages: "all" | number = "all"; + if (rawNumOfPages === "all") { + info("Fetching all pages of deployments"); + } else { + const parsedPages = parseInt(rawNumOfPages || ""); + if (isNaN(parsedPages)) { + throw new Error(`NUM_OF_PAGES is not a number: ${rawNumOfPages}`); + } + if (parsedPages < 1) { + throw new Error(`NUM_OF_PAGES must be greater than 0: ${rawNumOfPages}`); + } + numOfPages = parsedPages; + } + + if (numOfPages === "all" && startingPage) { + throw new Error(`Cannot use STARTING_PAGE with NUM_OF_PAGES=all`); + } + + const parsedInputs = { + environment, + ref, + owner, + repo, + numOfPages, + startingPage, + dryRun, + debug, + }; + info(`Configuration: ${JSON.stringify(parsedInputs)}`); + return parsedInputs; +} + +function getOctokit(debug: boolean) { + const OctokitAPI = Octokit.plugin(throttling, retry); + const octokit = new OctokitAPI({ + log: debug ? console : undefined, + throttle: { + onRateLimit: (retryAfter, options, octokit, retryCount) => { + octokit.log.warn( + // Types are busted from octokit + //@ts-expect-error + `Request quota exhausted for request ${options.method} ${options.url}` + ); + + octokit.log.info(`Retrying after ${retryAfter} seconds!`); + return true; + }, + onSecondaryRateLimit: (_retryAfter, options, octokit) => { + octokit.log.warn( + // Types are busted from octokit + //@ts-expect-error + `SecondaryRateLimit detected for request ${options.method} ${options.url}` + ); + return true; + }, + }, + }); + + return octokit; +} + +async function getDeployments({ + octokit, + owner, + repo, + environment, + ref, + paginateOptions, +}: { + octokit: ReturnType; + owner: string; + repo: string; + environment: string; + ref?: string; + paginateOptions: { + numOfPages: number | "all"; + startingPage?: number; + }; +}) { + const listDeploymentsSharedArgs: Parameters< + typeof octokit.repos.listDeployments + >[0] = { + owner, + repo, + environment, + ref, + per_page: 100, + request: { + retries: 20, + }, + }; + + if (paginateOptions.numOfPages === "all") { + info(`Fetching all deployments`); + const deployments = await octokit.paginate(octokit.repos.listDeployments, { + ...listDeploymentsSharedArgs, + }); + + return deployments; + } else { + info( + `Fetching ${ + paginateOptions.numOfPages * listDeploymentsSharedArgs.per_page! + } deployments` + ); + const deployments: Awaited< + ReturnType + >["data"] = []; + + const offset = paginateOptions.startingPage || 0; + for (let i = offset; i < paginateOptions.numOfPages + offset; i++) { + const deploymentPage = await octokit.repos.listDeployments({ + ...listDeploymentsSharedArgs, + page: i, + }); + + deployments.push(...deploymentPage.data); + } + + return deployments; + } +} diff --git a/.github/actions/delete-deployments/package.json b/.github/actions/delete-deployments/package.json new file mode 100644 index 00000000000..7045cb35797 --- /dev/null +++ b/.github/actions/delete-deployments/package.json @@ -0,0 +1,25 @@ +{ + "name": "delete-deployments", + "version": "1.0.0", + "description": "", + "main": "index.ts", + "scripts": { + "start": "ts-node -T .", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@actions/core": "^1.10.1", + "@octokit/action": "^6.0.5", + "@octokit/plugin-retry": "^6.0.0", + "@octokit/plugin-throttling": "^7.0.0", + "ts-node": "^10.9.1" + }, + "devDependencies": { + "@octokit/types": "^11.1.0", + "@types/node": "^18", + "typescript": "^5.2.2" + } +} diff --git a/.github/actions/delete-deployments/pnpm-lock.yaml b/.github/actions/delete-deployments/pnpm-lock.yaml new file mode 100644 index 00000000000..a5553eb3dee --- /dev/null +++ b/.github/actions/delete-deployments/pnpm-lock.yaml @@ -0,0 +1,350 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@actions/core': + specifier: ^1.10.1 + version: 1.10.1 + '@octokit/action': + specifier: ^6.0.5 + version: 6.0.5 + '@octokit/plugin-retry': + specifier: ^6.0.0 + version: 6.0.0(@octokit/core@5.0.0) + '@octokit/plugin-throttling': + specifier: ^7.0.0 + version: 7.0.0(@octokit/core@5.0.0) + ts-node: + specifier: ^10.9.1 + version: 10.9.1(@types/node@18.17.15)(typescript@5.2.2) + +devDependencies: + '@octokit/types': + specifier: ^11.1.0 + version: 11.1.0 + '@types/node': + specifier: ^18 + version: 18.17.15 + typescript: + specifier: ^5.2.2 + version: 5.2.2 + +packages: + + /@actions/core@1.10.1: + resolution: {integrity: sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==} + dependencies: + '@actions/http-client': 2.1.1 + uuid: 8.3.2 + dev: false + + /@actions/http-client@2.1.1: + resolution: {integrity: sha512-qhrkRMB40bbbLo7gF+0vu+X+UawOvQQqNAA/5Unx774RS8poaOhThDOG6BGmxvAnxhQnDp2BG/ZUm65xZILTpw==} + dependencies: + tunnel: 0.0.6 + dev: false + + /@cspotcode/source-map-support@0.8.1: + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + dev: false + + /@jridgewell/resolve-uri@3.1.1: + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + engines: {node: '>=6.0.0'} + dev: false + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: false + + /@jridgewell/trace-mapping@0.3.9: + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: false + + /@octokit/action@6.0.5: + resolution: {integrity: sha512-jcCZb+jR4nzHgj86wlUvbTv92hiZ4OWpI9dIoWRilbtT4HuVVNFZvQih8X/YE2GMVrLCVbBD0xkjeq+1m8Rcpw==} + engines: {node: '>= 18'} + dependencies: + '@octokit/auth-action': 4.0.0 + '@octokit/core': 5.0.0 + '@octokit/plugin-paginate-rest': 8.0.0(@octokit/core@5.0.0) + '@octokit/plugin-rest-endpoint-methods': 9.0.0(@octokit/core@5.0.0) + '@octokit/types': 11.1.0 + undici: 5.24.0 + dev: false + + /@octokit/auth-action@4.0.0: + resolution: {integrity: sha512-sMm9lWZdiX6e89YFaLrgE9EFs94k58BwIkvjOtozNWUqyTmsrnWFr/M5LolaRzZ7Kmb5FbhF9hi7FEeE274SoQ==} + engines: {node: '>= 18'} + dependencies: + '@octokit/auth-token': 4.0.0 + '@octokit/types': 11.1.0 + dev: false + + /@octokit/auth-token@4.0.0: + resolution: {integrity: sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==} + engines: {node: '>= 18'} + dev: false + + /@octokit/core@5.0.0: + resolution: {integrity: sha512-YbAtMWIrbZ9FCXbLwT9wWB8TyLjq9mxpKdgB3dUNxQcIVTf9hJ70gRPwAcqGZdY6WdJPZ0I7jLaaNDCiloGN2A==} + engines: {node: '>= 18'} + dependencies: + '@octokit/auth-token': 4.0.0 + '@octokit/graphql': 7.0.1 + '@octokit/request': 8.1.1 + '@octokit/request-error': 5.0.0 + '@octokit/types': 11.1.0 + before-after-hook: 2.2.3 + universal-user-agent: 6.0.0 + dev: false + + /@octokit/endpoint@9.0.0: + resolution: {integrity: sha512-szrQhiqJ88gghWY2Htt8MqUDO6++E/EIXqJ2ZEp5ma3uGS46o7LZAzSLt49myB7rT+Hfw5Y6gO3LmOxGzHijAQ==} + engines: {node: '>= 18'} + dependencies: + '@octokit/types': 11.1.0 + is-plain-object: 5.0.0 + universal-user-agent: 6.0.0 + dev: false + + /@octokit/graphql@7.0.1: + resolution: {integrity: sha512-T5S3oZ1JOE58gom6MIcrgwZXzTaxRnxBso58xhozxHpOqSTgDS6YNeEUvZ/kRvXgPrRz/KHnZhtb7jUMRi9E6w==} + engines: {node: '>= 18'} + dependencies: + '@octokit/request': 8.1.1 + '@octokit/types': 11.1.0 + universal-user-agent: 6.0.0 + dev: false + + /@octokit/openapi-types@18.0.0: + resolution: {integrity: sha512-V8GImKs3TeQRxRtXFpG2wl19V7444NIOTDF24AWuIbmNaNYOQMWRbjcGDXV5B+0n887fgDcuMNOmlul+k+oJtw==} + + /@octokit/plugin-paginate-rest@8.0.0(@octokit/core@5.0.0): + resolution: {integrity: sha512-2xZ+baZWUg+qudVXnnvXz7qfrTmDeYPCzangBVq/1gXxii/OiS//4shJp9dnCCvj1x+JAm9ji1Egwm1BA47lPQ==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '>=5' + dependencies: + '@octokit/core': 5.0.0 + '@octokit/types': 11.1.0 + dev: false + + /@octokit/plugin-rest-endpoint-methods@9.0.0(@octokit/core@5.0.0): + resolution: {integrity: sha512-KquMF/VB1IkKNiVnzJKspY5mFgGyLd7HzdJfVEGTJFzqu9BRFNWt+nwTCMuUiWc72gLQhRWYubTwOkQj+w/1PA==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '>=5' + dependencies: + '@octokit/core': 5.0.0 + '@octokit/types': 11.1.0 + dev: false + + /@octokit/plugin-retry@6.0.0(@octokit/core@5.0.0): + resolution: {integrity: sha512-a1/A4A+PB1QoAHQfLJxGHhLfSAT03bR1jJz3GgQJZvty2ozawFWs93MiBQXO7SL2YbO7CIq0Goj4qLOBj8JeMQ==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '>=5' + dependencies: + '@octokit/core': 5.0.0 + '@octokit/request-error': 5.0.0 + '@octokit/types': 11.1.0 + bottleneck: 2.19.5 + dev: false + + /@octokit/plugin-throttling@7.0.0(@octokit/core@5.0.0): + resolution: {integrity: sha512-KL2k/d0uANc8XqP5S64YcNFCudR3F5AaKO39XWdUtlJIjT9Ni79ekWJ6Kj5xvAw87udkOMEPcVf9xEge2+ahew==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': ^5.0.0 + dependencies: + '@octokit/core': 5.0.0 + '@octokit/types': 11.1.0 + bottleneck: 2.19.5 + dev: false + + /@octokit/request-error@5.0.0: + resolution: {integrity: sha512-1ue0DH0Lif5iEqT52+Rf/hf0RmGO9NWFjrzmrkArpG9trFfDM/efx00BJHdLGuro4BR/gECxCU2Twf5OKrRFsQ==} + engines: {node: '>= 18'} + dependencies: + '@octokit/types': 11.1.0 + deprecation: 2.3.1 + once: 1.4.0 + dev: false + + /@octokit/request@8.1.1: + resolution: {integrity: sha512-8N+tdUz4aCqQmXl8FpHYfKG9GelDFd7XGVzyN8rc6WxVlYcfpHECnuRkgquzz+WzvHTK62co5di8gSXnzASZPQ==} + engines: {node: '>= 18'} + dependencies: + '@octokit/endpoint': 9.0.0 + '@octokit/request-error': 5.0.0 + '@octokit/types': 11.1.0 + is-plain-object: 5.0.0 + universal-user-agent: 6.0.0 + dev: false + + /@octokit/types@11.1.0: + resolution: {integrity: sha512-Fz0+7GyLm/bHt8fwEqgvRBWwIV1S6wRRyq+V6exRKLVWaKGsuy6H9QFYeBVDV7rK6fO3XwHgQOPxv+cLj2zpXQ==} + dependencies: + '@octokit/openapi-types': 18.0.0 + + /@tsconfig/node10@1.0.9: + resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} + dev: false + + /@tsconfig/node12@1.0.11: + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + dev: false + + /@tsconfig/node14@1.0.3: + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + dev: false + + /@tsconfig/node16@1.0.4: + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + dev: false + + /@types/node@18.17.15: + resolution: {integrity: sha512-2yrWpBk32tvV/JAd3HNHWuZn/VDN1P+72hWirHnvsvTGSqbANi+kSeuQR9yAHnbvaBvHDsoTdXV0Fe+iRtHLKA==} + + /acorn-walk@8.2.0: + resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} + engines: {node: '>=0.4.0'} + dev: false + + /acorn@8.10.0: + resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: false + + /arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + dev: false + + /before-after-hook@2.2.3: + resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} + dev: false + + /bottleneck@2.19.5: + resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==} + dev: false + + /busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + dependencies: + streamsearch: 1.1.0 + dev: false + + /create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + dev: false + + /deprecation@2.3.1: + resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} + dev: false + + /diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + dev: false + + /is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + dev: false + + /make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: false + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: false + + /streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + dev: false + + /ts-node@10.9.1(@types/node@18.17.15)(typescript@5.2.2): + resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} + 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.4 + '@types/node': 18.17.15 + acorn: 8.10.0 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.2.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: false + + /tunnel@0.0.6: + resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} + engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} + dev: false + + /typescript@5.2.2: + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + engines: {node: '>=14.17'} + hasBin: true + + /undici@5.24.0: + resolution: {integrity: sha512-OKlckxBjFl0oXxcj9FU6oB8fDAaiRUq+D8jrFWGmOfI/gIyjk/IeS75LMzgYKUaeHzLUcYvf9bbJGSrUwTfwwQ==} + engines: {node: '>=14.0'} + dependencies: + busboy: 1.6.0 + dev: false + + /universal-user-agent@6.0.0: + resolution: {integrity: sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==} + dev: false + + /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==} + dev: false + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: false + + /yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + dev: false diff --git a/.github/actions/delete-deployments/test.sh b/.github/actions/delete-deployments/test.sh new file mode 100755 index 00000000000..18b77260886 --- /dev/null +++ b/.github/actions/delete-deployments/test.sh @@ -0,0 +1,9 @@ +#!/bin/sh +export NUM_OF_PAGES=all +export ENVIRONMENT=integration +export DRY_RUN=false +export REPOSITORY=smartcontractkit/chainlink +export REF=fix/golint +export GITHUB_ACTION=true + +pnpm start diff --git a/.github/actions/delete-deployments/tsconfig.json b/.github/actions/delete-deployments/tsconfig.json new file mode 100644 index 00000000000..4b36d4a178c --- /dev/null +++ b/.github/actions/delete-deployments/tsconfig.json @@ -0,0 +1,104 @@ +{ + "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/scripts/bash/.shellspec b/.github/scripts/bash/.shellspec deleted file mode 100644 index d567ecf976a..00000000000 --- a/.github/scripts/bash/.shellspec +++ /dev/null @@ -1,12 +0,0 @@ ---require spec_helper - -## Default kcov (coverage) options -# --kcov-options "--include-path=. --path-strip-level=1" -# --kcov-options "--include-pattern=.sh" -# --kcov-options "--exclude-pattern=/.shellspec,/spec/,/coverage/,/report/" - -## Example: Include script "myprog" with no extension -# --kcov-options "--include-pattern=.sh,myprog" - -## Example: Only specified files/directories -# --kcov-options "--include-pattern=myprog,/lib/" diff --git a/.github/scripts/bash/README.md b/.github/scripts/bash/README.md deleted file mode 100644 index ed23cd863b7..00000000000 --- a/.github/scripts/bash/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# bash scripts - -These are bash helper scripts for the CI/CD pipelines. - -## Testing - -For each bash script, create a corresponding *_spec.sh file in the `./spec/` directory. - -1. [Install ShellSpec](https://github.com/shellspec/shellspec#installation) using ASDF (see the .tool-versions file at the root of repo for version). -2. From this directory run `shellspec` \ No newline at end of file diff --git a/.github/scripts/bash/ontriggerlint.sh b/.github/scripts/bash/ontriggerlint.sh deleted file mode 100755 index a38a5e2a203..00000000000 --- a/.github/scripts/bash/ontriggerlint.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -## -# Execute tests via: ./ontriggerlint_test.sh -# -# For the GitHub contexts that should be passed in as args, see: -# https://docs.github.com/en/actions/learn-github-actions/contexts -# -# Trigger golangci-lint job steps when event is one of: -# 1. on a schedule (GITHUB_EVENT_NAME) -# 2. on PR's where the target branch (GITHUB_BASE_REF) is not prefixed with 'release/*' -# and where the relevant source code (SRC_CHANGED) has changed -# 3. on pushes to these branches (GITHUB_REF): staging, trying, rollup and where the -# relevant source code (SRC_CHANGED) has changed -# -# env vars: -# GITHUB_EVENT_NAME GitHub's event name, ex: schedule|pull_request|push (GitHub context: github.event_name) -# GITHUB_BASE_REF GitHub's base ref - target branch of pull request (GitHub context: github.base_ref) -# GITHUB_REF GitHub's ref - branch or tag that triggered run (GitHub context: github.ref) -# SRC_CHANGED Specific source paths that we want to trigger on were modified. One of: true|false -## - -if [[ -z "${GITHUB_REF:-}" ]]; then GITHUB_REF=""; fi - -# Strip out /refs/heads/ from GITHUB_REF leaving just the abbreviated name -ABBREV_GITHUB_REF="${GITHUB_REF#refs\/heads\/}" - -ON_TRIGGER=false -if [[ "${GITHUB_EVENT_NAME:-}" = "schedule" ]]; then - # Trigger on scheduled runs - ON_TRIGGER=true -elif [[ "${SRC_CHANGED:-}" = "true" && "${GITHUB_EVENT_NAME:-}" = "pull_request" && "${GITHUB_BASE_REF:-}" != release/* ]]; then - # Trigger if it's from a pull request targetting any branch EXCEPT the release branch - ON_TRIGGER=true -elif [[ "${SRC_CHANGED:-}" = "true" && "${GITHUB_EVENT_NAME:-}" = "push" && "${ABBREV_GITHUB_REF}" =~ ^(staging|trying|rollup)$ ]]; then - # Trigger if it's a push to specific branches - ON_TRIGGER=true -fi - -echo "on_trigger=${ON_TRIGGER}" diff --git a/.github/scripts/bash/spec/ontriggerlint_spec.sh b/.github/scripts/bash/spec/ontriggerlint_spec.sh deleted file mode 100644 index 212de847cac..00000000000 --- a/.github/scripts/bash/spec/ontriggerlint_spec.sh +++ /dev/null @@ -1,106 +0,0 @@ -# shellcheck shell=sh - -Describe 'Scheduled' - It 'Trigger on schedule when source changed' - export SRC_CHANGED=true - export GITHUB_EVENT_NAME=schedule - When run ./ontriggerlint.sh - The status should eq 0 - The stdout should equal 'on_trigger=true' - End - - It 'Trigger on schedule when source unchanged' - export SRC_CHANGED=false - export GITHUB_EVENT_NAME=schedule - When run ./ontriggerlint.sh - The status should eq 0 - The stdout should equal 'on_trigger=true' - End -End - - -Describe 'Pull Request' - It 'Trigger on pull_request for non release branches when source changed' - export SRC_CHANGED=true - export GITHUB_EVENT_NAME=pull_request - export GITHUB_BASE_REF=develop - When run ./ontriggerlint.sh - The status should eq 0 - The stdout should equal 'on_trigger=true' - End - - It 'No trigger on pull_request for non release branches when source unchanged' - export SRC_CHANGED=false - export GITHUB_EVENT_NAME=pull_request - export GITHUB_BASE_REF=develop - When run ./ontriggerlint.sh - The status should eq 0 - The stdout should equal 'on_trigger=false' - End - - It 'No trigger on pull_request for release branches when source changed' - export SRC_CHANGED=true - export GITHUB_EVENT_NAME=pull_request - export GITHUB_BASE_REF=release/1.2.3 - When run ./ontriggerlint.sh - The status should eq 0 - The stdout should equal 'on_trigger=false' - End -End - -Describe 'Push' - It 'Trigger on push to the staging branch when source changed' - export SRC_CHANGED=true - export GITHUB_EVENT_NAME=push - export GITHUB_REF=staging - When run ./ontriggerlint.sh - The status should eq 0 - The stdout should equal 'on_trigger=true' - End - - It 'No trigger on push to the staging branch when source unchanged' - export SRC_CHANGED=false - export GITHUB_EVENT_NAME=push - export GITHUB_REF=staging - When run ./ontriggerlint.sh - The status should eq 0 - The stdout should equal 'on_trigger=false' - End - - It 'Trigger on push to the trying branch when source changed' - export SRC_CHANGED=true - export GITHUB_EVENT_NAME=push - export GITHUB_REF=trying - When run ./ontriggerlint.sh - The status should eq 0 - The stdout should equal 'on_trigger=true' - End - - It 'Trigger on push to the rollup branch when source changed' - export SRC_CHANGED=true - export GITHUB_EVENT_NAME=push - export GITHUB_REF=rollup - When run ./ontriggerlint.sh - The status should eq 0 - The stdout should equal 'on_trigger=true' - End - - It 'No trigger on push to the develop branch when source changed' - export SRC_CHANGED=true - export GITHUB_EVENT_NAME=push - export GITHUB_REF=develop - When run ./ontriggerlint.sh - The status should eq 0 - The stdout should equal 'on_trigger=false' - End -End - -Describe 'Misc' - It 'No trigger on invalid event name when source changed' - export SRC_CHANGED=true - export GITHUB_EVENT_NAME=invalid_event_name - When run ./ontriggerlint.sh - The status should eq 0 - The stdout should equal 'on_trigger=false' - End -End diff --git a/.github/scripts/bash/spec/spec_helper.sh b/.github/scripts/bash/spec/spec_helper.sh deleted file mode 100644 index 93f19083cd2..00000000000 --- a/.github/scripts/bash/spec/spec_helper.sh +++ /dev/null @@ -1,24 +0,0 @@ -# shellcheck shell=sh - -# Defining variables and functions here will affect all specfiles. -# Change shell options inside a function may cause different behavior, -# so it is better to set them here. -# set -eu - -# This callback function will be invoked only once before loading specfiles. -spec_helper_precheck() { - # Available functions: info, warn, error, abort, setenv, unsetenv - # Available variables: VERSION, SHELL_TYPE, SHELL_VERSION - : minimum_version "0.28.1" -} - -# This callback function will be invoked after a specfile has been loaded. -spec_helper_loaded() { - : -} - -# This callback function will be invoked after core modules has been loaded. -spec_helper_configure() { - # Available functions: import, before_each, after_each, before_all, after_all - : import 'support/custom_matcher' -} diff --git a/.github/workflows/bash-cicd-scripts.yml b/.github/workflows/bash-cicd-scripts.yml deleted file mode 100644 index 21a884a4384..00000000000 --- a/.github/workflows/bash-cicd-scripts.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: Bash CICD Scripts - -on: - pull_request: - -jobs: - changes: - name: detect changes - runs-on: ubuntu-latest - outputs: - bash-cicd-scripts-src: ${{ steps.bash-cicd-scripts.outputs.src }} - steps: - - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - - uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 - id: bash-cicd-scripts - with: - filters: | - src: - - '.github/scripts/bash/**' - - '.github/workflows/bash-cicd-scripts.yml' - shellcheck: - name: ShellCheck Lint - runs-on: ubuntu-latest - needs: [changes] - steps: - - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - - name: Run ShellCheck - if: needs.changes.outputs.bash-cicd-scripts-src == 'true' - uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0 - with: - scandir: './.github/scripts/bash' - shellspec: - name: ShellSpec Tests - runs-on: ubuntu-latest - needs: [changes] - defaults: - run: - shell: bash - steps: - - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - - name: Install shellspec - if: needs.changes.outputs.bash-cicd-scripts-src == 'true' - env: - VERSION: 0.28.1 - VERSION_SHA256SUM: 350d3de04ba61505c54eda31a3c2ee912700f1758b1a80a284bc08fd8b6c5992 - GZ_TAR_FILE: shellspec-dist.tar.gz - run: | - curl -sSfL "https://github.com/shellspec/shellspec/releases/download/${VERSION}/shellspec-dist.tar.gz" \ - --output "${GZ_TAR_FILE}" - echo "Checking sha256sum of ShellSpec released archive." - echo "${VERSION_SHA256SUM} ${GZ_TAR_FILE}" | sha256sum --check - tar -xzf "${GZ_TAR_FILE}" -C "${HOME}/.local" - ln -s "${HOME}/.local/shellspec/shellspec" /usr/local/bin/shellspec - shellspec --version - - name: Run shellspec tests - if: needs.changes.outputs.bash-cicd-scripts-src == 'true' - working-directory: ./.github/scripts/bash - run: shellspec diff --git a/.github/workflows/build-publish-develop.yml b/.github/workflows/build-publish-develop.yml index 22f9ce81f7f..4384956da3c 100644 --- a/.github/workflows/build-publish-develop.yml +++ b/.github/workflows/build-publish-develop.yml @@ -1,9 +1,16 @@ -name: 'Push develop to private ECR' +name: "Push develop to private ECR" on: push: branches: - develop + workflow_dispatch: + inputs: + git_ref: + description: "Git ref (commit SHA, branch name, tag name, etc.) to checkout" + required: true +env: + GIT_REF: ${{ github.event.inputs.git_ref || github.ref }} jobs: push-chainlink-develop: @@ -25,7 +32,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - + with: + ref: ${{ env.GIT_REF }} - name: Build, sign and publish chainlink image uses: ./.github/actions/build-sign-publish-chainlink with: diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index 7b0b5e36ad7..b346cb9f4c3 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -10,82 +10,35 @@ on: branches: - master - develop - - 'release/*' - - staging - - trying - - rollup + - "release/*" merge_group: pull_request: schedule: - cron: "0 0 * * *" jobs: - golangci-changes: - name: detect changes for lint - runs-on: ubuntu-latest - outputs: - src: ${{ steps.golangci-changes.outputs.src }} - steps: - - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - - uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 - id: golangci-changes - with: - filters: | - src: - - '**/*.go' - - '**/go.mod' - - '**/go.sum' - - '.golangci.yml' - - '.github/workflows/ci-core.yml' - init: - name: initialize - runs-on: ubuntu-latest - needs: [golangci-changes] - defaults: - run: - shell: bash - outputs: - # Determine if `on` event should trigger linting to run - on_trigger_lint: ${{ steps.golangci-lint.outputs.on_trigger }} - steps: - - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - - name: Check if event should trigger lint - id: golangci-lint - env: - GITHUB_EVENT_NAME: ${{ github.event_name }} - GITHUB_BASE_REF: ${{ github.base_ref }} - GITHUB_REF: ${{ github.ref }} - SRC_CHANGED: ${{ needs.golangci-changes.outputs.src }} - run: ./.github/scripts/bash/ontriggerlint.sh | tee -a $GITHUB_OUTPUT - golangci: + if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' }} name: lint - runs-on: ubuntu-latest - needs: [init] + runs-on: ubuntu20.04-8cores-32GB steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - with: - fetch-depth: 0 - - uses: actions/setup-go@v4 - if: needs.init.outputs.on_trigger_lint == 'true' - with: - go-version-file: 'go.mod' - # If cache is set to true (default), the "prepare environment" will - # silently fail with these errors: - # Error: /usr/bin/tar: <...>: Cannot open: File exists - cache: false + - uses: actions/checkout@v4 + - name: Setup Go + uses: ./.github/actions/setup-go + - name: Touching core/web/assets/index.html + run: mkdir -p core/web/assets && touch core/web/assets/index.html + - name: Build binary + run: go build ./... - name: golangci-lint - if: needs.init.outputs.on_trigger_lint == 'true' uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 with: - version: v1.53.3 - only-new-issues: ${{ github.event.schedule == '' }} # show only new issues, unless it's a scheduled run - args: --out-format checkstyle:golangci-lint-report.xml - - name: Print lint report artifact - if: always() - run: test -f golangci-lint-report.xml && cat golangci-lint-report.xml || true + version: v1.54.2 + # We already cache these directories in setup-go + skip-pkg-cache: true + skip-build-cache: true + # only-new-issues is only applicable to PRs, otherwise it is always set to false + only-new-issues: true + args: --out-format colored-line-number,checkstyle:golangci-lint-report.xml - name: Store lint report artifact if: always() uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 @@ -94,7 +47,6 @@ jobs: path: golangci-lint-report.xml - name: Collect Metrics if: always() - id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} @@ -231,7 +183,7 @@ jobs: env: SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} with: - channel-id: '#topic-data-races' + channel-id: "#topic-data-races" slack-message: "Race tests failed: ${{ job.html_url }}\n${{ format('https://github.com/smartcontractkit/chainlink/actions/runs/{0}', github.run_id) }}" - name: Collect Metrics if: always() @@ -289,7 +241,7 @@ jobs: -gh_sha=$GITHUB_SHA \ -gh_event_path=$GITHUB_EVENT_PATH \ -command=./tools/bin/go_core_tests \ - `ls -R ./artifacts/go_core_tests*/output-short.txt` + `ls -R ./artifacts/go_core_tests*/output.txt` - name: Store logs artifacts if: always() uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8d1fe137f67..58b38015a63 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -4,9 +4,6 @@ on: push: branches: - develop - - staging - - trying - - rollup pull_request: # The branches below must be a subset of the branches above branches: [develop] diff --git a/.github/workflows/delete-deployments.yml b/.github/workflows/delete-deployments.yml new file mode 100644 index 00000000000..87cba36c085 --- /dev/null +++ b/.github/workflows/delete-deployments.yml @@ -0,0 +1,32 @@ +name: Deployments +on: + workflow_dispatch: + schedule: + # every 10 mins + - cron: "*/10 * * * *" + +jobs: + cleanup: + name: Clean up integration environment deployments + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: 🧼 Clean up Environment + uses: ./.github/actions/delete-deployments + with: + environment: integration + # Delete 300 deployments at a time + num-of-pages: 3 + # We start with page 2 because usually the first 200 deployments are still active, so we cannot delete them + starting-page: 2 + + - name: Collect Metrics + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: Clean up integration environment deployments + continue-on-error: true diff --git a/.github/workflows/generic-test-runner.yml b/.github/workflows/generic-test-runner.yml deleted file mode 100644 index dc194ab5bec..00000000000 --- a/.github/workflows/generic-test-runner.yml +++ /dev/null @@ -1,141 +0,0 @@ -name: Generic Test Runner -on: - workflow_dispatch: - inputs: - network: - description: 'Network to run tests against' - required: true - default: 'SIMULATED' - wsURL: - description: 'Chain WS URL (Skip with SIMULATED)' - required: false - httpURL: - description: 'Chain HTTP URL (Skip with SIMULATED)' - required: false - fundingKey: - description: 'Private key to fund test (Skip with SIMULATED)' - required: false - directory: - description: 'Directory to run tests from' - required: true - default: 'smoke' - test: - description: 'Test to run' - required: true - default: 'OCRBasic' - testInputs: - description: 'Custom test inputs' - required: false - default: '' -env: - ENV_JOB_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests:${{ github.sha }} - CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink - -jobs: - build-chainlink: - environment: integration - permissions: - id-token: write - contents: read - strategy: - matrix: - image: - - name: "" - dockerfile: core/chainlink.Dockerfile - tag-suffix: "" - - name: (plugins) - dockerfile: plugins/chainlink.Dockerfile - tag-suffix: -plugins - name: Build Chainlink Image ${{ matrix.image.name }} - runs-on: ubuntu20.04-16cores-64GB - steps: - - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - - name: Check if image exists - id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 - with: - repository: chainlink - tag: ${{ github.sha }}${{ matrix.image.tag-suffix }} - AWS_REGION: ${{ secrets.QA_AWS_REGION }} - AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - - name: Build Image - if: steps.check-image.outputs.exists == 'false' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 - with: - cl_repo: smartcontractkit/chainlink - cl_ref: ${{ github.sha }} - cl_dockerfile: ${{ matrix.image.dockerfile }} - push_tag: ${{ env.CHAINLINK_IMAGE }}:${{ github.sha }}${{ matrix.image.tag-suffix }} - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - - name: Print Chainlink Image Built - run: | - echo "### chainlink node image tag used for this test run :link:" >>$GITHUB_STEP_SUMMARY - echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY - - build-test-image: - environment: integration - permissions: - id-token: write - contents: read - name: Build Test Image - runs-on: ubuntu20.04-16cores-64GB - env: - TEST_SUITE: ${{ github.event.inputs.directory }} - steps: - - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - - name: Build Test Image - uses: ./.github/actions/build-test-image - with: - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - - test: - runs-on: ubuntu-latest - needs: [build-chainlink, build-test-image] - name: Run Test - environment: integration - permissions: - id-token: write - contents: read - env: - CHAINLINK_ENV_USER: ${{ github.actor }} - CHAINLINK_COMMIT_SHA: ${{ github.sha }} - TEST_SUITE: ${{ github.event.inputs.directory }} - SELECTED_NETWORKS: ${{ github.event.inputs.network }} - TEST_LOG_LEVEL: debug - steps: - - name: Mask Inputs - run: | - EVM_URLS=$(jq -r '.inputs.wsURL' $GITHUB_EVENT_PATH) - EVM_HTTP_URLS=$(jq -r '.inputs.httpURL' $GITHUB_EVENT_PATH) - EVM_KEYS=$(jq -r '.inputs.fundingKey' $GITHUB_EVENT_PATH) - - echo ::add-mask::$EVM_URLS - echo ::add-mask::$EVM_HTTP_URLS - echo ::add-mask::$EVM_KEYS - - echo EVM_URLS=$EVM_URLS >> $GITHUB_ENV - echo EVM_HTTP_URLS=$EVM_HTTP_URLS >> $GITHUB_ENV - echo EVM_KEYS=$EVM_KEYS >> $GITHUB_ENV - - name: Debug Input - run: echo ${{ github.event.inputs.testInputs }} - - name: Checkout the repo - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 - with: - test_command_to_run: make test_need_operator_assets && cd ./integration-tests && go test -timeout 1h -count=1 ./${{ github.event.inputs.directory }} -run ${{ github.event.inputs.test }} -v -args ${{ github.event.inputs.test-inputs }} - test_download_vendor_packages_command: cd ./integration-tests && go mod download - cl_repo: ${{ env.CHAINLINK_IMAGE }} - cl_image_tag: ${{ github.sha }} - artifacts_location: ./integration-tests/smoke/logs - publish_check_name: Generic Test Run - token: ${{ secrets.GITHUB_TOKEN }} - go_mod_path: ./integration-tests/go.mod - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} diff --git a/.github/workflows/integration-staging-tests.yml b/.github/workflows/integration-staging-tests.yml new file mode 100644 index 00000000000..a6fda178d50 --- /dev/null +++ b/.github/workflows/integration-staging-tests.yml @@ -0,0 +1,63 @@ +name: E2E Functions staging tests + +on: +# TODO: enable when env will be stable +# schedule: +# - cron: "0 0 * * *" + workflow_dispatch: + inputs: + network: + description: Blockchain network (testnet) + type: choice + default: "MUMBAI" + options: + - "MUMBAI" + test_type: + description: Test type + type: choice + default: "mumbai_functions_soak_test_real" + options: + - "mumbai_functions_soak_test_http" + - "mumbai_functions_stress_test_http" + - "mumbai_functions_soak_test_only_secrets" + - "mumbai_functions_stress_test_only_secrets" + - "mumbai_functions_soak_test_real" + - "mumbai_functions_stress_test_real" +# TODO: disabled, need GATI access +# - "gateway_secrets_set_soak_test" +# - "gateway_secrets_list_soak_test" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + e2e-soak-test: + environment: sdlc + runs-on: ubuntu20.04-8cores-32GB + permissions: + contents: read + id-token: write + env: + LOKI_URL: ${{ secrets.LOKI_URL }} + LOKI_TOKEN: ${{ secrets.LOKI_TOKEN }} + + SELECTED_NETWORKS: ${{ inputs.network }} + SELECTED_TEST: ${{ inputs.test_type }} + MUMBAI_URLS: ${{ secrets.FUNCTIONS_STAGING_MUMBAI_URLS }} + MUMBAI_KEYS: ${{ secrets.FUNCTIONS_STAGING_MUMBAI_KEYS }} + + WASP_LOG_LEVEL: info + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Run E2E soak tests + run: | + cd integration-tests/load/functions + if [[ $SELECTED_TEST == mumbai_functions* ]]; then + go test -v -timeout 6h -run TestFunctionsLoad/$SELECTED_TEST + elif [[ $SELECTED_TEST == gateway* ]]; then + go test -v -timeout 6h -run TestGatewayLoad/$SELECTED_TEST + fi \ No newline at end of file diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 1b0d0d091ed..43ace19d4c6 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -4,6 +4,7 @@ on: pull_request: schedule: - cron: "0 0 * * *" + # - cron: "0 * * * *" # DEBUG: Run every hour to nail down flakes push: tags: - "*" @@ -87,7 +88,7 @@ jobs: - name: Check if image exists if: needs.changes.outputs.src == 'true' id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 with: repository: chainlink tag: ${{ github.sha }}${{ matrix.image.tag-suffix }} @@ -95,7 +96,7 @@ jobs: AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - name: Build Image if: steps.check-image.outputs.exists == 'false' && needs.changes.outputs.src == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 with: cl_repo: smartcontractkit/chainlink cl_ref: ${{ github.sha }} @@ -147,6 +148,11 @@ jobs: outputs: matrix: ${{ env.MATRIX_JSON }} steps: + - name: Check for Skip Tests Label + if: contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') + run: | + echo "## \`skip-smoke-tests\` label is active, skipping E2E smoke tests" >>$GITHUB_STEP_SUMMARY + exit 0 - name: Checkout the repo uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: Compare Test Lists @@ -158,11 +164,12 @@ jobs: id: build-test-matrix-list run: | cd ./integration-tests - MATRIX_JSON_AUTOMATION=$(./scripts/buildTestMatrixList.sh ./smoke/automation_test.go automation ubuntu20.04-8cores-32GB) - MATRIX_JSON_KEEPER=$(./scripts/buildTestMatrixList.sh ./smoke/keeper_test.go keeper ubuntu20.04-8cores-32GB) + MATRIX_JSON_AUTOMATION=$(./scripts/buildTestMatrixList.sh ./smoke/automation_test.go automation ubuntu20.04-8cores-32GB 1) + MATRIX_JSON_KEEPER=$(./scripts/buildTestMatrixList.sh ./smoke/keeper_test.go keeper ubuntu20.04-8cores-32GB 1) COMBINED_ARRAY=$(jq -c -n "$MATRIX_JSON_AUTOMATION + $MATRIX_JSON_KEEPER") echo "MATRIX_JSON=${COMBINED_ARRAY}" >> $GITHUB_ENV eth-smoke-tests-matrix-automation: + if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') }} environment: integration permissions: checks: write @@ -198,7 +205,7 @@ jobs: ## Run this step when changes that require tests to be run are made - name: Run Tests if: needs.changes.outputs.src == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 env: PYROSCOPE_SERVER: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }} @@ -209,12 +216,12 @@ jobs: cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - artifacts_location: ./integration-tests/smoke/logs + artifacts_location: ./integration-tests/smoke/logs/ publish_check_name: ${{ matrix.product.name }} token: ${{ secrets.GITHUB_TOKEN }} go_mod_path: ./integration-tests/go.mod cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} - cache_restore_only: 'true' + cache_restore_only: "true" QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} @@ -229,6 +236,7 @@ jobs: test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true eth-smoke-tests-matrix: + if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') }} environment: integration permissions: checks: write @@ -304,7 +312,7 @@ jobs: ## Run this step when changes that require tests to be run are made - name: Run Tests if: needs.changes.outputs.src == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 env: PYROSCOPE_SERVER: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }} @@ -315,36 +323,29 @@ jobs: cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - artifacts_location: ./integration-tests/smoke/logs + artifacts_name: ${{ matrix.product.name }}-test-logs + artifacts_location: ./integration-tests/smoke/logs/ publish_check_name: ${{ matrix.product.name }} token: ${{ secrets.GITHUB_TOKEN }} go_mod_path: ./integration-tests/go.mod cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} - cache_restore_only: 'true' + cache_restore_only: "true" QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} ## Run this step when changes that do not need the test to run are made - name: Run Setup if: needs.changes.outputs.src == 'false' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 with: test_download_vendor_packages_command: cd ./integration-tests && go mod download go_mod_path: ./integration-tests/go.mod cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} - cache_restore_only: 'true' + cache_restore_only: "true" QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - - name: Upload test log - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 - if: failure() - with: - name: test-log-${{ matrix.product.name }} - path: /tmp/gotest.log - retention-days: 7 - continue-on-error: true - name: Collect Metrics if: always() id: collect-gha-metrics @@ -376,6 +377,33 @@ jobs: this-job-name: ETH Smoke Tests continue-on-error: true + cleanup: + name: Clean up integration environment deployments + if: always() + needs: [eth-smoke-tests] + runs-on: ubuntu-latest + steps: + - name: Checkout repo + if: ${{ github.event_name == 'pull_request' }} + uses: actions/checkout@v4 + + - name: 🧼 Clean up Environment + if: ${{ github.event_name == 'pull_request' }} + uses: ./.github/actions/delete-deployments + with: + environment: integration + ref: ${{ github.head_ref }} # See https://github.com/github/docs/issues/15319#issuecomment-1476705663 + + - name: Collect Metrics + if: ${{ github.event_name == 'pull_request' }} + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: Clean up integration environment deployments + continue-on-error: true + # 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: @@ -383,13 +411,14 @@ jobs: needs: [eth-smoke-tests] runs-on: ubuntu20.04-16cores-64GB name: ETH Smoke Tests Go Mod Cache + continue-on-error: true steps: - name: Checkout the repo uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Run Setup - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 with: test_download_vendor_packages_command: | cd ./integration-tests @@ -398,7 +427,7 @@ jobs: go test -run=NonExistentTest ./smoke/... || echo "ignore expected test failure" go_mod_path: ./integration-tests/go.mod cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} - cache_restore_only: 'false' + cache_restore_only: "false" ### Migration tests node-migration-tests: @@ -437,7 +466,7 @@ jobs: run: | echo "Running migration tests from version '${{ steps.get_latest_version.outputs.latest_version }}' to: '${{ github.sha }}'" - name: Run Migration Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 with: test_command_to_run: make test_need_operator_assets && cd ./integration-tests && go test -timeout 30m -count=1 -json ./migration 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download @@ -448,7 +477,7 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} go_mod_path: ./integration-tests/go.mod cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} - cache_restore_only: 'true' + cache_restore_only: "true" QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} @@ -537,7 +566,7 @@ jobs: steps: - name: Check if image exists id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 with: repository: chainlink-solana-tests tag: ${{ needs.get_solana_sha.outputs.sha }} @@ -633,6 +662,7 @@ jobs: if: needs.changes.outputs.src == 'false' || needs.solana-test-image-exists.outputs.exists == 'true' solana-smoke-tests: + if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') }} environment: integration permissions: checks: write @@ -679,7 +709,7 @@ jobs: ref: ${{ needs.get_solana_sha.outputs.sha }} - name: Run Tests if: needs.changes.outputs.src == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 with: test_command_to_run: export ENV_JOB_IMAGE=${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-solana-tests:${{ needs.get_solana_sha.outputs.sha }} && make test_smoke cl_repo: ${{ env.CHAINLINK_IMAGE }} @@ -719,7 +749,6 @@ jobs: CHAINLINK_ENV_USER: ${{ github.actor }} TEST_LOG_LEVEL: debug EVM_KEYS: ${{ secrets.QA_EVM_KEYS }} - TEST_EVM_KEYS: ${{ secrets.QA_EVM_KEYS }} OPTIMISM_GOERLI_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_URLS }} OPTIMISM_GOERLI_HTTP_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_HTTP_URLS }} @@ -742,7 +771,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} ## Only run OCR smoke test for now - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 env: PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} PYROSCOPE_ENVIRONMENT: ci-smoke-ocr-evm-${{ matrix.testnet }} # TODO: Only for OCR for now @@ -758,7 +787,7 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} go_mod_path: ./integration-tests/go.mod cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} - cache_restore_only: 'true' + cache_restore_only: "true" QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} @@ -776,7 +805,7 @@ jobs: testnet-smoke-tests-notify: name: Live Testnet Start Slack Thread - if: ${{ github.event_name == 'schedule' || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')) }} ## Only run live tests on new tags and nightly + if: success() || failure() environment: integration outputs: thread_ts: ${{ steps.slack.outputs.thread_ts }} @@ -896,4 +925,4 @@ jobs: env: SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} - ### End Live Testnet Section \ No newline at end of file + ### End Live Testnet Section diff --git a/.github/workflows/lint-gh-workflows.yml b/.github/workflows/lint-gh-workflows.yml index ebe09e67d88..cc7b44bc284 100644 --- a/.github/workflows/lint-gh-workflows.yml +++ b/.github/workflows/lint-gh-workflows.yml @@ -9,7 +9,7 @@ jobs: - name: Check out Code uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: Run actionlint - uses: reviewdog/action-actionlint@7485c2136bd093d2317a854c72910eebaee35238 # v1.37.1 + uses: reviewdog/action-actionlint@67ec075cacebd361442f6e3ef7671f74c6548909 # v1.38.0 - name: Collect Metrics if: always() id: collect-gha-metrics diff --git a/.github/workflows/operator-ui-ci.yml b/.github/workflows/operator-ui-ci.yml index b73106177c5..8ced3b222cf 100644 --- a/.github/workflows/operator-ui-ci.yml +++ b/.github/workflows/operator-ui-ci.yml @@ -40,7 +40,6 @@ jobs: with: owner: smartcontractkit repo: operator-ui - comment_downstream_url: ${{ github.event.pull_request.comments_url }} github_token: ${{ steps.get-gh-token.outputs.access-token }} workflow_file_name: chainlink-ci.yml client_payload: '{"ref": "${{ github.event.pull_request.head.sha }}"}' diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index 5044b668c2c..29022197bd3 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -30,7 +30,7 @@ jobs: tests: strategy: matrix: - product: [ vrf, automation, llo-feeds, functions, automation-dev, shared ] + product: [vrf, automation, llo-feeds, functions, shared] needs: [changes] if: needs.changes.outputs.changes == 'true' name: Tests @@ -52,7 +52,8 @@ jobs: - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 with: - version: nightly + # Has to match the `make foundry` version. + version: nightly-ca67d15f4abd46394b324c50e21e66f306a1162d - name: Run Forge build run: | @@ -72,9 +73,9 @@ jobs: FOUNDRY_PROFILE: ${{ matrix.product }} - name: Run Forge snapshot - if: ${{ !contains(fromJson('["vrf"]'), matrix.product) }} + if: ${{ !contains(fromJson('["vrf"]'), matrix.product) && !contains(fromJson('["automation"]'), matrix.product) }} run: | - forge snapshot --check gas-snapshots/${{ matrix.product }}.gas-snapshot + forge snapshot --nmt "testFuzz_\w{1,}?" --check gas-snapshots/${{ matrix.product }}.gas-snapshot id: snapshot working-directory: contracts env: diff --git a/.tool-versions b/.tool-versions index c7deac35bf5..1916a350289 100644 --- a/.tool-versions +++ b/.tool-versions @@ -4,5 +4,4 @@ nodejs 16.16.0 postgres 13.3 helm 3.10.3 zig 0.10.1 -golangci-lint 1.53.3 -shellspec 0.28.1 +golangci-lint 1.54.2 diff --git a/GNUmakefile b/GNUmakefile index 8698d845f3d..71279f43651 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -146,7 +146,7 @@ config-docs: ## Generate core node configuration documentation .PHONY: golangci-lint golangci-lint: ## Run golangci-lint for all issues. [ -d "./golangci-lint" ] || mkdir ./golangci-lint && \ - docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.53.2 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 > ./golangci-lint/$(shell date +%Y-%m-%d_%H:%M:%S).txt + docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.54.2 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 > ./golangci-lint/$(shell date +%Y-%m-%d_%H:%M:%S).txt GORELEASER_CONFIG ?= .goreleaser.yaml diff --git a/contracts/GNUmakefile b/contracts/GNUmakefile index 501ef968482..328c921545c 100644 --- a/contracts/GNUmakefile +++ b/contracts/GNUmakefile @@ -1,7 +1,6 @@ # ALL_FOUNDRY_PRODUCTS contains a list of all products that have a foundry -# profile defined. Adding a product to this list will make it available for -# snapshotting. -ALL_FOUNDRY_PRODUCTS = vrf automation llo-feeds functions automation-dev shared +# profile defined and use the Foundry snapshots. +ALL_FOUNDRY_PRODUCTS = llo-feeds functions shared # To make a snapshot for a specific product, either set the `FOUNDRY_PROFILE` env var # or call the target with `FOUNDRY_PROFILE=product` @@ -13,9 +12,11 @@ ALL_FOUNDRY_PRODUCTS = vrf automation llo-feeds functions automation-dev shared # make snapshot # make call example # make FOUNDRY_PROFILE=llo-feeds snapshot +# note make snapshot skips fuzz tests named according to best practices, although forge uses +# a static fuzz seed by default, flaky gas results per platform are still observed. .PHONY: snapshot snapshot: ## Make a snapshot for a specific product. - export FOUNDRY_PROFILE=$(FOUNDRY_PROFILE) && forge snapshot --snap gas-snapshots/$(FOUNDRY_PROFILE).gas-snapshot + export FOUNDRY_PROFILE=$(FOUNDRY_PROFILE) && forge snapshot --nmt "testFuzz_\w{1,}?" --snap gas-snapshots/$(FOUNDRY_PROFILE).gas-snapshot .PHONY: snapshot-all snapshot-all: ## Make a snapshot for all products. @@ -35,9 +36,12 @@ abigen: ## Build & install abigen. mockery: $(mockery) ## Install mockery. go install github.com/vektra/mockery/v2@v2.28.1 +.PHONY: foundry +foundry: ## Install foundry. + foundryup --version nightly-ca67d15f4abd46394b324c50e21e66f306a1162d + .PHONY: foundry-refresh -foundry-refresh: - foundryup +foundry-refresh: foundry git submodule deinit -f . git submodule update --init --recursive diff --git a/contracts/foundry.toml b/contracts/foundry.toml index 78ad4adf5dc..3b98f944582 100644 --- a/contracts/foundry.toml +++ b/contracts/foundry.toml @@ -31,12 +31,6 @@ solc_version = '0.8.6' optimizer_runs = 10000 src = 'src/v0.8/automation' test = 'src/v0.8/automation/test' -solc_version = '0.8.6' - -[profile.automation-dev] -optimizer_runs = 10000 -src = 'src/v0.8/dev/automation' -test = 'src/v0.8/dev/automation/test' [profile.llo-feeds] optimizer_runs = 1000000 diff --git a/contracts/gas-snapshots/automation-dev.gas-snapshot b/contracts/gas-snapshots/automation-dev.gas-snapshot deleted file mode 100644 index badbfba604c..00000000000 --- a/contracts/gas-snapshots/automation-dev.gas-snapshot +++ /dev/null @@ -1,5 +0,0 @@ -AutomationForwarder_forward:testBasicSuccess() (gas: 87630) -AutomationForwarder_forward:testNotAuthorizedReverts() (gas: 25427) -AutomationForwarder_forward:testWrongFunctionSelectorSuccess() (gas: 17958) -AutomationForwarder_updateRegistry:testBasicSuccess() (gas: 14577) -AutomationForwarder_updateRegistry:testNotFromRegistryNotAuthorizedReverts() (gas: 17665) \ No newline at end of file diff --git a/contracts/gas-snapshots/automation.gas-snapshot b/contracts/gas-snapshots/automation.gas-snapshot index a90453b1029..620e0b22559 100644 --- a/contracts/gas-snapshots/automation.gas-snapshot +++ b/contracts/gas-snapshots/automation.gas-snapshot @@ -1,3 +1,8 @@ +AutomationForwarder_forward:testBasicSuccess() (gas: 87630) +AutomationForwarder_forward:testNotAuthorizedReverts() (gas: 24560) +AutomationForwarder_forward:testWrongFunctionSelectorSuccess() (gas: 17958) +AutomationForwarder_updateRegistry:testBasicSuccess() (gas: 14577) +AutomationForwarder_updateRegistry:testNotFromRegistryNotAuthorizedReverts() (gas: 17665) HeartbeatRequester_getAggregatorRequestHeartbeat:testBasicSuccess() (gas: 75412) HeartbeatRequester_getAggregatorRequestHeartbeat:testHeartbeatNotPermittedReverts() (gas: 21730) HeartbeatRequester_permitHeartbeat:testBasicDeployerSuccess() (gas: 48229) diff --git a/contracts/gas-snapshots/functions.gas-snapshot b/contracts/gas-snapshots/functions.gas-snapshot index e0d973ead2a..9b501e677b9 100644 --- a/contracts/gas-snapshots/functions.gas-snapshot +++ b/contracts/gas-snapshots/functions.gas-snapshot @@ -1,3 +1,7 @@ +FunctionsBilling_EstimateCost:test_EstimateCost_RevertsIfGasPriceAboveCeiling() (gas: 32391) +FunctionsBilling_EstimateCost:test_EstimateCost_Success() (gas: 53002) +FunctionsBilling_OracleWithdrawAll:test_OracleWithdrawAll_RevertIfNotOwner() (gas: 13274) +FunctionsBilling_OracleWithdrawAll:test_OracleWithdrawAll_SuccessPaysTransmittersWithBalance() (gas: 146635) FunctionsOracle_sendRequest:testEmptyRequestDataReverts() (gas: 13452) FunctionsOracle_setDONPublicKey:testEmptyPublicKeyReverts() (gas: 10974) FunctionsOracle_setDONPublicKey:testOnlyOwnerReverts() (gas: 11255) @@ -9,144 +13,152 @@ FunctionsOracle_setRegistry:testSetRegistrySuccess() (gas: 35791) FunctionsOracle_setRegistry:testSetRegistry_gas() (gas: 31987) FunctionsOracle_typeAndVersion:testTypeAndVersionSuccess() (gas: 6905) FunctionsRouter_Constructor:test_Constructor_Success() (gas: 12073) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 48299) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 38870) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidCommitment() (gas: 36239) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidRequestId() (gas: 35161) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 165) -FunctionsRouter_Fulfill:test_Fulfill_RevertIfNotCommittedCoordinator() (gas: 28037) -FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 33206) -FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 102749) -FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 1770949) -FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 206000) -FunctionsRouter_GetAdminFee:test_GetAdminFee_Success() (gas: 17842) -FunctionsRouter_GetAllowListId:test_GetAllowListId_Success() (gas: 12883) -FunctionsRouter_GetConfig:test_GetConfig_Success() (gas: 31332) -FunctionsRouter_GetContractById:test_GetContractById_RevertIfRouteDoesNotExist() (gas: 13893) -FunctionsRouter_GetContractById:test_GetContractById_SuccessIfRouteExists() (gas: 17417) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 48079) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 38613) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidCommitment() (gas: 36022) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidRequestId() (gas: 35147) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 210) +FunctionsRouter_Fulfill:test_Fulfill_RevertIfNotCommittedCoordinator() (gas: 27993) +FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 33184) +FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 93416) +FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 103212) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 1762498) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 205574) +FunctionsRouter_GetAdminFee:test_GetAdminFee_Success() (gas: 18005) +FunctionsRouter_GetAllowListId:test_GetAllowListId_Success() (gas: 12926) +FunctionsRouter_GetConfig:test_GetConfig_Success() (gas: 37136) +FunctionsRouter_GetContractById:test_GetContractById_RevertIfRouteDoesNotExist() (gas: 13871) +FunctionsRouter_GetContractById:test_GetContractById_SuccessIfRouteExists() (gas: 17395) FunctionsRouter_GetProposedContractById:test_GetProposedContractById_RevertIfRouteDoesNotExist() (gas: 16382) FunctionsRouter_GetProposedContractById:test_GetProposedContractById_SuccessIfRouteExists() (gas: 23934) -FunctionsRouter_GetProposedContractSet:test_GetProposedContractSet_Success() (gas: 25935) -FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_RevertGasLimitTooBig() (gas: 25509) +FunctionsRouter_GetProposedContractSet:test_GetProposedContractSet_Success() (gas: 25958) +FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_RevertGasLimitTooBig() (gas: 28034) FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_RevertInvalidConfig() (gas: 41004) -FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_Success() (gas: 22027) +FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_Success() (gas: 24551) FunctionsRouter_Pause:test_Pause_RevertIfNotOwner() (gas: 13315) -FunctionsRouter_Pause:test_Pause_Success() (gas: 20254) -FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfEmptyAddress() (gas: 14790) -FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfExceedsMaxProposal() (gas: 22683) -FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfLengthMismatch() (gas: 14669) -FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotNewContract() (gas: 19047) -FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotOwner() (gas: 23348) -FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_Success() (gas: 118768) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfConsumerNotAllowed() (gas: 58984) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfEmptyData() (gas: 29426) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfIncorrectDonId() (gas: 57935) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 186118) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 48426) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidDonId() (gas: 25066) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfNoSubscription() (gas: 29162) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfPaused() (gas: 34231) -FunctionsRouter_SendRequest:test_SendRequest_Success() (gas: 197905) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfConsumerNotAllowed() (gas: 65547) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfEmptyData() (gas: 36013) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfIncorrectDonId() (gas: 29904) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalidCallbackGasLimit() (gas: 55012) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalidDonId() (gas: 27532) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfNoSubscription() (gas: 35747) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfPaused() (gas: 40817) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_Success() (gas: 204530) -FunctionsRouter_SendRequestToProposed:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 192704) -FunctionsRouter_SetAllowListId:test_SetAllowListId_Success() (gas: 30666) -FunctionsRouter_SetAllowListId:test_UpdateConfig_RevertIfNotOwner() (gas: 13402) -FunctionsRouter_Unpause:test_Unpause_RevertIfNotOwner() (gas: 13294) -FunctionsRouter_Unpause:test_Unpause_Success() (gas: 77334) -FunctionsRouter_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 21909) -FunctionsRouter_UpdateConfig:test_UpdateConfig_Success() (gas: 51123) -FunctionsRouter_UpdateContracts:test_UpdateContracts_RevertIfNotOwner() (gas: 13315) -FunctionsRouter_UpdateContracts:test_UpdateContracts_Success() (gas: 38715) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 60355) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfPaused() (gas: 60984) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderBecomesBlocked() (gas: 94703) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderIsNotNewOwner() (gas: 62713) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_Success() (gas: 59611) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumers() (gas: 137842) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNoSubscription() (gas: 12914) +FunctionsRouter_Pause:test_Pause_Success() (gas: 20298) +FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfEmptyAddress() (gas: 14768) +FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfExceedsMaxProposal() (gas: 22661) +FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfLengthMismatch() (gas: 14647) +FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotNewContract() (gas: 19025) +FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotOwner() (gas: 23326) +FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_Success() (gas: 118413) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfConsumerNotAllowed() (gas: 59304) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfDuplicateRequestId() (gas: 192143) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfEmptyData() (gas: 29405) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfIncorrectDonId() (gas: 57926) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 185987) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 50902) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidDonId() (gas: 25061) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfNoSubscription() (gas: 29111) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfPaused() (gas: 34247) +FunctionsRouter_SendRequest:test_SendRequest_Success() (gas: 197669) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfConsumerNotAllowed() (gas: 65800) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfEmptyData() (gas: 35991) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfIncorrectDonId() (gas: 29897) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalidCallbackGasLimit() (gas: 57488) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalidDonId() (gas: 27482) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfNoSubscription() (gas: 35696) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfPaused() (gas: 40766) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_Success() (gas: 204227) +FunctionsRouter_SendRequestToProposed:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 192506) +FunctionsRouter_SetAllowListId:test_SetAllowListId_Success() (gas: 30687) +FunctionsRouter_SetAllowListId:test_UpdateConfig_RevertIfNotOwner() (gas: 13380) +FunctionsRouter_Unpause:test_Unpause_RevertIfNotOwner() (gas: 13337) +FunctionsRouter_Unpause:test_Unpause_Success() (gas: 77421) +FunctionsRouter_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 24437) +FunctionsRouter_UpdateConfig:test_UpdateConfig_Success() (gas: 60653) +FunctionsRouter_UpdateContracts:test_UpdateContracts_RevertIfNotOwner() (gas: 13293) +FunctionsRouter_UpdateContracts:test_UpdateContracts_Success() (gas: 38716) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 60333) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfPaused() (gas: 60962) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderBecomesBlocked() (gas: 94681) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderIsNotNewOwner() (gas: 62691) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_Success() (gas: 59679) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumers() (gas: 137833) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumersAfterConfigUpdate() (gas: 164777) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNoSubscription() (gas: 12926) FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotAllowedSender() (gas: 57789) FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotSubscriptionOwner() (gas: 87166) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfPaused() (gas: 18006) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_Success() (gas: 95394) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNoSubscription() (gas: 15041) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotAllowedSender() (gas: 57863) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotSubscriptionOwner() (gas: 89296) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPaused() (gas: 20103) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPendingRequests() (gas: 193421) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_Success() (gas: 67209) -FunctionsSubscriptions_Constructor:test_Constructor_Success() (gas: 7609) -FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfNotAllowedSender() (gas: 28659) -FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfPaused() (gas: 17970) -FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_Success() (gas: 371776) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfPaused() (gas: 18051) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_Success() (gas: 95481) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNoSubscription() (gas: 15085) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotAllowedSender() (gas: 57929) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotSubscriptionOwner() (gas: 89340) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPaused() (gas: 20191) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPendingRequests() (gas: 193277) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitAllBalanceAsDeposit() (gas: 113352) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitSomeBalanceAsDeposit() (gas: 124604) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessRecieveDeposit() (gas: 310123) +FunctionsSubscriptions_Constructor:test_Constructor_Success() (gas: 7654) +FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfNotAllowedSender() (gas: 28637) +FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfPaused() (gas: 17948) +FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_Success() (gas: 371980) FunctionsSubscriptions_GetConsumer:test_GetConsumer_Success() (gas: 16225) -FunctionsSubscriptions_GetFlags:test_GetFlags_Success() (gas: 40880) -FunctionsSubscriptions_GetSubscription:test_GetSubscription_Success() (gas: 30869) +FunctionsSubscriptions_GetFlags:test_GetFlags_Success() (gas: 40858) +FunctionsSubscriptions_GetSubscription:test_GetSubscription_Success() (gas: 30959) FunctionsSubscriptions_GetSubscriptionCount:test_GetSubscriptionCount_Success() (gas: 12967) +FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfEndIsAfterLastSubscription() (gas: 14949) +FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfStartIsAfterEnd() (gas: 11863) +FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_Success() (gas: 59568) FunctionsSubscriptions_GetTotalBalance:test_GetTotalBalance_Success() (gas: 15032) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata() (gas: 27616) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription() (gas: 30093) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink() (gas: 13424) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused() (gas: 35022) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success() (gas: 56121) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata() (gas: 27594) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription() (gas: 30071) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink() (gas: 13402) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused() (gas: 35000) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success() (gas: 56279) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfAmountMoreThanBalance() (gas: 20745) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfBalanceInvariant() (gas: 189) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfNoAmount() (gas: 15638) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfPaused() (gas: 20833) -FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_SuccessPaysRecipient() (gas: 59873) -FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_SuccessSetsBalanceToZero() (gas: 57842) +FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_SuccessPaysRecipient() (gas: 59732) +FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_SuccessSetsBalanceToZero() (gas: 57701) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_RevertIfNoSubscription() (gas: 12818) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_RevertIfNotOwner() (gas: 15549) -FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_Success() (gas: 52817) -FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessDeletesSubscription() (gas: 47539) -FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessSubOwnerRefunded() (gas: 48847) -FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessWhenRequestInFlight() (gas: 162051) -FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfAmountMoreThanBalance() (gas: 17946) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_Success() (gas: 54867) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessDeletesSubscription() (gas: 48362) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessSubOwnerRefunded() (gas: 50896) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessWhenRequestInFlight() (gas: 163911) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfAmountMoreThanBalance() (gas: 17924) FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfBalanceInvariant() (gas: 165) -FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfNotOwner() (gas: 15577) -FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessIfNoAmount() (gas: 37559) -FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessPaysRecipient() (gas: 54598) -FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessSetsBalanceToZero() (gas: 37975) -FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessFalseIfNoPendingRequests() (gas: 14980) -FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessTrueIfPendingRequests() (gas: 175611) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfEmptyNewOwner() (gas: 27632) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfInvalidNewOwner() (gas: 57751) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNoSubscription() (gas: 15022) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 75152) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotSubscriptionOwner() (gas: 17981) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfPaused() (gas: 20126) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_Success() (gas: 68148) -FunctionsSubscriptions_RecoverFunds:test_OwnerCancelSubscription_RevertIfNotOwner() (gas: 15554) -FunctionsSubscriptions_RecoverFunds:test_RecoverFunds_Success() (gas: 41111) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfInvalidConsumer() (gas: 29946) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfNotOwner() (gas: 15555) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessIfNoAmount() (gas: 37396) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessPaysRecipient() (gas: 54435) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessSetsBalanceToZero() (gas: 37790) +FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessFalseIfNoPendingRequests() (gas: 15025) +FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessTrueIfPendingRequests() (gas: 175411) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfEmptyNewOwner() (gas: 27610) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfInvalidNewOwner() (gas: 57707) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNoSubscription() (gas: 15000) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 75130) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotSubscriptionOwner() (gas: 17959) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfPaused() (gas: 20104) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_Success() (gas: 68216) +FunctionsSubscriptions_RecoverFunds:test_OwnerCancelSubscription_RevertIfNotOwner() (gas: 15532) +FunctionsSubscriptions_RecoverFunds:test_RecoverFunds_Success() (gas: 41093) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfInvalidConsumer() (gas: 30238) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNoSubscription() (gas: 14997) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotAllowedSender() (gas: 57778) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotSubscriptionOwner() (gas: 87210) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPaused() (gas: 18004) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPendingRequests() (gas: 190641) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_Success() (gas: 41585) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPendingRequests() (gas: 190701) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_Success() (gas: 41979) FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNoSubscription() (gas: 12847) FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNotOwner() (gas: 15640) -FunctionsSubscriptions_SetFlags:test_SetFlags_Success() (gas: 35571) -FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfPaused() (gas: 25881) -FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfTimeoutNotExceeded() (gas: 25210) -FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertInvalidRequest() (gas: 28164) -FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_Success() (gas: 57781) +FunctionsSubscriptions_SetFlags:test_SetFlags_Success() (gas: 35549) +FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfPaused() (gas: 25859) +FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfTimeoutNotExceeded() (gas: 25188) +FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertInvalidRequest() (gas: 28142) +FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_Success() (gas: 57634) FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfNotAllowedSender() (gas: 26368) FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfPaused() (gas: 15714) FunctionsSubscriptions_createSubscription:test_CreateSubscription_Success() (gas: 152510) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfAcceptorIsNotSender() (gas: 25855) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfBlockedSender() (gas: 44366) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfInvalidSigner() (gas: 23615) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientContractIsNotSender() (gas: 1469094) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientContractIsNotSender() (gas: 1458273) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientIsNotSender() (gas: 26021) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForContract() (gas: 1549182) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForContract() (gas: 1538382) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForSelf() (gas: 94702) FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_RevertIfNotOwner() (gas: 15469) FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_Success() (gas: 50442) diff --git a/contracts/gas-snapshots/llo-feeds.gas-snapshot b/contracts/gas-snapshots/llo-feeds.gas-snapshot index 1a2df6b93e5..4cc6be66bed 100644 --- a/contracts/gas-snapshots/llo-feeds.gas-snapshot +++ b/contracts/gas-snapshots/llo-feeds.gas-snapshot @@ -1,119 +1,119 @@ FeeManagerProcessFeeTest:test_DiscountIsAppliedForNative() (gas: 52634) FeeManagerProcessFeeTest:test_DiscountIsReturnedForNative() (gas: 52566) -FeeManagerProcessFeeTest:test_DiscountIsReturnedForNativeWithSurcharge() (gas: 78769) +FeeManagerProcessFeeTest:test_DiscountIsReturnedForNativeWithSurcharge() (gas: 78747) FeeManagerProcessFeeTest:test_V1PayloadVerifies() (gas: 25961) FeeManagerProcessFeeTest:test_V1PayloadVerifiesAndReturnsChange() (gas: 57252) -FeeManagerProcessFeeTest:test_V2PayloadVerifies() (gas: 118189) +FeeManagerProcessFeeTest:test_V2PayloadVerifies() (gas: 118212) FeeManagerProcessFeeTest:test_V2PayloadWithoutQuoteFails() (gas: 28568) -FeeManagerProcessFeeTest:test_V2PayloadWithoutZeroFee() (gas: 72501) -FeeManagerProcessFeeTest:test_WithdrawERC20() (gas: 71670) -FeeManagerProcessFeeTest:test_WithdrawNonAdminAddr() (gas: 56292) -FeeManagerProcessFeeTest:test_WithdrawUnwrappedNative() (gas: 25344) +FeeManagerProcessFeeTest:test_V2PayloadWithoutZeroFee() (gas: 72524) +FeeManagerProcessFeeTest:test_WithdrawERC20() (gas: 71648) +FeeManagerProcessFeeTest:test_WithdrawNonAdminAddr() (gas: 56270) +FeeManagerProcessFeeTest:test_WithdrawUnwrappedNative() (gas: 25322) FeeManagerProcessFeeTest:test_baseFeeIsAppliedForLink() (gas: 14623) FeeManagerProcessFeeTest:test_baseFeeIsAppliedForNative() (gas: 17581) FeeManagerProcessFeeTest:test_correctDiscountIsAppliedWhenBothTokensAreDiscounted() (gas: 90945) FeeManagerProcessFeeTest:test_discountAIsNotAppliedWhenSetForOtherUsers() (gas: 56524) FeeManagerProcessFeeTest:test_discountFeeRoundsDownWhenUneven() (gas: 52803) FeeManagerProcessFeeTest:test_discountIsAppliedForLink() (gas: 49627) -FeeManagerProcessFeeTest:test_discountIsAppliedWith100PercentSurcharge() (gas: 78817) +FeeManagerProcessFeeTest:test_discountIsAppliedWith100PercentSurcharge() (gas: 78795) FeeManagerProcessFeeTest:test_discountIsNoLongerAppliedAfterRemoving() (gas: 46428) FeeManagerProcessFeeTest:test_discountIsNotAppliedForInvalidTokenAddress() (gas: 17568) FeeManagerProcessFeeTest:test_discountIsNotAppliedToOtherFeeds() (gas: 54571) FeeManagerProcessFeeTest:test_discountIsReturnedForLink() (gas: 49581) -FeeManagerProcessFeeTest:test_emptyQuoteRevertsWithError() (gas: 12392) -FeeManagerProcessFeeTest:test_eventIsEmittedAfterSurchargeIsSet() (gas: 41412) -FeeManagerProcessFeeTest:test_eventIsEmittedIfNotEnoughLink() (gas: 259447) -FeeManagerProcessFeeTest:test_eventIsEmittedUponWithdraw() (gas: 69018) +FeeManagerProcessFeeTest:test_emptyQuoteRevertsWithError() (gas: 11525) +FeeManagerProcessFeeTest:test_eventIsEmittedAfterSurchargeIsSet() (gas: 41390) +FeeManagerProcessFeeTest:test_eventIsEmittedIfNotEnoughLink() (gas: 259493) +FeeManagerProcessFeeTest:test_eventIsEmittedUponWithdraw() (gas: 68996) FeeManagerProcessFeeTest:test_feeIsUpdatedAfterDiscountIsRemoved() (gas: 49706) FeeManagerProcessFeeTest:test_feeIsUpdatedAfterNewDiscountIsApplied() (gas: 67635) -FeeManagerProcessFeeTest:test_feeIsUpdatedAfterNewSurchargeIsApplied() (gas: 64232) +FeeManagerProcessFeeTest:test_feeIsUpdatedAfterNewSurchargeIsApplied() (gas: 64188) FeeManagerProcessFeeTest:test_feeIsZeroWith100PercentDiscount() (gas: 52012) FeeManagerProcessFeeTest:test_getBaseRewardWithLinkQuote() (gas: 14621) FeeManagerProcessFeeTest:test_getLinkFeeIsRoundedUp() (gas: 49774) FeeManagerProcessFeeTest:test_getLinkRewardIsSameAsFee() (gas: 55561) -FeeManagerProcessFeeTest:test_getLinkRewardWithNativeQuoteAndSurchargeWithLinkDiscount() (gas: 82702) +FeeManagerProcessFeeTest:test_getLinkRewardWithNativeQuoteAndSurchargeWithLinkDiscount() (gas: 82680) FeeManagerProcessFeeTest:test_getRewardWithLinkDiscount() (gas: 49602) FeeManagerProcessFeeTest:test_getRewardWithLinkQuoteAndLinkDiscount() (gas: 49604) FeeManagerProcessFeeTest:test_getRewardWithNativeQuote() (gas: 17601) -FeeManagerProcessFeeTest:test_getRewardWithNativeQuoteAndSurcharge() (gas: 50826) +FeeManagerProcessFeeTest:test_getRewardWithNativeQuoteAndSurcharge() (gas: 50804) FeeManagerProcessFeeTest:test_linkAvailableForPaymentReturnsLinkBalance() (gas: 52375) -FeeManagerProcessFeeTest:test_nativeSurcharge0Percent() (gas: 30814) -FeeManagerProcessFeeTest:test_nativeSurcharge100Percent() (gas: 50827) -FeeManagerProcessFeeTest:test_nativeSurchargeCannotExceed100Percent() (gas: 17166) -FeeManagerProcessFeeTest:test_nativeSurchargeEventIsEmittedOnUpdate() (gas: 41370) +FeeManagerProcessFeeTest:test_nativeSurcharge0Percent() (gas: 30792) +FeeManagerProcessFeeTest:test_nativeSurcharge100Percent() (gas: 50805) +FeeManagerProcessFeeTest:test_nativeSurchargeCannotExceed100Percent() (gas: 17144) +FeeManagerProcessFeeTest:test_nativeSurchargeEventIsEmittedOnUpdate() (gas: 41348) FeeManagerProcessFeeTest:test_noFeeIsAppliedWhenReportHasZeroFee() (gas: 51879) -FeeManagerProcessFeeTest:test_noFeeIsAppliedWhenReportHasZeroFeeAndDiscountAndSurchargeIsSet() (gas: 78062) +FeeManagerProcessFeeTest:test_noFeeIsAppliedWhenReportHasZeroFeeAndDiscountAndSurchargeIsSet() (gas: 78040) FeeManagerProcessFeeTest:test_nonAdminProxyUserCannotProcessFee() (gas: 21892) FeeManagerProcessFeeTest:test_nonAdminUserCanNotSetDiscount() (gas: 19836) -FeeManagerProcessFeeTest:test_payLinkDeficit() (gas: 195521) +FeeManagerProcessFeeTest:test_payLinkDeficit() (gas: 195540) FeeManagerProcessFeeTest:test_payLinkDeficitOnlyCallableByAdmin() (gas: 17360) -FeeManagerProcessFeeTest:test_payLinkDeficitPaysAllFeesProcessed() (gas: 216708) -FeeManagerProcessFeeTest:test_payLinkDeficitTwice() (gas: 199820) -FeeManagerProcessFeeTest:test_processFeeAsProxy() (gas: 118561) +FeeManagerProcessFeeTest:test_payLinkDeficitPaysAllFeesProcessed() (gas: 216745) +FeeManagerProcessFeeTest:test_payLinkDeficitTwice() (gas: 199838) +FeeManagerProcessFeeTest:test_processFeeAsProxy() (gas: 118584) FeeManagerProcessFeeTest:test_processFeeDefaultReportsStillVerifiesWithEmptyQuote() (gas: 26811) FeeManagerProcessFeeTest:test_processFeeEmitsEventIfNotEnoughLink() (gas: 163961) FeeManagerProcessFeeTest:test_processFeeIfSubscriberIsSelf() (gas: 27362) -FeeManagerProcessFeeTest:test_processFeeNative() (gas: 174559) -FeeManagerProcessFeeTest:test_processFeeUsesCorrectDigest() (gas: 119521) +FeeManagerProcessFeeTest:test_processFeeNative() (gas: 174582) +FeeManagerProcessFeeTest:test_processFeeUsesCorrectDigest() (gas: 119544) FeeManagerProcessFeeTest:test_processFeeWithDefaultReportPayloadAndQuoteStillVerifies() (gas: 29175) -FeeManagerProcessFeeTest:test_processFeeWithDiscountEmitsEvent() (gas: 244302) +FeeManagerProcessFeeTest:test_processFeeWithDiscountEmitsEvent() (gas: 244325) FeeManagerProcessFeeTest:test_processFeeWithInvalidReportVersionFailsToDecode() (gas: 30610) -FeeManagerProcessFeeTest:test_processFeeWithNoDiscountDoesNotEmitEvent() (gas: 168476) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNative() (gas: 182111) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddress() (gas: 133607) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddressExcessiveFee() (gas: 157494) +FeeManagerProcessFeeTest:test_processFeeWithNoDiscountDoesNotEmitEvent() (gas: 168499) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNative() (gas: 182134) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddress() (gas: 133630) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddressExcessiveFee() (gas: 157517) FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeShortFunds() (gas: 94743) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeWithExcessiveFee() (gas: 189049) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeWithExcessiveFee() (gas: 189072) FeeManagerProcessFeeTest:test_processFeeWithWithCorruptQuotePayload() (gas: 28473) FeeManagerProcessFeeTest:test_processFeeWithWithEmptyQuotePayload() (gas: 28919) FeeManagerProcessFeeTest:test_processFeeWithWithZeroQuotePayload() (gas: 29914) FeeManagerProcessFeeTest:test_processFeeWithZeroLinkNonZeroNativeWithLinkQuote() (gas: 35154) -FeeManagerProcessFeeTest:test_processFeeWithZeroLinkNonZeroNativeWithNativeQuote() (gas: 154448) +FeeManagerProcessFeeTest:test_processFeeWithZeroLinkNonZeroNativeWithNativeQuote() (gas: 154471) FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkReturnsChange() (gas: 55617) -FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkWithLinkQuote() (gas: 118462) +FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkWithLinkQuote() (gas: 118485) FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkWithNativeQuote() (gas: 37856) -FeeManagerProcessFeeTest:test_processMultipleLinkAndNativeUnwrappedReports() (gas: 295021) -FeeManagerProcessFeeTest:test_processMultipleLinkAndNativeWrappedReports() (gas: 278263) -FeeManagerProcessFeeTest:test_processMultipleLinkReports() (gas: 235077) -FeeManagerProcessFeeTest:test_processMultipleUnwrappedNativeReports() (gas: 268847) -FeeManagerProcessFeeTest:test_processMultipleV1Reports() (gas: 71419) -FeeManagerProcessFeeTest:test_processMultipleWrappedNativeReports() (gas: 251978) -FeeManagerProcessFeeTest:test_processV1V2V3Reports() (gas: 282317) -FeeManagerProcessFeeTest:test_processV1V2V3ReportsWithUnwrapped() (gas: 299043) +FeeManagerProcessFeeTest:test_processMultipleLinkAndNativeUnwrappedReports() (gas: 295090) +FeeManagerProcessFeeTest:test_processMultipleLinkAndNativeWrappedReports() (gas: 278332) +FeeManagerProcessFeeTest:test_processMultipleLinkReports() (gas: 235123) +FeeManagerProcessFeeTest:test_processMultipleUnwrappedNativeReports() (gas: 268893) +FeeManagerProcessFeeTest:test_processMultipleV1Reports() (gas: 71442) +FeeManagerProcessFeeTest:test_processMultipleWrappedNativeReports() (gas: 252024) +FeeManagerProcessFeeTest:test_processV1V2V3Reports() (gas: 282386) +FeeManagerProcessFeeTest:test_processV1V2V3ReportsWithUnwrapped() (gas: 299112) FeeManagerProcessFeeTest:test_reportWithNoExpiryOrFeeReturnsZero() (gas: 11038) FeeManagerProcessFeeTest:test_setDiscountOver100Percent() (gas: 19548) FeeManagerProcessFeeTest:test_subscriberDiscountEventIsEmittedOnUpdate() (gas: 46281) -FeeManagerProcessFeeTest:test_surchargeFeeRoundsUpWhenUneven() (gas: 51157) -FeeManagerProcessFeeTest:test_surchargeIsApplied() (gas: 51082) -FeeManagerProcessFeeTest:test_surchargeIsAppliedForNativeFeeWithDiscount() (gas: 79236) -FeeManagerProcessFeeTest:test_surchargeIsNoLongerAppliedAfterRemoving() (gas: 47004) -FeeManagerProcessFeeTest:test_surchargeIsNotAppliedForLinkFee() (gas: 49862) -FeeManagerProcessFeeTest:test_surchargeIsNotAppliedWith100PercentDiscount() (gas: 78233) -FeeManagerProcessFeeTest:test_testRevertIfReportHasExpired() (gas: 15251) +FeeManagerProcessFeeTest:test_surchargeFeeRoundsUpWhenUneven() (gas: 51135) +FeeManagerProcessFeeTest:test_surchargeIsApplied() (gas: 51060) +FeeManagerProcessFeeTest:test_surchargeIsAppliedForNativeFeeWithDiscount() (gas: 79214) +FeeManagerProcessFeeTest:test_surchargeIsNoLongerAppliedAfterRemoving() (gas: 46968) +FeeManagerProcessFeeTest:test_surchargeIsNotAppliedForLinkFee() (gas: 49840) +FeeManagerProcessFeeTest:test_surchargeIsNotAppliedWith100PercentDiscount() (gas: 78211) +FeeManagerProcessFeeTest:test_testRevertIfReportHasExpired() (gas: 14383) RewardManagerClaimTest:test_claimAllRecipients() (gas: 275763) RewardManagerClaimTest:test_claimMultipleRecipients() (gas: 153306) -RewardManagerClaimTest:test_claimRewardsWithDuplicatePoolIdsDoesNotPayoutTwice() (gas: 328322) +RewardManagerClaimTest:test_claimRewardsWithDuplicatePoolIdsDoesNotPayoutTwice() (gas: 328345) RewardManagerClaimTest:test_claimSingleRecipient() (gas: 88340) -RewardManagerClaimTest:test_claimUnevenAmountRoundsDown() (gas: 313526) +RewardManagerClaimTest:test_claimUnevenAmountRoundsDown() (gas: 313549) RewardManagerClaimTest:test_claimUnregisteredPoolId() (gas: 34461) RewardManagerClaimTest:test_claimUnregisteredRecipient() (gas: 40491) RewardManagerClaimTest:test_eventIsEmittedUponClaim() (gas: 86069) RewardManagerClaimTest:test_eventIsNotEmittedUponUnsuccessfulClaim() (gas: 24700) -RewardManagerClaimTest:test_recipientsClaimMultipleDeposits() (gas: 383191) -RewardManagerClaimTest:test_singleRecipientClaimMultipleDeposits() (gas: 136266) +RewardManagerClaimTest:test_recipientsClaimMultipleDeposits() (gas: 383214) +RewardManagerClaimTest:test_singleRecipientClaimMultipleDeposits() (gas: 136289) RewardManagerNoRecipientSet:test_claimAllRecipientsAfterRecipientsSet() (gas: 489469) -RewardManagerPayRecipientsTest:test_addFundsToPoolAsNonOwnerOrFeeManager() (gas: 11405) -RewardManagerPayRecipientsTest:test_addFundsToPoolAsOwner() (gas: 53858) -RewardManagerPayRecipientsTest:test_payAllRecipients() (gas: 249449) -RewardManagerPayRecipientsTest:test_payAllRecipientsFromNonAdminUser() (gas: 20452) -RewardManagerPayRecipientsTest:test_payAllRecipientsFromRecipientInPool() (gas: 249695) -RewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalInvalidRecipient() (gas: 260899) -RewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalUnregisteredRecipient() (gas: 264035) -RewardManagerPayRecipientsTest:test_payRecipientWithInvalidPool() (gas: 28526) -RewardManagerPayRecipientsTest:test_payRecipientsEmptyRecipientList() (gas: 24947) -RewardManagerPayRecipientsTest:test_payRecipientsWithInvalidPoolId() (gas: 31032) -RewardManagerPayRecipientsTest:test_paySingleRecipient() (gas: 84331) -RewardManagerPayRecipientsTest:test_paySubsetOfRecipientsInPool() (gas: 197426) +RewardManagerPayRecipientsTest:test_addFundsToPoolAsNonOwnerOrFeeManager() (gas: 11428) +RewardManagerPayRecipientsTest:test_addFundsToPoolAsOwner() (gas: 53876) +RewardManagerPayRecipientsTest:test_payAllRecipients() (gas: 249472) +RewardManagerPayRecipientsTest:test_payAllRecipientsFromNonAdminUser() (gas: 20475) +RewardManagerPayRecipientsTest:test_payAllRecipientsFromRecipientInPool() (gas: 249718) +RewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalInvalidRecipient() (gas: 260922) +RewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalUnregisteredRecipient() (gas: 264058) +RewardManagerPayRecipientsTest:test_payRecipientWithInvalidPool() (gas: 28549) +RewardManagerPayRecipientsTest:test_payRecipientsEmptyRecipientList() (gas: 24970) +RewardManagerPayRecipientsTest:test_payRecipientsWithInvalidPoolId() (gas: 31055) +RewardManagerPayRecipientsTest:test_paySingleRecipient() (gas: 84354) +RewardManagerPayRecipientsTest:test_paySubsetOfRecipientsInPool() (gas: 197449) RewardManagerRecipientClaimDifferentWeightsTest:test_allRecipientsClaimingReceiveExpectedAmount() (gas: 279714) RewardManagerRecipientClaimMultiplePoolsTest:test_claimAllRecipientsMultiplePools() (gas: 509889) RewardManagerRecipientClaimMultiplePoolsTest:test_claimAllRecipientsSinglePool() (gas: 281811) @@ -122,19 +122,19 @@ RewardManagerRecipientClaimMultiplePoolsTest:test_claimMultipleRecipientsMultipl RewardManagerRecipientClaimMultiplePoolsTest:test_claimMultipleRecipientsSinglePool() (gas: 153434) RewardManagerRecipientClaimMultiplePoolsTest:test_claimSingleRecipientMultiplePools() (gas: 131911) RewardManagerRecipientClaimMultiplePoolsTest:test_claimSingleUniqueRecipient() (gas: 105312) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnevenAmountRoundsDown() (gas: 576243) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnevenAmountRoundsDown() (gas: 576289) RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnregisteredRecipient() (gas: 63555) RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorAndTotalPoolsEqual() (gas: 10202) -RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorCannotBeGreaterThanTotalPools() (gas: 12680) +RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorCannotBeGreaterThanTotalPools() (gas: 11107) RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorSingleResult() (gas: 19606) RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPools() (gas: 29052) RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPoolsWhereAlreadyClaimed() (gas: 147218) RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInNoPools() (gas: 18532) RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInSinglePool() (gas: 24569) -RewardManagerRecipientClaimMultiplePoolsTest:test_recipientsClaimMultipleDeposits() (gas: 387641) -RewardManagerRecipientClaimMultiplePoolsTest:test_singleRecipientClaimMultipleDeposits() (gas: 136305) -RewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmount() (gas: 198427) -RewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmountWithSmallDeposit() (gas: 218297) +RewardManagerRecipientClaimMultiplePoolsTest:test_recipientsClaimMultipleDeposits() (gas: 387664) +RewardManagerRecipientClaimMultiplePoolsTest:test_singleRecipientClaimMultipleDeposits() (gas: 136328) +RewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmount() (gas: 198450) +RewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmountWithSmallDeposit() (gas: 218320) RewardManagerSetRecipientsTest:test_eventIsEmittedUponSetRecipients() (gas: 191821) RewardManagerSetRecipientsTest:test_setRecipientContainsDuplicateRecipients() (gas: 126091) RewardManagerSetRecipientsTest:test_setRewardRecipientFromManagerAddress() (gas: 193972) @@ -147,19 +147,19 @@ RewardManagerSetRecipientsTest:test_setRewardRecipients() (gas: 185681) RewardManagerSetRecipientsTest:test_setRewardRecipientsIsEmpty() (gas: 87113) RewardManagerSetRecipientsTest:test_setSingleRewardRecipient() (gas: 110394) RewardManagerSetupTest:test_eventEmittedUponFeeManagerUpdate() (gas: 21388) -RewardManagerSetupTest:test_eventEmittedUponFeePaid() (gas: 259190) -RewardManagerSetupTest:test_rejectsZeroLinkAddressOnConstruction() (gas: 59418) +RewardManagerSetupTest:test_eventEmittedUponFeePaid() (gas: 259213) +RewardManagerSetupTest:test_rejectsZeroLinkAddressOnConstruction() (gas: 59432) RewardManagerSetupTest:test_setFeeManagerZeroAddress() (gas: 17038) -RewardManagerUpdateRewardRecipientsMultiplePoolsTest:test_updatePrimaryRecipientWeights() (gas: 373696) +RewardManagerUpdateRewardRecipientsMultiplePoolsTest:test_updatePrimaryRecipientWeights() (gas: 373719) RewardManagerUpdateRewardRecipientsTest:test_eventIsEmittedUponUpdateRecipients() (gas: 279303) RewardManagerUpdateRewardRecipientsTest:test_onlyAdminCanUpdateRecipients() (gas: 19749) -RewardManagerUpdateRewardRecipientsTest:test_partialUpdateRecipientWeights() (gas: 218972) +RewardManagerUpdateRewardRecipientsTest:test_partialUpdateRecipientWeights() (gas: 218995) RewardManagerUpdateRewardRecipientsTest:test_updateAllRecipientsWithSameAddressAndWeight() (gas: 273125) RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsToSubset() (gas: 245331) RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithExcessiveWeight() (gas: 259403) RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithSameAddressAndWeight() (gas: 149004) RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithUnderWeightSet() (gas: 259477) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientWeights() (gas: 369177) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientWeights() (gas: 369200) RewardManagerUpdateRewardRecipientsTest:test_updateRecipientWithNewZeroAddress() (gas: 258619) RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsContainsDuplicateRecipients() (gas: 288757) RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentLargerSet() (gas: 261428) @@ -182,23 +182,23 @@ VerifierActivateFeedTest:test_revertsIfNoFeedExistsActivate() (gas: 13179) VerifierActivateFeedTest:test_revertsIfNoFeedExistsDeactivate() (gas: 13157) VerifierActivateFeedTest:test_revertsIfNotOwnerActivateFeed() (gas: 17098) VerifierActivateFeedTest:test_revertsIfNotOwnerDeactivateFeed() (gas: 17153) -VerifierBulkVerifyBillingReport:test_verifyBulkReportWithUnwrappedAndWrappedNativeDefaultsToUnwrapped() (gas: 391378) -VerifierBulkVerifyBillingReport:test_verifyBulkWithLinkAndUnwrappedNative() (gas: 700956) -VerifierBulkVerifyBillingReport:test_verifyBulkWithLinkAndWrappedNative() (gas: 685536) -VerifierBulkVerifyBillingReport:test_verifyMultiVersions() (gas: 568369) -VerifierBulkVerifyBillingReport:test_verifyMultiVersionsReturnsVerifiedReports() (gas: 781180) -VerifierBulkVerifyBillingReport:test_verifyWithBulkLink() (gas: 578147) -VerifierBulkVerifyBillingReport:test_verifyWithBulkNative() (gas: 581753) -VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrapped() (gas: 589227) -VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrappedReturnsChange() (gas: 596254) +VerifierBulkVerifyBillingReport:test_verifyBulkReportWithUnwrappedAndWrappedNativeDefaultsToUnwrapped() (gas: 391401) +VerifierBulkVerifyBillingReport:test_verifyBulkWithLinkAndUnwrappedNative() (gas: 701002) +VerifierBulkVerifyBillingReport:test_verifyBulkWithLinkAndWrappedNative() (gas: 685582) +VerifierBulkVerifyBillingReport:test_verifyMultiVersions() (gas: 568438) +VerifierBulkVerifyBillingReport:test_verifyMultiVersionsReturnsVerifiedReports() (gas: 781249) +VerifierBulkVerifyBillingReport:test_verifyWithBulkLink() (gas: 578193) +VerifierBulkVerifyBillingReport:test_verifyWithBulkNative() (gas: 581776) +VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrapped() (gas: 589250) +VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrappedReturnsChange() (gas: 596277) VerifierConstructorTest:test_revertsIfInitializedWithEmptyVerifierProxy() (gas: 59939) VerifierConstructorTest:test_setsTheCorrectProperties() (gas: 1788491) VerifierDeactivateFeedWithVerifyTest:test_currentReportAllowsVerification() (gas: 192062) -VerifierDeactivateFeedWithVerifyTest:test_currentReportFailsVerification() (gas: 113377) +VerifierDeactivateFeedWithVerifyTest:test_currentReportFailsVerification() (gas: 111727) VerifierDeactivateFeedWithVerifyTest:test_previousReportAllowsVerification() (gas: 99613) -VerifierDeactivateFeedWithVerifyTest:test_previousReportFailsVerification() (gas: 69932) +VerifierDeactivateFeedWithVerifyTest:test_previousReportFailsVerification() (gas: 68305) VerifierProxyAccessControlledVerificationTest:test_proxiesToTheVerifierIfHasAccess() (gas: 204836) -VerifierProxyAccessControlledVerificationTest:test_revertsIfNoAccess() (gas: 109546) +VerifierProxyAccessControlledVerificationTest:test_revertsIfNoAccess() (gas: 107889) VerifierProxyConstructorTest:test_correctlySetsTheCorrectAccessControllerInterface() (gas: 1439877) VerifierProxyConstructorTest:test_correctlySetsTheOwner() (gas: 1419891) VerifierProxyConstructorTest:test_correctlySetsVersion() (gas: 6873) @@ -220,7 +220,7 @@ VerifierProxyUnsetVerifierTest:test_revertsIfNotAdmin() (gas: 14965) VerifierProxyUnsetVerifierWithPreviouslySetVerifierTest:test_correctlyUnsetsVerifier() (gas: 12697) VerifierProxyUnsetVerifierWithPreviouslySetVerifierTest:test_emitsAnEventAfterUnsettingVerifier() (gas: 17965) VerifierProxyVerifyTest:test_proxiesToTheCorrectVerifier() (gas: 198420) -VerifierProxyVerifyTest:test_revertsIfNoVerifierConfigured() (gas: 116319) +VerifierProxyVerifyTest:test_revertsIfNoVerifierConfigured() (gas: 114671) VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlySetsConfigWhenDigestsAreRemoved() (gas: 538582) VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesDigestsOnMultipleVerifiersInTheProxy() (gas: 964048) VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesTheDigestInTheProxy() (gas: 520140) @@ -237,29 +237,29 @@ VerifierSetConfigWhenThereAreMultipleDigestsTest:test_correctlyUpdatesDigestsOnM VerifierSetConfigWhenThereAreMultipleDigestsTest:test_correctlyUpdatesTheDigestInTheProxy() (gas: 519921) VerifierSupportsInterfaceTest:test_falseIfIsNotCorrectInterface() (gas: 5590) VerifierSupportsInterfaceTest:test_trueIfIsCorrectInterface() (gas: 5633) -VerifierTestBillingReport:test_verifyWithLink() (gas: 278542) -VerifierTestBillingReport:test_verifyWithNative() (gas: 319232) -VerifierTestBillingReport:test_verifyWithNativeUnwrapped() (gas: 321475) -VerifierTestBillingReport:test_verifyWithNativeUnwrappedReturnsChange() (gas: 328541) +VerifierTestBillingReport:test_verifyWithLink() (gas: 278565) +VerifierTestBillingReport:test_verifyWithNative() (gas: 319255) +VerifierTestBillingReport:test_verifyWithNativeUnwrapped() (gas: 321498) +VerifierTestBillingReport:test_verifyWithNativeUnwrappedReturnsChange() (gas: 328564) VerifierVerifyMultipleConfigDigestTest:test_canVerifyNewerReportsWithNewerConfigs() (gas: 131228) VerifierVerifyMultipleConfigDigestTest:test_canVerifyOlderReportsWithOlderConfigs() (gas: 187132) -VerifierVerifyMultipleConfigDigestTest:test_revertsIfAReportIsVerifiedWithAnExistingButIncorrectDigest() (gas: 88205) -VerifierVerifyMultipleConfigDigestTest:test_revertsIfVerifyingWithAnUnsetDigest() (gas: 128062) +VerifierVerifyMultipleConfigDigestTest:test_revertsIfAReportIsVerifiedWithAnExistingButIncorrectDigest() (gas: 86566) +VerifierVerifyMultipleConfigDigestTest:test_revertsIfVerifyingWithAnUnsetDigest() (gas: 126411) VerifierVerifySingleConfigDigestTest:test_emitsAnEventIfReportVerified() (gas: 186945) VerifierVerifySingleConfigDigestTest:test_returnsThePriceAndBlockNumIfReportVerified() (gas: 187114) -VerifierVerifySingleConfigDigestTest:test_revertsIfConfigDigestNotSet() (gas: 116130) -VerifierVerifySingleConfigDigestTest:test_revertsIfDuplicateSignersHaveSigned() (gas: 182315) -VerifierVerifySingleConfigDigestTest:test_revertsIfMismatchedSignatureLength() (gas: 53037) -VerifierVerifySingleConfigDigestTest:test_revertsIfReportHasUnconfiguredFeedID() (gas: 103976) -VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedByNonProxy() (gas: 100992) -VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedWithIncorrectAddresses() (gas: 184066) -VerifierVerifySingleConfigDigestTest:test_revertsIfWrongNumberOfSigners() (gas: 110031) +VerifierVerifySingleConfigDigestTest:test_revertsIfConfigDigestNotSet() (gas: 114479) +VerifierVerifySingleConfigDigestTest:test_revertsIfDuplicateSignersHaveSigned() (gas: 180665) +VerifierVerifySingleConfigDigestTest:test_revertsIfMismatchedSignatureLength() (gas: 51479) +VerifierVerifySingleConfigDigestTest:test_revertsIfReportHasUnconfiguredFeedID() (gas: 102318) +VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedByNonProxy() (gas: 99348) +VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedWithIncorrectAddresses() (gas: 182416) +VerifierVerifySingleConfigDigestTest:test_revertsIfWrongNumberOfSigners() (gas: 108382) VerifierVerifySingleConfigDigestTest:test_setsTheCorrectEpoch() (gas: 194270) Verifier_accessControlledVerify:testVerifyWithAccessControl_gas() (gas: 208853) -Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithLinkFeeSuccess_gas() (gas: 540669) -Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithNativeFeeSuccess_gas() (gas: 564041) +Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithLinkFeeSuccess_gas() (gas: 540715) +Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithNativeFeeSuccess_gas() (gas: 564087) Verifier_setConfig:testSetConfigSuccess_gas() (gas: 922428) Verifier_verify:testVerifyProxySuccess_gas() (gas: 195542) Verifier_verify:testVerifySuccess_gas() (gas: 186725) -Verifier_verifyWithFee:testVerifyProxyWithLinkFeeSuccess_gas() (gas: 242491) -Verifier_verifyWithFee:testVerifyProxyWithNativeFeeSuccess_gas() (gas: 260968) \ No newline at end of file +Verifier_verifyWithFee:testVerifyProxyWithLinkFeeSuccess_gas() (gas: 242514) +Verifier_verifyWithFee:testVerifyProxyWithNativeFeeSuccess_gas() (gas: 260991) \ No newline at end of file diff --git a/contracts/package.json b/contracts/package.json index 5f7a8c3d325..2683b49cc02 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -51,15 +51,15 @@ "@types/deep-equal-in-any-order": "^1.0.1", "@types/mocha": "^8.2.2", "@types/node": "^15.12.2", - "@typescript-eslint/eslint-plugin": "^5.59.5", - "@typescript-eslint/parser": "^5.59.5", + "@typescript-eslint/eslint-plugin": "^6.6.0", + "@typescript-eslint/parser": "^6.6.0", "abi-to-sol": "^0.6.6", "chai": "^4.3.4", "debug": "^4.3.2", - "eslint": "^8.40.0", - "eslint-config-prettier": "^8.8.0", + "eslint": "^8.48.0", + "eslint-config-prettier": "^9.0.0", "deep-equal-in-any-order": "^2.0.6", - "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-prettier": "^5.0.0", "ethereum-waffle": "^3.3.0", "ethers": "~5.6.0", "hardhat": "~2.12.7", @@ -69,10 +69,10 @@ "hardhat-ignore-warnings": "^0.2.6", "istanbul": "^0.4.5", "moment": "^2.29.4", - "prettier": "^2.8.8", + "prettier": "^3.0.3", "prettier-plugin-solidity": "1.1.3", "rlp": "^2.0.0", - "solhint": "^3.4.1", + "solhint": "^3.6.2", "solhint-plugin-prettier": "^0.0.5", "solidity-coverage": "^0.8.4", "ts-node": "^10.0.0", diff --git a/contracts/pnpm-lock.yaml b/contracts/pnpm-lock.yaml index da673532152..fde49eb9fdc 100644 --- a/contracts/pnpm-lock.yaml +++ b/contracts/pnpm-lock.yaml @@ -83,11 +83,11 @@ devDependencies: specifier: ^15.12.2 version: 15.14.9 '@typescript-eslint/eslint-plugin': - specifier: ^5.59.5 - version: 5.59.8(@typescript-eslint/parser@5.59.8)(eslint@8.42.0)(typescript@4.9.5) + specifier: ^6.6.0 + version: 6.6.0(@typescript-eslint/parser@6.6.0)(eslint@8.48.0)(typescript@4.9.5) '@typescript-eslint/parser': - specifier: ^5.59.5 - version: 5.59.8(eslint@8.42.0)(typescript@4.9.5) + specifier: ^6.6.0 + version: 6.6.0(eslint@8.48.0)(typescript@4.9.5) abi-to-sol: specifier: ^0.6.6 version: 0.6.6 @@ -101,14 +101,14 @@ devDependencies: specifier: ^2.0.6 version: 2.0.6 eslint: - specifier: ^8.40.0 - version: 8.42.0 + specifier: ^8.48.0 + version: 8.48.0 eslint-config-prettier: - specifier: ^8.8.0 - version: 8.8.0(eslint@8.42.0) + specifier: ^9.0.0 + version: 9.0.0(eslint@8.48.0) eslint-plugin-prettier: - specifier: ^4.2.1 - version: 4.2.1(eslint-config-prettier@8.8.0)(eslint@8.42.0)(prettier@2.8.8) + specifier: ^5.0.0 + version: 5.0.0(eslint-config-prettier@9.0.0)(eslint@8.48.0)(prettier@3.0.3) ethereum-waffle: specifier: ^3.3.0 version: 3.3.0(typescript@4.9.5) @@ -137,20 +137,20 @@ devDependencies: specifier: ^2.29.4 version: 2.29.4 prettier: - specifier: ^2.8.8 - version: 2.8.8 + specifier: ^3.0.3 + version: 3.0.3 prettier-plugin-solidity: specifier: 1.1.3 - version: 1.1.3(prettier@2.8.8) + version: 1.1.3(prettier@3.0.3) rlp: specifier: ^2.0.0 version: 2.2.7 solhint: - specifier: ^3.4.1 - version: 3.4.1 + specifier: ^3.6.2 + version: 3.6.2 solhint-plugin-prettier: specifier: ^0.0.5 - version: 0.0.5(prettier-plugin-solidity@1.1.3)(prettier@2.8.8) + version: 0.0.5(prettier-plugin-solidity@1.1.3)(prettier@3.0.3) solidity-coverage: specifier: ^0.8.4 version: 0.8.4(hardhat@2.12.7) @@ -169,6 +169,11 @@ devDependencies: packages: + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + dev: true + /@babel/code-frame@7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} @@ -248,14 +253,14 @@ packages: deprecated: Please use @ensdomains/ens-contracts dev: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.42.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.48.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.42.0 - eslint-visitor-keys: 3.4.1 + eslint: 8.48.0 + eslint-visitor-keys: 3.4.3 dev: true /@eslint-community/regexpp@4.5.1: @@ -263,13 +268,18 @@ packages: engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true - /@eslint/eslintrc@2.0.3: - resolution: {integrity: sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==} + /@eslint-community/regexpp@4.8.0: + resolution: {integrity: sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/eslintrc@2.1.2: + resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 debug: 4.3.4(supports-color@8.1.1) - espree: 9.5.2 + espree: 9.6.1 globals: 13.20.0 ignore: 5.2.4 import-fresh: 3.3.0 @@ -280,8 +290,8 @@ packages: - supports-color dev: true - /@eslint/js@8.42.0: - resolution: {integrity: sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==} + /@eslint/js@8.48.0: + resolution: {integrity: sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true @@ -1440,6 +1450,18 @@ packages: - supports-color dev: true + /@pkgr/utils@2.4.2: + resolution: {integrity: sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dependencies: + cross-spawn: 7.0.3 + fast-glob: 3.3.1 + is-glob: 4.0.3 + open: 9.1.0 + picocolors: 1.0.0 + tslib: 2.6.2 + dev: true + /@resolver-engine/core@0.3.3: resolution: {integrity: sha512-eB8nEbKDJJBi5p5SrvrvILn4a0h42bKtbCTri3ZxCGt6UvoQyp7HnGOfki944bUjBSHKK3RvgfViHn+kqdXtnQ==} dependencies: @@ -1850,8 +1872,8 @@ packages: resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==} dev: true - /@types/json-schema@7.0.11: - resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} + /@types/json-schema@7.0.12: + resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} dev: true /@types/keyv@3.1.4: @@ -1969,133 +1991,134 @@ packages: '@types/underscore': 1.11.4 dev: true - /@typescript-eslint/eslint-plugin@5.59.8(@typescript-eslint/parser@5.59.8)(eslint@8.42.0)(typescript@4.9.5): - resolution: {integrity: sha512-JDMOmhXteJ4WVKOiHXGCoB96ADWg9q7efPWHRViT/f09bA8XOMLAVHHju3l0MkZnG1izaWXYmgvQcUjTRcpShQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/eslint-plugin@6.6.0(@typescript-eslint/parser@6.6.0)(eslint@8.48.0)(typescript@4.9.5): + resolution: {integrity: sha512-CW9YDGTQnNYMIo5lMeuiIG08p4E0cXrXTbcZ2saT/ETE7dWUrNxlijsQeU04qAAKkILiLzdQz+cGFxCJjaZUmA==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - '@typescript-eslint/parser': ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: '@eslint-community/regexpp': 4.5.1 - '@typescript-eslint/parser': 5.59.8(eslint@8.42.0)(typescript@4.9.5) - '@typescript-eslint/scope-manager': 5.59.8 - '@typescript-eslint/type-utils': 5.59.8(eslint@8.42.0)(typescript@4.9.5) - '@typescript-eslint/utils': 5.59.8(eslint@8.42.0)(typescript@4.9.5) + '@typescript-eslint/parser': 6.6.0(eslint@8.48.0)(typescript@4.9.5) + '@typescript-eslint/scope-manager': 6.6.0 + '@typescript-eslint/type-utils': 6.6.0(eslint@8.48.0)(typescript@4.9.5) + '@typescript-eslint/utils': 6.6.0(eslint@8.48.0)(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 6.6.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.42.0 - grapheme-splitter: 1.0.4 + eslint: 8.48.0 + graphemer: 1.4.0 ignore: 5.2.4 - natural-compare-lite: 1.4.0 - semver: 7.5.0 - tsutils: 3.21.0(typescript@4.9.5) + natural-compare: 1.4.0 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@5.59.8(eslint@8.42.0)(typescript@4.9.5): - resolution: {integrity: sha512-AnR19RjJcpjoeGojmwZtCwBX/RidqDZtzcbG3xHrmz0aHHoOcbWnpDllenRDmDvsV0RQ6+tbb09/kyc+UT9Orw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/parser@6.6.0(eslint@8.48.0)(typescript@4.9.5): + resolution: {integrity: sha512-setq5aJgUwtzGrhW177/i+DMLqBaJbdwGj2CPIVFFLE0NCliy5ujIdLHd2D1ysmlmsjdL2GWW+hR85neEfc12w==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^7.0.0 || ^8.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.59.8 - '@typescript-eslint/types': 5.59.8 - '@typescript-eslint/typescript-estree': 5.59.8(typescript@4.9.5) + '@typescript-eslint/scope-manager': 6.6.0 + '@typescript-eslint/types': 6.6.0 + '@typescript-eslint/typescript-estree': 6.6.0(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 6.6.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.42.0 + eslint: 8.48.0 typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager@5.59.8: - resolution: {integrity: sha512-/w08ndCYI8gxGf+9zKf1vtx/16y8MHrZs5/tnjHhMLNSixuNcJavSX4wAiPf4aS5x41Es9YPCn44MIe4cxIlig==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/scope-manager@6.6.0: + resolution: {integrity: sha512-pT08u5W/GT4KjPUmEtc2kSYvrH8x89cVzkA0Sy2aaOUIw6YxOIjA8ilwLr/1fLjOedX1QAuBpG9XggWqIIfERw==} + engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 5.59.8 - '@typescript-eslint/visitor-keys': 5.59.8 + '@typescript-eslint/types': 6.6.0 + '@typescript-eslint/visitor-keys': 6.6.0 dev: true - /@typescript-eslint/type-utils@5.59.8(eslint@8.42.0)(typescript@4.9.5): - resolution: {integrity: sha512-+5M518uEIHFBy3FnyqZUF3BMP+AXnYn4oyH8RF012+e7/msMY98FhGL5SrN29NQ9xDgvqCgYnsOiKp1VjZ/fpA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/type-utils@6.6.0(eslint@8.48.0)(typescript@4.9.5): + resolution: {integrity: sha512-8m16fwAcEnQc69IpeDyokNO+D5spo0w1jepWWY2Q6y5ZKNuj5EhVQXjtVAeDDqvW6Yg7dhclbsz6rTtOvcwpHg==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - eslint: '*' + eslint: ^7.0.0 || ^8.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.59.8(typescript@4.9.5) - '@typescript-eslint/utils': 5.59.8(eslint@8.42.0)(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 6.6.0(typescript@4.9.5) + '@typescript-eslint/utils': 6.6.0(eslint@8.48.0)(typescript@4.9.5) debug: 4.3.4(supports-color@8.1.1) - eslint: 8.42.0 - tsutils: 3.21.0(typescript@4.9.5) + eslint: 8.48.0 + ts-api-utils: 1.0.3(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/types@5.59.8: - resolution: {integrity: sha512-+uWuOhBTj/L6awoWIg0BlWy0u9TyFpCHrAuQ5bNfxDaZ1Ppb3mx6tUigc74LHcbHpOHuOTOJrBoAnhdHdaea1w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/types@6.6.0: + resolution: {integrity: sha512-CB6QpJQ6BAHlJXdwUmiaXDBmTqIE2bzGTDLADgvqtHWuhfNP3rAOK7kAgRMAET5rDRr9Utt+qAzRBdu3AhR3sg==} + engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/typescript-estree@5.59.8(typescript@4.9.5): - resolution: {integrity: sha512-Jy/lPSDJGNow14vYu6IrW790p7HIf/SOV1Bb6lZ7NUkLc2iB2Z9elESmsaUtLw8kVqogSbtLH9tut5GCX1RLDg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/typescript-estree@6.6.0(typescript@4.9.5): + resolution: {integrity: sha512-hMcTQ6Al8MP2E6JKBAaSxSVw5bDhdmbCEhGW/V8QXkb9oNsFkA4SBuOMYVPxD3jbtQ4R/vSODBsr76R6fP3tbA==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.59.8 - '@typescript-eslint/visitor-keys': 5.59.8 + '@typescript-eslint/types': 6.6.0 + '@typescript-eslint/visitor-keys': 6.6.0 debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 - semver: 7.5.0 - tsutils: 3.21.0(typescript@4.9.5) + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@5.59.8(eslint@8.42.0)(typescript@4.9.5): - resolution: {integrity: sha512-Tr65630KysnNn9f9G7ROF3w1b5/7f6QVCJ+WK9nhIocWmx9F+TmCAcglF26Vm7z8KCTwoKcNEBZrhlklla3CKg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/utils@6.6.0(eslint@8.48.0)(typescript@4.9.5): + resolution: {integrity: sha512-mPHFoNa2bPIWWglWYdR0QfY9GN0CfvvXX1Sv6DlSTive3jlMTUy+an67//Gysc+0Me9pjitrq0LJp0nGtLgftw==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.42.0) - '@types/json-schema': 7.0.11 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.48.0) + '@types/json-schema': 7.0.12 '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 5.59.8 - '@typescript-eslint/types': 5.59.8 - '@typescript-eslint/typescript-estree': 5.59.8(typescript@4.9.5) - eslint: 8.42.0 - eslint-scope: 5.1.1 - semver: 7.5.0 + '@typescript-eslint/scope-manager': 6.6.0 + '@typescript-eslint/types': 6.6.0 + '@typescript-eslint/typescript-estree': 6.6.0(typescript@4.9.5) + eslint: 8.48.0 + semver: 7.5.4 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/visitor-keys@5.59.8: - resolution: {integrity: sha512-pJhi2ms0x0xgloT7xYabil3SGGlojNNKjK/q6dB3Ey0uJLMjK2UDGJvHieiyJVW/7C3KI+Z4Q3pEHkm4ejA+xQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/visitor-keys@6.6.0: + resolution: {integrity: sha512-L61uJT26cMOfFQ+lMZKoJNbAEckLe539VhTxiGHrWl5XSKQgA0RTBZJW2HFPy5T0ZvPVSD93QsrTKDkfNwJGyQ==} + engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 5.59.8 + '@typescript-eslint/types': 6.6.0 eslint-visitor-keys: 3.4.1 dev: true @@ -2187,16 +2210,16 @@ packages: negotiator: 0.6.2 dev: true - /acorn-jsx@5.3.2(acorn@8.8.0): + /acorn-jsx@5.3.2(acorn@8.10.0): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - acorn: 8.8.0 + acorn: 8.10.0 dev: true - /acorn@8.8.0: - resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==} + /acorn@8.10.0: + resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} engines: {node: '>=0.4.0'} hasBin: true dev: true @@ -3109,6 +3132,11 @@ packages: engines: {node: '>=0.6'} dev: true + /big-integer@1.6.51: + resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==} + engines: {node: '>=0.6'} + dev: true + /big.js@6.2.1: resolution: {integrity: sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==} dev: true @@ -3200,6 +3228,13 @@ packages: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} dev: true + /bplist-parser@0.2.0: + resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==} + engines: {node: '>= 5.10.0'} + dependencies: + big-integer: 1.6.51 + dev: true + /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -3375,6 +3410,13 @@ packages: engines: {node: '>=8.0.0'} dev: false + /bundle-name@3.0.0: + resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==} + engines: {node: '>=12'} + dependencies: + run-applescript: 5.0.0 + dev: true + /busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} @@ -3880,7 +3922,7 @@ packages: dev: true /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} dev: true /concat-stream@1.6.2: @@ -4242,6 +4284,24 @@ packages: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true + /default-browser-id@3.0.0: + resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==} + engines: {node: '>=12'} + dependencies: + bplist-parser: 0.2.0 + untildify: 4.0.0 + dev: true + + /default-browser@4.0.0: + resolution: {integrity: sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==} + engines: {node: '>=14.16'} + dependencies: + bundle-name: 3.0.0 + default-browser-id: 3.0.0 + execa: 7.2.0 + titleize: 3.0.0 + dev: true + /defer-to-connect@1.1.1: resolution: {integrity: sha512-J7thop4u3mRTkYRQ+Vpfwy2G5Ehoy82I14+14W4YMDLKdWloI9gSzRbV30s/NckQGVJtPkWNcW4oMAUigTdqiQ==} requiresBuild: true @@ -4266,6 +4326,11 @@ packages: inherits: 2.0.4 dev: true + /define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + dev: true + /define-properties@1.1.4: resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} engines: {node: '>= 0.4'} @@ -4645,42 +4710,38 @@ packages: source-map: 0.2.0 dev: true - /eslint-config-prettier@8.8.0(eslint@8.42.0): - resolution: {integrity: sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==} + /eslint-config-prettier@9.0.0(eslint@8.48.0): + resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.42.0 + eslint: 8.48.0 dev: true - /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.8.0)(eslint@8.42.0)(prettier@2.8.8): - resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} - engines: {node: '>=12.0.0'} + /eslint-plugin-prettier@5.0.0(eslint-config-prettier@9.0.0)(eslint@8.48.0)(prettier@3.0.3): + resolution: {integrity: sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==} + engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: - eslint: '>=7.28.0' + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' eslint-config-prettier: '*' - prettier: '>=2.0.0' + prettier: '>=3.0.0' peerDependenciesMeta: + '@types/eslint': + optional: true eslint-config-prettier: optional: true dependencies: - eslint: 8.42.0 - eslint-config-prettier: 8.8.0(eslint@8.42.0) - prettier: 2.8.8 + eslint: 8.48.0 + eslint-config-prettier: 9.0.0(eslint@8.48.0) + prettier: 3.0.3 prettier-linter-helpers: 1.0.0 + synckit: 0.8.5 dev: true - /eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - dev: true - - /eslint-scope@7.2.0: - resolution: {integrity: sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==} + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: esrecurse: 4.3.0 @@ -4692,15 +4753,20 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@8.42.0: - resolution: {integrity: sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==} + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /eslint@8.48.0: + resolution: {integrity: sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.42.0) - '@eslint-community/regexpp': 4.5.1 - '@eslint/eslintrc': 2.0.3 - '@eslint/js': 8.42.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.48.0) + '@eslint-community/regexpp': 4.8.0 + '@eslint/eslintrc': 2.1.2 + '@eslint/js': 8.48.0 '@humanwhocodes/config-array': 0.11.10 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 @@ -4710,9 +4776,9 @@ packages: debug: 4.3.4(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 - eslint-scope: 7.2.0 - eslint-visitor-keys: 3.4.1 - espree: 9.5.2 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 @@ -4721,8 +4787,7 @@ packages: glob-parent: 6.0.2 globals: 13.20.0 graphemer: 1.4.0 - ignore: 5.2.0 - import-fresh: 3.3.0 + ignore: 5.2.4 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 @@ -4732,21 +4797,20 @@ packages: lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 - optionator: 0.9.1 + optionator: 0.9.3 strip-ansi: 6.0.1 - strip-json-comments: 3.1.1 text-table: 0.2.0 transitivePeerDependencies: - supports-color dev: true - /espree@9.5.2: - resolution: {integrity: sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==} + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 8.8.0 - acorn-jsx: 5.3.2(acorn@8.8.0) - eslint-visitor-keys: 3.4.1 + acorn: 8.10.0 + acorn-jsx: 5.3.2(acorn@8.10.0) + eslint-visitor-keys: 3.4.3 dev: true /esprima@2.7.3: @@ -4780,11 +4844,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - dev: true - /estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -5300,6 +5359,36 @@ packages: safe-buffer: 5.2.1 dev: true + /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 + + /execa@7.2.0: + resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==} + engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 4.3.1 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.1.0 + onetime: 6.0.0 + signal-exit: 3.0.7 + strip-final-newline: 3.0.0 + dev: true + /expand-brackets@2.1.4: resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} engines: {node: '>=0.10.0'} @@ -5436,6 +5525,17 @@ packages: micromatch: 4.0.5 dev: true + /fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + 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: true + /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} dev: true @@ -6494,6 +6594,16 @@ packages: - supports-color dev: true + /human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + dev: true + + /human-signals@4.3.1: + resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==} + engines: {node: '>=14.18.0'} + dev: true + /iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -6519,11 +6629,6 @@ packages: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} dev: true - /ignore@5.2.0: - resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==} - engines: {node: '>= 4'} - dev: true - /ignore@5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} @@ -6727,6 +6832,12 @@ packages: hasBin: true dev: true + /is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + dev: true + /is-extendable@0.1.1: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} engines: {node: '>=0.10.0'} @@ -6792,6 +6903,14 @@ packages: engines: {node: '>=6.5.0', npm: '>=3'} dev: true + /is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + dependencies: + is-docker: 3.0.0 + dev: true + /is-lower-case@1.1.3: resolution: {integrity: sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==} dependencies: @@ -6872,6 +6991,16 @@ packages: engines: {node: '>=0.10.0'} dev: true + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: true + + /is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} @@ -7664,6 +7793,10 @@ packages: resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} dev: true + /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'} @@ -7754,6 +7887,16 @@ packages: hasBin: true dev: true + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: true + + /mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + dev: true + /mimic-response@1.0.1: resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} engines: {node: '>=4'} @@ -8064,10 +8207,6 @@ packages: resolution: {integrity: sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==} dev: true - /natural-compare-lite@1.4.0: - resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} - dev: true - /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true @@ -8191,6 +8330,20 @@ packages: engines: {node: '>=10'} dev: true + /npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + dev: true + + /npm-run-path@5.1.0: + resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + path-key: 4.0.0 + dev: true + /nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} dependencies: @@ -8324,6 +8477,20 @@ packages: 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 + + /onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + dependencies: + mimic-fn: 4.0.0 + dev: true + /open@7.4.2: resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} engines: {node: '>=8'} @@ -8332,6 +8499,16 @@ packages: is-wsl: 2.2.0 dev: true + /open@9.1.0: + resolution: {integrity: sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==} + engines: {node: '>=14.16'} + dependencies: + default-browser: 4.0.0 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + is-wsl: 2.2.0 + dev: true + /optionator@0.8.3: resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} engines: {node: '>= 0.8.0'} @@ -8344,16 +8521,16 @@ packages: word-wrap: 1.2.3 dev: true - /optionator@0.9.1: - resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} + /optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} engines: {node: '>= 0.8.0'} dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 - word-wrap: 1.2.3 dev: true /os-homedir@1.0.2: @@ -8629,6 +8806,11 @@ packages: engines: {node: '>=8'} dev: true + /path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + dev: true + /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true @@ -8669,6 +8851,10 @@ packages: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} dev: true + /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'} @@ -8755,6 +8941,19 @@ packages: semver: 7.5.0 solidity-comments-extractor: 0.0.7 dev: true + optional: true + + /prettier-plugin-solidity@1.1.3(prettier@3.0.3): + resolution: {integrity: sha512-fQ9yucPi2sBbA2U2Xjh6m4isUTJ7S7QLc/XDDsktqqxYfTwdYKJ0EnnywXHwCGAaYbQNK+HIYPL1OemxuMsgeg==} + engines: {node: '>=12'} + peerDependencies: + prettier: '>=2.3.0 || >=3.0.0-alpha.0' + dependencies: + '@solidity-parser/parser': 0.16.0 + prettier: 3.0.3 + semver: 7.5.0 + solidity-comments-extractor: 0.0.7 + dev: true /prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} @@ -8762,6 +8961,12 @@ packages: hasBin: true dev: true + /prettier@3.0.3: + resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==} + engines: {node: '>=14'} + hasBin: true + dev: true + /private@0.1.8: resolution: {integrity: sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==} engines: {node: '>= 0.6'} @@ -9319,6 +9524,13 @@ packages: bn.js: 5.2.1 dev: true + /run-applescript@5.0.0: + resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==} + engines: {node: '>=12'} + dependencies: + execa: 5.1.1 + dev: true + /run-parallel-limit@1.1.0: resolution: {integrity: sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==} dependencies: @@ -9466,6 +9678,14 @@ packages: lru-cache: 6.0.0 dev: true + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + /send@0.17.1: resolution: {integrity: sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==} engines: {node: '>= 0.8.0'} @@ -9756,19 +9976,19 @@ packages: - debug dev: true - /solhint-plugin-prettier@0.0.5(prettier-plugin-solidity@1.1.3)(prettier@2.8.8): + /solhint-plugin-prettier@0.0.5(prettier-plugin-solidity@1.1.3)(prettier@3.0.3): resolution: {integrity: sha512-7jmWcnVshIrO2FFinIvDQmhQpfpS2rRRn3RejiYgnjIE68xO2bvrYvjqVNfrio4xH9ghOqn83tKuTzLjEbmGIA==} peerDependencies: prettier: ^1.15.0 || ^2.0.0 prettier-plugin-solidity: ^1.0.0-alpha.14 dependencies: - prettier: 2.8.8 + prettier: 3.0.3 prettier-linter-helpers: 1.0.0 - prettier-plugin-solidity: 1.1.3(prettier@2.8.8) + prettier-plugin-solidity: 1.1.3(prettier@3.0.3) dev: true - /solhint@3.4.1: - resolution: {integrity: sha512-pzZn2RlZhws1XwvLPVSsxfHrwsteFf5eySOhpAytzXwKQYbTCJV6z8EevYDiSVKMpWrvbKpEtJ055CuEmzp4Xg==} + /solhint@3.6.2: + resolution: {integrity: sha512-85EeLbmkcPwD+3JR7aEMKsVC9YrRSxd4qkXuMzrlf7+z2Eqdfm1wHWq1ffTuo5aDhoZxp2I9yF3QkxZOxOL7aQ==} hasBin: true dependencies: '@solidity-parser/parser': 0.16.0 @@ -9784,7 +10004,7 @@ packages: js-yaml: 4.1.0 lodash: 4.17.21 pluralize: 8.0.0 - semver: 6.3.0 + semver: 7.5.4 strip-ansi: 6.0.1 table: 6.8.1 text-table: 0.2.0 @@ -10209,6 +10429,16 @@ packages: is-utf8: 0.2.1 dev: true + /strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + dev: true + + /strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + dev: true + /strip-hex-prefix@1.0.0: resolution: {integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==} engines: {node: '>=6.5.0', npm: '>=3'} @@ -10318,6 +10548,14 @@ packages: get-port: 3.2.0 dev: true + /synckit@0.8.5: + resolution: {integrity: sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==} + engines: {node: ^14.18.0 || >=16.0.0} + dependencies: + '@pkgr/utils': 2.4.2 + tslib: 2.6.2 + dev: true + /table-layout@1.0.2: resolution: {integrity: sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==} engines: {node: '>=8.0.0'} @@ -10441,6 +10679,11 @@ packages: upper-case: 1.1.3 dev: true + /titleize@3.0.0: + resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==} + engines: {node: '>=12'} + dev: true + /tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -10525,6 +10768,15 @@ packages: engines: {node: '>=0.10.0'} dev: true + /ts-api-utils@1.0.3(typescript@4.9.5): + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} + engines: {node: '>=16.13.0'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 4.9.5 + dev: true + /ts-command-line-args@2.5.1: resolution: {integrity: sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==} hasBin: true @@ -10607,18 +10859,12 @@ packages: resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} dev: true - /tsort@0.0.1: - resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==} + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} dev: true - /tsutils@3.21.0(typescript@4.9.5): - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - peerDependencies: - typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' - dependencies: - tslib: 1.14.1 - typescript: 4.9.5 + /tsort@0.0.1: + resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==} dev: true /tunnel-agent@0.6.0: @@ -10846,6 +11092,11 @@ packages: isobject: 3.0.1 dev: true + /untildify@4.0.0: + resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} + engines: {node: '>=8'} + dev: true + /upper-case-first@1.1.2: resolution: {integrity: sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==} dependencies: diff --git a/contracts/scripts/generate-automation-master-interface.ts b/contracts/scripts/generate-automation-master-interface.ts index c480098c77f..821b0caac60 100644 --- a/contracts/scripts/generate-automation-master-interface.ts +++ b/contracts/scripts/generate-automation-master-interface.ts @@ -9,7 +9,7 @@ import { utils } from 'ethers' import fs from 'fs' import { exec } from 'child_process' -const dest = 'src/v0.8/dev/automation/2_1/interfaces' +const dest = 'src/v0.8/automation/interfaces/2_1' const srcDest = `${dest}/IKeeperRegistryMaster.sol` const tmpDest = `${dest}/tmp.txt` diff --git a/contracts/scripts/native_solc_compile_all_automation b/contracts/scripts/native_solc_compile_all_automation index e7dbe0db676..c38f4c2e3d5 100755 --- a/contracts/scripts/native_solc_compile_all_automation +++ b/contracts/scripts/native_solc_compile_all_automation @@ -37,7 +37,7 @@ compileContract automation/2_0/KeeperRegistry2_0.sol compileContract automation/2_0/KeeperRegistryLogic2_0.sol compileContract automation/UpkeepTranscoder.sol compileContract automation/mocks/MockAggregatorProxy.sol -compileContract dev/automation/tests/LogUpkeepCounter.sol +compileContract automation/testhelpers/LogUpkeepCounter.sol # Keepers x VRF v2 compileContract KeepersVRFConsumer.sol @@ -52,17 +52,17 @@ solc-select use $SOLC_VERSION export SOLC_VERSION=$SOLC_VERSION # v0.8.16 -compileContract dev/automation/2_1/AutomationRegistrar2_1.sol -compileContract dev/automation/2_1/KeeperRegistry2_1.sol -compileContract dev/automation/2_1/KeeperRegistryLogicA2_1.sol -compileContract dev/automation/2_1/KeeperRegistryLogicB2_1.sol -compileContract dev/automation/2_1/interfaces/IKeeperRegistryMaster.sol -compileContract dev/automation/2_1/interfaces/ILogAutomation.sol -compileContract dev/automation/2_1/AutomationUtils2_1.sol -compileContract dev/automation/2_1/AutomationForwarderLogic.sol -compileContract dev/automation/tests/LogTriggeredStreamsLookup.sol -compileContract dev/automation/tests/DummyProtocol.sol -compileContract dev/automation/2_1/interfaces/StreamsLookupCompatibleInterface.sol +compileContract automation/2_1/AutomationRegistrar2_1.sol +compileContract automation/2_1/KeeperRegistry2_1.sol +compileContract automation/2_1/KeeperRegistryLogicA2_1.sol +compileContract automation/2_1/KeeperRegistryLogicB2_1.sol +compileContract automation/interfaces/2_1/IKeeperRegistryMaster.sol +compileContract automation/interfaces/ILogAutomation.sol +compileContract automation/2_1/AutomationUtils2_1.sol +compileContract automation/2_1/AutomationForwarderLogic.sol +compileContract automation/testhelpers/LogTriggeredStreamsLookup.sol +compileContract automation/testhelpers/DummyProtocol.sol +compileContract automation/interfaces/StreamsLookupCompatibleInterface.sol compileContract tests/VerifiableLoadUpkeep.sol compileContract tests/VerifiableLoadStreamsLookupUpkeep.sol diff --git a/contracts/scripts/native_solc_compile_all_vrf b/contracts/scripts/native_solc_compile_all_vrf index 72be6eebf8d..feebbdcf145 100755 --- a/contracts/scripts/native_solc_compile_all_vrf +++ b/contracts/scripts/native_solc_compile_all_vrf @@ -51,6 +51,7 @@ compileContract vrf/BatchBlockhashStore.sol compileContract vrf/BatchVRFCoordinatorV2.sol compileContract vrf/testhelpers/VRFCoordinatorV2TestHelper.sol compileContractAltOpts vrf/VRFCoordinatorV2.sol 10000 +compileContract mocks/VRFCoordinatorV2Mock.sol compileContract vrf/VRFOwner.sol # VRF V2Plus diff --git a/contracts/src/v0.8/ChainSpecificUtil.sol b/contracts/src/v0.8/ChainSpecificUtil.sol index f3d3fd0aabd..324121c9fa5 100644 --- a/contracts/src/v0.8/ChainSpecificUtil.sol +++ b/contracts/src/v0.8/ChainSpecificUtil.sol @@ -14,10 +14,15 @@ library ChainSpecificUtil { ArbGasInfo private constant ARBGAS = ArbGasInfo(ARBGAS_ADDR); uint256 private constant ARB_MAINNET_CHAIN_ID = 42161; uint256 private constant ARB_GOERLI_TESTNET_CHAIN_ID = 421613; + uint256 private constant ARB_SEPOLIA_TESTNET_CHAIN_ID = 421614; function getBlockhash(uint64 blockNumber) internal view returns (bytes32) { uint256 chainid = block.chainid; - if (chainid == ARB_MAINNET_CHAIN_ID || chainid == ARB_GOERLI_TESTNET_CHAIN_ID) { + if ( + chainid == ARB_MAINNET_CHAIN_ID || + chainid == ARB_GOERLI_TESTNET_CHAIN_ID || + chainid == ARB_SEPOLIA_TESTNET_CHAIN_ID + ) { if ((getBlockNumber() - blockNumber) > 256 || blockNumber >= getBlockNumber()) { return ""; } diff --git a/contracts/src/v0.8/dev/automation/UpkeepTranscoder3_0.sol b/contracts/src/v0.8/automation/2_0/UpkeepTranscoder3_0.sol similarity index 100% rename from contracts/src/v0.8/dev/automation/UpkeepTranscoder3_0.sol rename to contracts/src/v0.8/automation/2_0/UpkeepTranscoder3_0.sol diff --git a/contracts/src/v0.8/dev/automation/2_1/AutomationForwarder.sol b/contracts/src/v0.8/automation/2_1/AutomationForwarder.sol similarity index 95% rename from contracts/src/v0.8/dev/automation/2_1/AutomationForwarder.sol rename to contracts/src/v0.8/automation/2_1/AutomationForwarder.sol index 4d574884b8d..e5a80ce3252 100644 --- a/contracts/src/v0.8/dev/automation/2_1/AutomationForwarder.sol +++ b/contracts/src/v0.8/automation/2_1/AutomationForwarder.sol @@ -1,7 +1,7 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; -import {IAutomationRegistryConsumer} from "./interfaces/IAutomationRegistryConsumer.sol"; +import {IAutomationRegistryConsumer} from "../interfaces/IAutomationRegistryConsumer.sol"; uint256 constant PERFORM_GAS_CUSHION = 5_000; diff --git a/contracts/src/v0.8/dev/automation/2_1/AutomationForwarderLogic.sol b/contracts/src/v0.8/automation/2_1/AutomationForwarderLogic.sol similarity index 76% rename from contracts/src/v0.8/dev/automation/2_1/AutomationForwarderLogic.sol rename to contracts/src/v0.8/automation/2_1/AutomationForwarderLogic.sol index 0a5535ce061..a7903c379df 100644 --- a/contracts/src/v0.8/dev/automation/2_1/AutomationForwarderLogic.sol +++ b/contracts/src/v0.8/automation/2_1/AutomationForwarderLogic.sol @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; -import {IAutomationRegistryConsumer} from "./interfaces/IAutomationRegistryConsumer.sol"; -import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; +import {IAutomationRegistryConsumer} from "../interfaces/IAutomationRegistryConsumer.sol"; +import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; contract AutomationForwarderLogic is ITypeAndVersion { IAutomationRegistryConsumer private s_registry; diff --git a/contracts/src/v0.8/dev/automation/2_1/AutomationRegistrar2_1.sol b/contracts/src/v0.8/automation/2_1/AutomationRegistrar2_1.sol similarity index 97% rename from contracts/src/v0.8/dev/automation/2_1/AutomationRegistrar2_1.sol rename to contracts/src/v0.8/automation/2_1/AutomationRegistrar2_1.sol index 847098e0fd4..b2679b3c151 100644 --- a/contracts/src/v0.8/dev/automation/2_1/AutomationRegistrar2_1.sol +++ b/contracts/src/v0.8/automation/2_1/AutomationRegistrar2_1.sol @@ -1,11 +1,11 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; -import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; -import {IKeeperRegistryMaster} from "./interfaces/IKeeperRegistryMaster.sol"; -import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; -import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; -import {IERC677Receiver} from "../../../shared/interfaces/IERC677Receiver.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {IKeeperRegistryMaster} from "../interfaces/2_1/IKeeperRegistryMaster.sol"; +import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {IERC677Receiver} from "../../shared/interfaces/IERC677Receiver.sol"; /** * @notice Contract to accept requests for upkeep registrations diff --git a/contracts/src/v0.8/dev/automation/2_1/AutomationUtils2_1.sol b/contracts/src/v0.8/automation/2_1/AutomationUtils2_1.sol similarity index 92% rename from contracts/src/v0.8/dev/automation/2_1/AutomationUtils2_1.sol rename to contracts/src/v0.8/automation/2_1/AutomationUtils2_1.sol index 1c1d76399bb..ed19b450d8b 100644 --- a/contracts/src/v0.8/dev/automation/2_1/AutomationUtils2_1.sol +++ b/contracts/src/v0.8/automation/2_1/AutomationUtils2_1.sol @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; import {KeeperRegistryBase2_1} from "./KeeperRegistryBase2_1.sol"; -import {ILogAutomation, Log} from "./interfaces/ILogAutomation.sol"; +import {ILogAutomation, Log} from "../interfaces/ILogAutomation.sol"; /** * @notice this file exposes structs that are otherwise internal to the automation registry diff --git a/contracts/src/v0.8/dev/automation/2_1/KeeperRegistry2_1.sol b/contracts/src/v0.8/automation/2_1/KeeperRegistry2_1.sol similarity index 96% rename from contracts/src/v0.8/dev/automation/2_1/KeeperRegistry2_1.sol rename to contracts/src/v0.8/automation/2_1/KeeperRegistry2_1.sol index 88d173f2288..bb287c3c731 100644 --- a/contracts/src/v0.8/dev/automation/2_1/KeeperRegistry2_1.sol +++ b/contracts/src/v0.8/automation/2_1/KeeperRegistry2_1.sol @@ -1,14 +1,14 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; -import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; -import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; -import {Proxy} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/proxy/Proxy.sol"; +import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; +import {Address} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; +import {Proxy} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/proxy/Proxy.sol"; import {KeeperRegistryBase2_1} from "./KeeperRegistryBase2_1.sol"; import {KeeperRegistryLogicB2_1} from "./KeeperRegistryLogicB2_1.sol"; -import {Chainable} from "./Chainable.sol"; -import {IERC677Receiver} from "../../../shared/interfaces/IERC677Receiver.sol"; -import {OCR2Abstract} from "../../../shared/ocr2/OCR2Abstract.sol"; +import {Chainable} from "../Chainable.sol"; +import {IERC677Receiver} from "../../shared/interfaces/IERC677Receiver.sol"; +import {OCR2Abstract} from "../../shared/ocr2/OCR2Abstract.sol"; /** * @notice Registry for adding work for Chainlink Keepers to perform on client diff --git a/contracts/src/v0.8/dev/automation/2_1/KeeperRegistryBase2_1.sol b/contracts/src/v0.8/automation/2_1/KeeperRegistryBase2_1.sol similarity index 96% rename from contracts/src/v0.8/dev/automation/2_1/KeeperRegistryBase2_1.sol rename to contracts/src/v0.8/automation/2_1/KeeperRegistryBase2_1.sol index ccd286fda2f..2d48671e3e0 100644 --- a/contracts/src/v0.8/dev/automation/2_1/KeeperRegistryBase2_1.sol +++ b/contracts/src/v0.8/automation/2_1/KeeperRegistryBase2_1.sol @@ -1,20 +1,20 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; -import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; -import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; -import {ArbGasInfo} from "../../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol"; -import {OVM_GasPriceOracle} from "../../../vendor/@eth-optimism/contracts/0.8.9/contracts/L2/predeploys/OVM_GasPriceOracle.sol"; -import {ExecutionPrevention} from "../../../automation/ExecutionPrevention.sol"; -import {ArbSys} from "../../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; -import {StreamsLookupCompatibleInterface} from "./interfaces/StreamsLookupCompatibleInterface.sol"; -import {ILogAutomation, Log} from "./interfaces/ILogAutomation.sol"; -import {IAutomationForwarder} from "./interfaces/IAutomationForwarder.sol"; -import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; -import {AggregatorV3Interface} from "../../../interfaces/AggregatorV3Interface.sol"; -import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; -import {KeeperCompatibleInterface} from "../../../automation/interfaces/KeeperCompatibleInterface.sol"; -import {UpkeepTranscoderInterface, UpkeepFormat} from "../../../automation/interfaces/UpkeepTranscoderInterface.sol"; +import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; +import {Address} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; +import {ArbGasInfo} from "../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol"; +import {OVM_GasPriceOracle} from "../../vendor/@eth-optimism/contracts/0.8.9/contracts/L2/predeploys/OVM_GasPriceOracle.sol"; +import {ExecutionPrevention} from "../ExecutionPrevention.sol"; +import {ArbSys} from "../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; +import {StreamsLookupCompatibleInterface} from "../interfaces/StreamsLookupCompatibleInterface.sol"; +import {ILogAutomation, Log} from "../interfaces/ILogAutomation.sol"; +import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {AggregatorV3Interface} from "../../interfaces/AggregatorV3Interface.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {KeeperCompatibleInterface} from "../interfaces/KeeperCompatibleInterface.sol"; +import {UpkeepTranscoderInterface, UpkeepFormat} from "../interfaces/UpkeepTranscoderInterface.sol"; /** * @notice Base Keeper Registry contract, contains shared logic between diff --git a/contracts/src/v0.8/dev/automation/2_1/KeeperRegistryLogicA2_1.sol b/contracts/src/v0.8/automation/2_1/KeeperRegistryLogicA2_1.sol similarity index 96% rename from contracts/src/v0.8/dev/automation/2_1/KeeperRegistryLogicA2_1.sol rename to contracts/src/v0.8/automation/2_1/KeeperRegistryLogicA2_1.sol index ef9acaf9a8b..e3845ce63bd 100644 --- a/contracts/src/v0.8/dev/automation/2_1/KeeperRegistryLogicA2_1.sol +++ b/contracts/src/v0.8/automation/2_1/KeeperRegistryLogicA2_1.sol @@ -1,15 +1,15 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; -import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; -import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; +import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; +import {Address} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; import {KeeperRegistryBase2_1} from "./KeeperRegistryBase2_1.sol"; import {KeeperRegistryLogicB2_1} from "./KeeperRegistryLogicB2_1.sol"; -import {Chainable} from "./Chainable.sol"; +import {Chainable} from "../Chainable.sol"; import {AutomationForwarder} from "./AutomationForwarder.sol"; -import {IAutomationForwarder} from "./interfaces/IAutomationForwarder.sol"; -import {UpkeepTranscoderInterfaceV2} from "../../../automation/interfaces/UpkeepTranscoderInterfaceV2.sol"; -import {MigratableKeeperRegistryInterfaceV2} from "../../../automation/interfaces/MigratableKeeperRegistryInterfaceV2.sol"; +import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol"; +import {UpkeepTranscoderInterfaceV2} from "../interfaces/UpkeepTranscoderInterfaceV2.sol"; +import {MigratableKeeperRegistryInterfaceV2} from "../interfaces/MigratableKeeperRegistryInterfaceV2.sol"; /** * @notice Logic contract, works in tandem with KeeperRegistry as a proxy diff --git a/contracts/src/v0.8/dev/automation/2_1/KeeperRegistryLogicB2_1.sol b/contracts/src/v0.8/automation/2_1/KeeperRegistryLogicB2_1.sol similarity index 97% rename from contracts/src/v0.8/dev/automation/2_1/KeeperRegistryLogicB2_1.sol rename to contracts/src/v0.8/automation/2_1/KeeperRegistryLogicB2_1.sol index ce9d49eac3d..b394bff4ee8 100644 --- a/contracts/src/v0.8/dev/automation/2_1/KeeperRegistryLogicB2_1.sol +++ b/contracts/src/v0.8/automation/2_1/KeeperRegistryLogicB2_1.sol @@ -1,11 +1,11 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; import {KeeperRegistryBase2_1} from "./KeeperRegistryBase2_1.sol"; -import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; -import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; -import {UpkeepFormat} from "../../../automation/interfaces/UpkeepTranscoderInterface.sol"; -import {IAutomationForwarder} from "./interfaces/IAutomationForwarder.sol"; +import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; +import {Address} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; +import {UpkeepFormat} from "../interfaces/UpkeepTranscoderInterface.sol"; +import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol"; contract KeeperRegistryLogicB2_1 is KeeperRegistryBase2_1 { using Address for address; diff --git a/contracts/src/v0.8/automation/2_1/LICENSE b/contracts/src/v0.8/automation/2_1/LICENSE new file mode 100644 index 00000000000..03ba03d7792 --- /dev/null +++ b/contracts/src/v0.8/automation/2_1/LICENSE @@ -0,0 +1,55 @@ +Business Source License 1.1 + +License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved. +"Business Source License" is a trademark of MariaDB Corporation Ab. + +--- + +Parameters + +Licensor: SmartContract Chainlink Limited SEZC + +Licensed Work: Automation v2.1 +The Licensed Work is (c) 2023 SmartContract Chainlink Limited SEZC + +Additional Use Grant: Any uses listed and defined at https://github.com/smartcontractkit/ocr2keepers/tree/main/pkg/v3/Automation_v2.1_Grants.md + +Change Date: September 12, 2027 + +Change License: MIT + +--- + +Terms + +The Licensor hereby grants you the right to copy, modify, create derivative works, redistribute, and make non-production use of the Licensed Work. The Licensor may make an Additional Use Grant, above, permitting limited production use. + +Effective on the Change Date, or the fourth anniversary of the first publicly available distribution of a specific version of the Licensed Work under this License, whichever comes first, the Licensor hereby grants you rights under the terms of the Change License, and the rights granted in the paragraph above terminate. + +If your use of the Licensed Work does not comply with the requirements currently in effect as described in this License, you must purchase a commercial license from the Licensor, its affiliated entities, or authorized resellers, or you must refrain from using the Licensed Work. + +All copies of the original and modified Licensed Work, and derivative works of the Licensed Work, are subject to this License. This License applies separately for each version of the Licensed Work and the Change Date may vary for each version of the Licensed Work released by Licensor. + +You must conspicuously display this License on each original or modified copy of the Licensed Work. If you receive the Licensed Work in original or modified form from a third party, the terms and conditions set forth in this License apply to your use of that work. + +Any use of the Licensed Work in violation of this License will automatically terminate your rights under this License for the current and all other versions of the Licensed Work. + +This License does not grant you any right in any trademark or logo of Licensor or its affiliates (provided that you may use a trademark or logo of Licensor as expressly required by this License). + +TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE. + +MariaDB hereby grants you permission to use this License’s text to license your works, and to refer to it using the trademark "Business Source License", as long as you comply with the Covenants of Licensor below. + +--- + +Covenants of Licensor + +In consideration of the right to use this License’s text and the "Business Source License" name and trademark, Licensor covenants to MariaDB, and to all other recipients of the licensed work to be provided by Licensor: + +1. To specify as the Change License the GPL Version 2.0 or any later version, or a license that is compatible with GPL Version 2.0 or a later version, where "compatible" means that software provided under the Change License can be included in a program with software provided under GPL Version 2.0 or a later version. Licensor may specify additional Change Licenses without limitation. + +2. To either: (a) specify an additional grant of rights to use that does not impose any additional restriction on the right granted in this License, as the Additional Use Grant; or (b) insert the text "None". + +3. To specify a Change Date. + +4. Not to modify this License in any other way. diff --git a/contracts/src/v0.8/dev/automation/2_1/README.md b/contracts/src/v0.8/automation/2_1/README.md similarity index 100% rename from contracts/src/v0.8/dev/automation/2_1/README.md rename to contracts/src/v0.8/automation/2_1/README.md diff --git a/contracts/src/v0.8/dev/automation/2_1/UpkeepTranscoder4_0.sol b/contracts/src/v0.8/automation/2_1/UpkeepTranscoder4_0.sol similarity index 93% rename from contracts/src/v0.8/dev/automation/2_1/UpkeepTranscoder4_0.sol rename to contracts/src/v0.8/automation/2_1/UpkeepTranscoder4_0.sol index fa990df91c9..7e304b42baa 100644 --- a/contracts/src/v0.8/dev/automation/2_1/UpkeepTranscoder4_0.sol +++ b/contracts/src/v0.8/automation/2_1/UpkeepTranscoder4_0.sol @@ -1,12 +1,12 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; -import {UpkeepTranscoderInterfaceV2} from "../../../automation/interfaces/UpkeepTranscoderInterfaceV2.sol"; -import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +import {UpkeepTranscoderInterfaceV2} from "../interfaces/UpkeepTranscoderInterfaceV2.sol"; +import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol"; import {KeeperRegistryBase2_1 as R21} from "./KeeperRegistryBase2_1.sol"; -import {IAutomationForwarder} from "./interfaces/IAutomationForwarder.sol"; -import {AutomationRegistryBaseInterface, UpkeepInfo} from "../../../automation/interfaces/2_0/AutomationRegistryInterface2_0.sol"; +import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol"; +import {AutomationRegistryBaseInterface, UpkeepInfo} from "../interfaces/2_0/AutomationRegistryInterface2_0.sol"; enum RegistryVersion { V12, diff --git a/contracts/src/v0.8/dev/automation/2_1/test/AutomationForwarder.t.sol b/contracts/src/v0.8/automation/2_1/test/AutomationForwarder.t.sol similarity index 87% rename from contracts/src/v0.8/dev/automation/2_1/test/AutomationForwarder.t.sol rename to contracts/src/v0.8/automation/2_1/test/AutomationForwarder.t.sol index d876def8bf0..ef0b829b73c 100644 --- a/contracts/src/v0.8/dev/automation/2_1/test/AutomationForwarder.t.sol +++ b/contracts/src/v0.8/automation/2_1/test/AutomationForwarder.t.sol @@ -1,16 +1,16 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; -import {IAutomationRegistryConsumer} from "../interfaces/IAutomationRegistryConsumer.sol"; -import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol"; +import {IAutomationRegistryConsumer} from "../../interfaces/IAutomationRegistryConsumer.sol"; +import {IAutomationForwarder} from "../../interfaces/IAutomationForwarder.sol"; import {AutomationForwarder} from "../AutomationForwarder.sol"; import {AutomationForwarderLogic} from "../AutomationForwarderLogic.sol"; -import {MockKeeperRegistry2_1} from "../mocks/MockKeeperRegistry2_1.sol"; -import {UpkeepCounter} from "../mocks/UpkeepCounter.sol"; +import {MockKeeperRegistry2_1} from "../../mocks/MockKeeperRegistry2_1.sol"; +import {UpkeepCounter} from "../../testhelpers/UpkeepCounter.sol"; import {BaseTest} from "./BaseTest.t.sol"; // in contracts directory, run -// forge test --match-path src/v0.8/dev/automation/2_1/test/AutomationForwarder.t.sol +// forge test --match-path src/v0.8/automation/2_1/test/AutomationForwarder.t.sol contract AutomationForwarderSetUp is BaseTest { IAutomationForwarder internal forwarder; diff --git a/contracts/src/v0.8/dev/automation/2_1/test/BaseTest.t.sol b/contracts/src/v0.8/automation/2_1/test/BaseTest.t.sol similarity index 86% rename from contracts/src/v0.8/dev/automation/2_1/test/BaseTest.t.sol rename to contracts/src/v0.8/automation/2_1/test/BaseTest.t.sol index 8f8e7587826..f5bc74286a4 100644 --- a/contracts/src/v0.8/dev/automation/2_1/test/BaseTest.t.sol +++ b/contracts/src/v0.8/automation/2_1/test/BaseTest.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; import {StructFactory} from "./StructFactory.sol"; diff --git a/contracts/src/v0.8/dev/automation/2_1/test/StructFactory.sol b/contracts/src/v0.8/automation/2_1/test/StructFactory.sol similarity index 77% rename from contracts/src/v0.8/dev/automation/2_1/test/StructFactory.sol rename to contracts/src/v0.8/automation/2_1/test/StructFactory.sol index b46c7797884..83bb9e89050 100644 --- a/contracts/src/v0.8/dev/automation/2_1/test/StructFactory.sol +++ b/contracts/src/v0.8/automation/2_1/test/StructFactory.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; contract StructFactory { diff --git a/contracts/src/v0.8/dev/automation/2_1/Chainable.sol b/contracts/src/v0.8/automation/Chainable.sol similarity index 100% rename from contracts/src/v0.8/dev/automation/2_1/Chainable.sol rename to contracts/src/v0.8/automation/Chainable.sol diff --git a/contracts/src/v0.8/dev/automation/2_1/interfaces/IKeeperRegistryMaster.sol b/contracts/src/v0.8/automation/interfaces/2_1/IKeeperRegistryMaster.sol similarity index 100% rename from contracts/src/v0.8/dev/automation/2_1/interfaces/IKeeperRegistryMaster.sol rename to contracts/src/v0.8/automation/interfaces/2_1/IKeeperRegistryMaster.sol diff --git a/contracts/src/v0.8/dev/automation/2_1/interfaces/IAutomationForwarder.sol b/contracts/src/v0.8/automation/interfaces/IAutomationForwarder.sol similarity index 85% rename from contracts/src/v0.8/dev/automation/2_1/interfaces/IAutomationForwarder.sol rename to contracts/src/v0.8/automation/interfaces/IAutomationForwarder.sol index fbf9743d0ca..0a53de697a1 100644 --- a/contracts/src/v0.8/dev/automation/2_1/interfaces/IAutomationForwarder.sol +++ b/contracts/src/v0.8/automation/interfaces/IAutomationForwarder.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {ITypeAndVersion} from "../../../../shared/interfaces/ITypeAndVersion.sol"; +import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; import {IAutomationRegistryConsumer} from "./IAutomationRegistryConsumer.sol"; interface IAutomationForwarder is ITypeAndVersion { diff --git a/contracts/src/v0.8/dev/automation/2_1/interfaces/IAutomationRegistryConsumer.sol b/contracts/src/v0.8/automation/interfaces/IAutomationRegistryConsumer.sol similarity index 100% rename from contracts/src/v0.8/dev/automation/2_1/interfaces/IAutomationRegistryConsumer.sol rename to contracts/src/v0.8/automation/interfaces/IAutomationRegistryConsumer.sol diff --git a/contracts/src/v0.8/dev/automation/2_1/interfaces/ILogAutomation.sol b/contracts/src/v0.8/automation/interfaces/ILogAutomation.sol similarity index 100% rename from contracts/src/v0.8/dev/automation/2_1/interfaces/ILogAutomation.sol rename to contracts/src/v0.8/automation/interfaces/ILogAutomation.sol diff --git a/contracts/src/v0.8/dev/automation/2_1/interfaces/StreamsLookupCompatibleInterface.sol b/contracts/src/v0.8/automation/interfaces/StreamsLookupCompatibleInterface.sol similarity index 100% rename from contracts/src/v0.8/dev/automation/2_1/interfaces/StreamsLookupCompatibleInterface.sol rename to contracts/src/v0.8/automation/interfaces/StreamsLookupCompatibleInterface.sol diff --git a/contracts/src/v0.8/dev/automation/2_1/mocks/MockKeeperRegistry2_1.sol b/contracts/src/v0.8/automation/mocks/MockKeeperRegistry2_1.sol similarity index 100% rename from contracts/src/v0.8/dev/automation/2_1/mocks/MockKeeperRegistry2_1.sol rename to contracts/src/v0.8/automation/mocks/MockKeeperRegistry2_1.sol diff --git a/contracts/src/v0.8/dev/automation/tests/DummyProtocol.sol b/contracts/src/v0.8/automation/testhelpers/DummyProtocol.sol similarity index 100% rename from contracts/src/v0.8/dev/automation/tests/DummyProtocol.sol rename to contracts/src/v0.8/automation/testhelpers/DummyProtocol.sol diff --git a/contracts/src/v0.8/dev/automation/tests/LogTriggeredStreamsLookup.sol b/contracts/src/v0.8/automation/testhelpers/LogTriggeredStreamsLookup.sol similarity index 94% rename from contracts/src/v0.8/dev/automation/tests/LogTriggeredStreamsLookup.sol rename to contracts/src/v0.8/automation/testhelpers/LogTriggeredStreamsLookup.sol index 5c542a9b07e..eb7f3c48f69 100644 --- a/contracts/src/v0.8/dev/automation/tests/LogTriggeredStreamsLookup.sol +++ b/contracts/src/v0.8/automation/testhelpers/LogTriggeredStreamsLookup.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.16; -import {ILogAutomation, Log} from "../2_1/interfaces/ILogAutomation.sol"; -import "../2_1/interfaces/StreamsLookupCompatibleInterface.sol"; -import {ArbSys} from "../../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; +import {ILogAutomation, Log} from "../interfaces/ILogAutomation.sol"; +import "../interfaces/StreamsLookupCompatibleInterface.sol"; +import {ArbSys} from "../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; interface IVerifierProxy { /** diff --git a/contracts/src/v0.8/dev/automation/tests/LogUpkeepCounter.sol b/contracts/src/v0.8/automation/testhelpers/LogUpkeepCounter.sol similarity index 97% rename from contracts/src/v0.8/dev/automation/tests/LogUpkeepCounter.sol rename to contracts/src/v0.8/automation/testhelpers/LogUpkeepCounter.sol index 84e53b65493..a51f2d2af1a 100644 --- a/contracts/src/v0.8/dev/automation/tests/LogUpkeepCounter.sol +++ b/contracts/src/v0.8/automation/testhelpers/LogUpkeepCounter.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.6; -import {ILogAutomation, Log} from "../2_1/interfaces/ILogAutomation.sol"; +import {ILogAutomation, Log} from "../interfaces/ILogAutomation.sol"; contract LogUpkeepCounter is ILogAutomation { bytes32 sig1 = 0x3d53a39550e04688065827f3bb86584cb007ab9ebca7ebd528e7301c9c31eb5d; diff --git a/contracts/src/v0.8/dev/automation/2_1/mocks/UpkeepCounter.sol b/contracts/src/v0.8/automation/testhelpers/UpkeepCounter.sol similarity index 100% rename from contracts/src/v0.8/dev/automation/2_1/mocks/UpkeepCounter.sol rename to contracts/src/v0.8/automation/testhelpers/UpkeepCounter.sol diff --git a/contracts/src/v0.8/dev/automation/upkeeps/LinkAvailableBalanceMonitor.sol b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol similarity index 96% rename from contracts/src/v0.8/dev/automation/upkeeps/LinkAvailableBalanceMonitor.sol rename to contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol index 1ed1237f615..af24d86e3c8 100644 --- a/contracts/src/v0.8/dev/automation/upkeeps/LinkAvailableBalanceMonitor.sol +++ b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol @@ -2,11 +2,11 @@ pragma solidity 0.8.6; -import "../../../shared/access/ConfirmedOwner.sol"; -import "../../../automation/interfaces/KeeperCompatibleInterface.sol"; -import "../../../vendor/openzeppelin-solidity/v4.7.0/contracts/security/Pausable.sol"; -import "../../../vendor/openzeppelin-solidity/v4.7.0/contracts/token/ERC20/IERC20.sol"; -import "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableMap.sol"; +import "../../shared/access/ConfirmedOwner.sol"; +import "../interfaces/KeeperCompatibleInterface.sol"; +import "../../vendor/openzeppelin-solidity/v4.7.0/contracts/security/Pausable.sol"; +import "../../vendor/openzeppelin-solidity/v4.7.0/contracts/token/ERC20/IERC20.sol"; +import "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableMap.sol"; interface IAggregatorProxy { function aggregator() external view returns (address); diff --git a/contracts/src/v0.8/dev/automation/CanaryUpkeep1_2.sol b/contracts/src/v0.8/dev/automation/CanaryUpkeep1_2.sol deleted file mode 100644 index bf711eb565f..00000000000 --- a/contracts/src/v0.8/dev/automation/CanaryUpkeep1_2.sol +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.6; - -import "../../automation/interfaces/KeeperCompatibleInterface.sol"; -import "../../automation/interfaces/1_2/KeeperRegistryInterface1_2.sol"; -import "../../shared/access/ConfirmedOwner.sol"; - -error NoKeeperNodes(); -error InsufficientInterval(); - -/** - * @notice A canary upkeep which requires a different keeper to service its upkeep at an interval. This makes sure that - * all keepers are in a healthy state. - */ -contract CanaryUpkeep1_2 is KeeperCompatibleInterface, ConfirmedOwner { - uint256 private s_keeperIndex; - uint256 private s_interval; - uint256 private s_timestamp; - KeeperRegistryExecutableInterface private immutable i_keeperRegistry; - - /** - * @param keeperRegistry address of a keeper registry - */ - constructor(KeeperRegistryExecutableInterface keeperRegistry, uint256 interval) ConfirmedOwner(msg.sender) { - i_keeperRegistry = keeperRegistry; - s_timestamp = block.timestamp; - s_interval = interval; - s_keeperIndex = 0; - } - - /** - * @return the current keeper index - */ - function getKeeperIndex() external view returns (uint256) { - return s_keeperIndex; - } - - /** - * @return the current timestamp - */ - function getTimestamp() external view returns (uint256) { - return s_timestamp; - } - - /** - * @return the current interval - */ - function getInterval() external view returns (uint256) { - return s_interval; - } - - /** - * @return the keeper registry - */ - function getKeeperRegistry() external view returns (KeeperRegistryExecutableInterface) { - return i_keeperRegistry; - } - - /** - * @notice updates the interval - * @param interval the new interval - */ - function setInterval(uint256 interval) external onlyOwner { - s_interval = interval; - } - - /** - * @notice returns true if keeper array is not empty and sufficient time has passed - */ - function checkUpkeep(bytes calldata /* checkData */) external view override returns (bool, bytes memory) { - bool upkeepNeeded = block.timestamp >= s_interval + s_timestamp; - return (upkeepNeeded, bytes("")); - } - - /** - * @notice checks keepers array limit, timestamp limit, and requires transaction origin must be the anticipated keeper. - * If all checks pass, update the keeper index and timestamp. Otherwise, revert this transaction. - */ - function performUpkeep(bytes calldata /* performData */) external override { - (State memory _s, Config memory _c, address[] memory keepers) = i_keeperRegistry.getState(); - if (keepers.length == 0) { - revert NoKeeperNodes(); - } - if (block.timestamp < s_interval + s_timestamp) { - revert InsufficientInterval(); - } - // if keepers array is shortened, this statement will make sure keeper index is always valid - if (s_keeperIndex >= keepers.length) { - s_keeperIndex = 0; - } - - require(tx.origin == keepers[s_keeperIndex], "transaction origin is not the anticipated keeper."); - s_keeperIndex = (s_keeperIndex + 1) % keepers.length; - s_timestamp = block.timestamp; - } -} diff --git a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsBilling.sol b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsBilling.sol index 8e8607078e5..c616f7355d2 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsBilling.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsBilling.sol @@ -10,17 +10,15 @@ import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; -/** - * @title Functions Billing contract - * @notice Contract that calculates payment from users to the nodes of the Decentralized Oracle Network (DON). - * @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. - */ +/// @title Functions Billing contract +/// @notice Contract that calculates payment from users to the nodes of the Decentralized Oracle Network (DON). +/// @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. abstract contract FunctionsBilling is Routable, IFunctionsBilling { using FunctionsResponse for FunctionsResponse.RequestMeta; using FunctionsResponse for FunctionsResponse.Commitment; using FunctionsResponse for FunctionsResponse.FulfillResult; - uint32 private constant REASONABLE_GAS_PRICE_CEILING = 1_000_000; + uint256 private constant REASONABLE_GAS_PRICE_CEILING = 1_000_000_000_000_000; // 1 million gwei // ================================================================ // | Request Commitment state | // ================================================================ @@ -34,15 +32,14 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { // ================================================================ struct Config { - uint32 maxCallbackGasLimit; // ══════════════════╗ Maximum amount of gas that can be given to a request's client callback + uint32 fulfillmentGasPriceOverEstimationBP; // ══╗ Percentage of gas price overestimation to account for changes in gas price between request and response. Held as basis points (one hundredth of 1 percentage point) uint32 feedStalenessSeconds; // ║ How long before we consider the feed price to be stale and fallback to fallbackNativePerUnitLink. uint32 gasOverheadBeforeCallback; // ║ Represents the average gas execution cost before the fulfillment callback. This amount is always billed for every request. uint32 gasOverheadAfterCallback; // ║ Represents the average gas execution cost after the fulfillment callback. This amount is always billed for every request. uint32 requestTimeoutSeconds; // ║ How many seconds it takes before we consider a request to be timed out uint72 donFee; // ║ Additional flat fee (in Juels of LINK) that will be split between Node Operators. Max value is 2^80 - 1 == 1.2m LINK. uint16 maxSupportedRequestDataVersion; // ═══════╝ The highest support request data version supported by the node. All lower versions should also be supported. - uint32 fulfillmentGasPriceOverEstimationBP; // ══╗ Percentage of gas price overestimation to account for changes in gas price between request and response. Held as basis points (one hundredth of 1 percentage point) - uint224 fallbackNativePerUnitLink; // ═══════════╝ fallback NATIVE CURRENCY / LINK conversion rate if the data feed is stale + uint224 fallbackNativePerUnitLink; // ═══════════╸ fallback NATIVE CURRENCY / LINK conversion rate if the data feed is stale } Config private s_config; @@ -83,14 +80,14 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { // | Configuration | // ================================================================ - // @notice Gets the Chainlink Coordinator's billing configuration - // @return config + /// @notice Gets the Chainlink Coordinator's billing configuration + /// @return config function getConfig() external view returns (Config memory) { return s_config; } - // @notice Sets the Chainlink Coordinator's billing configuration - // @param config - See the contents of the Config struct in IFunctionsBilling.Config for more information + /// @notice Sets the Chainlink Coordinator's billing configuration + /// @param config - See the contents of the Config struct in IFunctionsBilling.Config for more information function updateConfig(Config memory config) public { _onlyOwner(); @@ -102,17 +99,17 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { // | Fee Calculation | // ================================================================ - // @inheritdoc IFunctionsBilling + /// @inheritdoc IFunctionsBilling function getDONFee(bytes memory /* requestData */) public view override returns (uint72) { return s_config.donFee; } - // @inheritdoc IFunctionsBilling + /// @inheritdoc IFunctionsBilling function getAdminFee() public view override returns (uint72) { return _getRouter().getAdminFee(); } - // @inheritdoc IFunctionsBilling + /// @inheritdoc IFunctionsBilling function getWeiPerUnitLink() public view returns (uint256) { Config memory config = s_config; (, int256 weiPerUnitLink, , uint256 timestamp, ) = s_linkToNativeFeed.latestRoundData(); @@ -126,47 +123,47 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { return uint256(weiPerUnitLink); } - function _getJuelsPerGas(uint256 gasPriceGwei) private view returns (uint96) { + function _getJuelsPerGas(uint256 gasPriceWei) private view returns (uint96) { // (1e18 juels/link) * (wei/gas) / (wei/link) = juels per gas // There are only 1e9*1e18 = 1e27 juels in existence, should not exceed uint96 (2^96 ~ 7e28) - return SafeCast.toUint96((1e18 * gasPriceGwei) / getWeiPerUnitLink()); + return SafeCast.toUint96((1e18 * gasPriceWei) / getWeiPerUnitLink()); } // ================================================================ // | Cost Estimation | // ================================================================ - // @inheritdoc IFunctionsBilling + /// @inheritdoc IFunctionsBilling function estimateCost( uint64 subscriptionId, bytes calldata data, uint32 callbackGasLimit, - uint256 gasPriceGwei + uint256 gasPriceWei ) external view override returns (uint96) { _getRouter().isValidCallbackGasLimit(subscriptionId, callbackGasLimit); // Reasonable ceilings to prevent integer overflows - if (gasPriceGwei > REASONABLE_GAS_PRICE_CEILING) { + if (gasPriceWei > REASONABLE_GAS_PRICE_CEILING) { revert InvalidCalldata(); } uint72 adminFee = getAdminFee(); uint72 donFee = getDONFee(data); - return _calculateCostEstimate(callbackGasLimit, gasPriceGwei, donFee, adminFee); + return _calculateCostEstimate(callbackGasLimit, gasPriceWei, donFee, adminFee); } - // @notice Estimate the cost in Juels of LINK + /// @notice Estimate the cost in Juels of LINK // that will be charged to a subscription to fulfill a Functions request // Gas Price can be overestimated to account for flucuations between request and response time function _calculateCostEstimate( uint32 callbackGasLimit, - uint256 gasPriceGwei, + uint256 gasPriceWei, uint72 donFee, uint72 adminFee ) internal view returns (uint96) { uint256 executionGas = s_config.gasOverheadBeforeCallback + s_config.gasOverheadAfterCallback + callbackGasLimit; - uint256 gasPriceWithOverestimation = gasPriceGwei + - ((gasPriceGwei * s_config.fulfillmentGasPriceOverEstimationBP) / 10_000); - // @NOTE: Basis Points are 1/100th of 1%, divide by 10_000 to bring back to original units + uint256 gasPriceWithOverestimation = gasPriceWei + + ((gasPriceWei * s_config.fulfillmentGasPriceOverEstimationBP) / 10_000); + /// @NOTE: Basis Points are 1/100th of 1%, divide by 10_000 to bring back to original units uint96 juelsPerGas = _getJuelsPerGas(gasPriceWithOverestimation); uint256 estimatedGasReimbursement = juelsPerGas * executionGas; @@ -179,12 +176,10 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { // | Billing | // ================================================================ - // @notice Initiate the billing process for an Functions request - // @dev Only callable by the Functions Router - // @param data - Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - // @param requestDataVersion - Version number of the structure of the request data - // @param billing - Billing configuration for the request - // @return commitment - The parameters of the request that must be held consistent at response time + /// @notice Initiate the billing process for an Functions request + /// @dev Only callable by the Functions Router + /// @param request - Chainlink Functions request data, see FunctionsResponse.RequestMeta for the structure + /// @return commitment - The parameters of the request that must be held consistent at response time function _startBilling( FunctionsResponse.RequestMeta memory request ) internal returns (FunctionsResponse.Commitment memory commitment) { @@ -234,8 +229,8 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { return commitment; } - // @notice Generate a keccak hash request ID - // @dev uses the number of requests that the consumer of a subscription has sent as a nonce + /// @notice Generate a keccak hash request ID + /// @dev uses the number of requests that the consumer of a subscription has sent as a nonce function _computeRequestId( address don, address client, @@ -245,13 +240,13 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { return keccak256(abi.encode(don, client, subscriptionId, nonce)); } - // @notice Finalize billing process for an Functions request by sending a callback to the Client contract and then charging the subscription - // @param requestId identifier for the request that was generated by the Registry in the beginBilling commitment - // @param response response data from DON consensus - // @param err error from DON consensus - // @return result fulfillment result - // @dev Only callable by a node that has been approved on the Coordinator - // @dev simulated offchain to determine if sufficient balance is present to fulfill the request + /// @notice Finalize billing process for an Functions request by sending a callback to the Client contract and then charging the subscription + /// @param requestId identifier for the request that was generated by the Registry in the beginBilling commitment + /// @param response response data from DON consensus + /// @param err error from DON consensus + /// @return result fulfillment result + /// @dev Only callable by a node that has been approved on the Coordinator + /// @dev simulated offchain to determine if sufficient balance is present to fulfill the request function _fulfillAndBill( bytes32 requestId, bytes memory response, @@ -261,14 +256,14 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { ) internal returns (FunctionsResponse.FulfillResult) { FunctionsResponse.Commitment memory commitment = abi.decode(onchainMetadata, (FunctionsResponse.Commitment)); - if (s_requestCommitments[requestId] != keccak256(abi.encode(commitment))) { - return FunctionsResponse.FulfillResult.INVALID_COMMITMENT; - } - if (s_requestCommitments[requestId] == bytes32(0)) { return FunctionsResponse.FulfillResult.INVALID_REQUEST_ID; } + if (s_requestCommitments[requestId] != keccak256(abi.encode(commitment))) { + return FunctionsResponse.FulfillResult.INVALID_COMMITMENT; + } + uint96 juelsPerGas = _getJuelsPerGas(tx.gasprice); // Gas overhead without callback uint96 gasOverheadJuels = juelsPerGas * @@ -306,25 +301,20 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { // | Request Timeout | // ================================================================ - // @inheritdoc IFunctionsBilling - // @dev Only callable by the Router - // @dev Used by FunctionsRouter.sol during timeout of a request - function deleteCommitment(bytes32 requestId) external override onlyRouter returns (bool) { - // Ensure that commitment exists - if (s_requestCommitments[requestId] == bytes32(0)) { - return false; - } + /// @inheritdoc IFunctionsBilling + /// @dev Only callable by the Router + /// @dev Used by FunctionsRouter.sol during timeout of a request + function deleteCommitment(bytes32 requestId) external override onlyRouter { // Delete commitment delete s_requestCommitments[requestId]; emit CommitmentDeleted(requestId); - return true; } // ================================================================ // | Fund withdrawal | // ================================================================ - // @inheritdoc IFunctionsBilling + /// @inheritdoc IFunctionsBilling function oracleWithdraw(address recipient, uint96 amount) external { _disperseFeePool(); @@ -337,8 +327,8 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { IFunctionsSubscriptions(address(_getRouter())).oracleWithdraw(recipient, amount); } - // @inheritdoc IFunctionsBilling - // @dev Only callable by the Coordinator owner + /// @inheritdoc IFunctionsBilling + /// @dev Only callable by the Coordinator owner function oracleWithdrawAll() external { _onlyOwner(); _disperseFeePool(); @@ -348,8 +338,10 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { // Bounded by "maxNumOracles" on OCR2Abstract.sol for (uint256 i = 0; i < transmitters.length; ++i) { uint96 balance = s_withdrawableTokens[transmitters[i]]; - s_withdrawableTokens[transmitters[i]] = 0; - IFunctionsSubscriptions(address(_getRouter())).oracleWithdraw(transmitters[i], balance); + if (balance > 0) { + s_withdrawableTokens[transmitters[i]] = 0; + IFunctionsSubscriptions(address(_getRouter())).oracleWithdraw(transmitters[i], balance); + } } } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsClient.sol b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsClient.sol index b7f676c2327..ecbbbd928fe 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsClient.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsClient.sol @@ -6,8 +6,8 @@ import {IFunctionsClient} from "./interfaces/IFunctionsClient.sol"; import {FunctionsRequest} from "./libraries/FunctionsRequest.sol"; -// @title The Chainlink Functions client contract -// @notice Contract developers can inherit this contract in order to make Chainlink Functions requests +/// @title The Chainlink Functions client contract +/// @notice Contract developers can inherit this contract in order to make Chainlink Functions requests abstract contract FunctionsClient is IFunctionsClient { using FunctionsRequest for FunctionsRequest.Request; @@ -22,11 +22,11 @@ abstract contract FunctionsClient is IFunctionsClient { i_router = IFunctionsRouter(router); } - // @notice Sends a Chainlink Functions request - // @param data The CBOR encoded bytes data for a Functions request - // @param subscriptionId The subscription ID that will be charged to service the request - // @param callbackGasLimit the amount of gas that will be available for the fulfillment callback - // @return requestId The generated request ID for this request + /// @notice Sends a Chainlink Functions request + /// @param data The CBOR encoded bytes data for a Functions request + /// @param subscriptionId The subscription ID that will be charged to service the request + /// @param callbackGasLimit the amount of gas that will be available for the fulfillment callback + /// @return requestId The generated request ID for this request function _sendRequest( bytes memory data, uint64 subscriptionId, @@ -44,18 +44,19 @@ abstract contract FunctionsClient is IFunctionsClient { return requestId; } - // @notice User defined function to handle a response from the DON - // @param requestId The request ID, returned by sendRequest() - // @param response Aggregated response from the execution of the user's source code - // @param err Aggregated error from the execution of the user code or from the execution pipeline - // @dev Either response or error parameter will be set, but never both + /// @notice User defined function to handle a response from the DON + /// @param requestId The request ID, returned by sendRequest() + /// @param response Aggregated response from the execution of the user's source code + /// @param err Aggregated error from the execution of the user code or from the execution pipeline + /// @dev Either response or error parameter will be set, but never both function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal virtual; - // @inheritdoc IFunctionsClient + /// @inheritdoc IFunctionsClient function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external override { if (msg.sender != address(i_router)) { revert OnlyRouterCanFulfill(); } fulfillRequest(requestId, response, err); + emit RequestFulfilled(requestId); } } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsCoordinator.sol b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsCoordinator.sol index aa7b1d5c7e1..540b382d652 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsCoordinator.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsCoordinator.sol @@ -9,15 +9,15 @@ import {FunctionsBilling} from "./FunctionsBilling.sol"; import {OCR2Base} from "./ocr/OCR2Base.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; -// @title Functions Coordinator contract -// @notice Contract that nodes of a Decentralized Oracle Network (DON) interact with -// @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. +/// @title Functions Coordinator contract +/// @notice Contract that nodes of a Decentralized Oracle Network (DON) interact with +/// @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilling { using FunctionsResponse for FunctionsResponse.RequestMeta; using FunctionsResponse for FunctionsResponse.Commitment; using FunctionsResponse for FunctionsResponse.FulfillResult; - // @inheritdoc ITypeAndVersion + /// @inheritdoc ITypeAndVersion string public constant override typeAndVersion = "Functions Coordinator v1.0.0"; event OracleRequest( @@ -47,7 +47,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli address linkToNativeFeed ) OCR2Base(true) FunctionsBilling(router, config, linkToNativeFeed) {} - // @inheritdoc IFunctionsCoordinator + /// @inheritdoc IFunctionsCoordinator function getThresholdPublicKey() external view override returns (bytes memory) { if (s_thresholdPublicKey.length == 0) { revert EmptyPublicKey(); @@ -55,7 +55,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli return s_thresholdPublicKey; } - // @inheritdoc IFunctionsCoordinator + /// @inheritdoc IFunctionsCoordinator function setThresholdPublicKey(bytes calldata thresholdPublicKey) external override onlyOwner { if (thresholdPublicKey.length == 0) { revert EmptyPublicKey(); @@ -63,7 +63,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli s_thresholdPublicKey = thresholdPublicKey; } - // @inheritdoc IFunctionsCoordinator + /// @inheritdoc IFunctionsCoordinator function getDONPublicKey() external view override returns (bytes memory) { if (s_donPublicKey.length == 0) { revert EmptyPublicKey(); @@ -71,7 +71,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli return s_donPublicKey; } - // @inheritdoc IFunctionsCoordinator + /// @inheritdoc IFunctionsCoordinator function setDONPublicKey(bytes calldata donPublicKey) external override onlyOwner { if (donPublicKey.length == 0) { revert EmptyPublicKey(); @@ -79,7 +79,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli s_donPublicKey = donPublicKey; } - // @dev check if node is in current transmitter list + /// @dev check if node is in current transmitter list function _isTransmitter(address node) internal view returns (bool) { address[] memory nodes = s_transmitters; // Bounded by "maxNumOracles" on OCR2Abstract.sol @@ -91,7 +91,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli return false; } - // @inheritdoc IFunctionsCoordinator + /// @inheritdoc IFunctionsCoordinator function startRequest( FunctionsResponse.RequestMeta calldata request ) external override onlyRouter returns (FunctionsResponse.Commitment memory commitment) { @@ -113,19 +113,19 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli return commitment; } - // DON fees are pooled together. If the OCR configuration is going to change, these need to be distributed. + /// @dev DON fees are pooled together. If the OCR configuration is going to change, these need to be distributed. function _beforeSetConfig(uint8 /* _f */, bytes memory /* _onchainConfig */) internal override { if (_getTransmitters().length > 0) { _disperseFeePool(); } } - // Used by FunctionsBilling.sol + /// @dev Used by FunctionsBilling.sol function _getTransmitters() internal view override returns (address[] memory) { return s_transmitters; } - // Report hook called within OCR2Base.sol + /// @dev Report hook called within OCR2Base.sol function _report( uint256 /*initialGas*/, address /*transmitter*/, @@ -171,7 +171,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli } } - // Used in FunctionsBilling.sol + /// @dev Used in FunctionsBilling.sol function _onlyOwner() internal view override { _validateOwnership(); } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsRouter.sol b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsRouter.sol index 46f6929fabc..41cd90341f3 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsRouter.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsRouter.sol @@ -62,6 +62,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, error SenderMustAcceptTermsOfService(address sender); error InvalidGasFlagValue(uint8 value); error GasLimitTooBig(uint32 limit); + error DuplicateRequestId(bytes32 requestId); struct CallbackResult { bool success; // ══════╸ Whether the callback succeeded or not @@ -84,11 +85,13 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, // | Configuration state | // ================================================================ struct Config { - uint16 maxConsumersPerSubscription; // ══════╗ Maximum number of consumers which can be added to a single subscription. This bound ensures we are able to loop over all subscription consumers as needed, without exceeding gas limits. Should a user require more consumers, they can use multiple subscriptions. - uint72 adminFee; // ║ Flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network - bytes4 handleOracleFulfillmentSelector; // ║ The function selector that is used when calling back to the Client contract - uint16 gasForCallExactCheck; // ═════════════╝ Used during calling back to the client. Ensures we have at least enough gas to be able to revert if gasAmount > 63//64*gas available. - uint32[] maxCallbackGasLimits; // ═══════════╸ List of max callback gas limits used by flag with GAS_FLAG_INDEX + uint16 maxConsumersPerSubscription; // ═════════╗ Maximum number of consumers which can be added to a single subscription. This bound ensures we are able to loop over all subscription consumers as needed, without exceeding gas limits. Should a user require more consumers, they can use multiple subscriptions. + uint72 adminFee; // ║ Flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network + bytes4 handleOracleFulfillmentSelector; // ║ The function selector that is used when calling back to the Client contract + uint16 gasForCallExactCheck; // ════════════════╝ Used during calling back to the client. Ensures we have at least enough gas to be able to revert if gasAmount > 63//64*gas available. + uint32[] maxCallbackGasLimits; // ══════════════╸ List of max callback gas limits used by flag with GAS_FLAG_INDEX + uint16 subscriptionDepositMinimumRequests; //═══╗ Amount of requests that must be completed before the full subscription balance will be released when closing a subscription account. + uint72 subscriptionDepositJuels; // ════════════╝ Amount of subscription funds that are held as a deposit until Config.subscriptionDepositMinimumRequests are made using the subscription. } Config private s_config; @@ -134,20 +137,20 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, // | Configuration | // ================================================================ - // @notice The identifier of the route to retrieve the address of the access control contract + /// @notice The identifier of the route to retrieve the address of the access control contract // The access control contract controls which accounts can manage subscriptions - // @return id - bytes32 id that can be passed to the "getContractById" of the Router + /// @return id - bytes32 id that can be passed to the "getContractById" of the Router function getConfig() external view returns (Config memory) { return s_config; } - // @notice The router configuration + /// @notice The router configuration function updateConfig(Config memory config) public onlyOwner { s_config = config; emit ConfigUpdated(config); } - // @inheritdoc IFunctionsRouter + /// @inheritdoc IFunctionsRouter function isValidCallbackGasLimit(uint64 subscriptionId, uint32 callbackGasLimit) public view { uint8 callbackGasLimitsIndexSelector = uint8(getFlags(subscriptionId)[MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX]); if (callbackGasLimitsIndexSelector >= s_config.maxCallbackGasLimits.length) { @@ -159,31 +162,36 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, } } - // @inheritdoc IFunctionsRouter + /// @inheritdoc IFunctionsRouter function getAdminFee() external view override returns (uint72) { return s_config.adminFee; } - // @inheritdoc IFunctionsRouter + /// @inheritdoc IFunctionsRouter function getAllowListId() external view override returns (bytes32) { return s_allowListId; } - // @inheritdoc IFunctionsRouter + /// @inheritdoc IFunctionsRouter function setAllowListId(bytes32 allowListId) external override onlyOwner { s_allowListId = allowListId; } - // Used within FunctionsSubscriptions.sol + /// @dev Used within FunctionsSubscriptions.sol function _getMaxConsumers() internal view override returns (uint16) { return s_config.maxConsumersPerSubscription; } + /// @dev Used within FunctionsSubscriptions.sol + function _getSubscriptionDepositDetails() internal view override returns (uint16, uint72) { + return (s_config.subscriptionDepositMinimumRequests, s_config.subscriptionDepositJuels); + } + // ================================================================ // | Requests | // ================================================================ - // @inheritdoc IFunctionsRouter + /// @inheritdoc IFunctionsRouter function sendRequest( uint64 subscriptionId, bytes calldata data, @@ -195,7 +203,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, return _sendRequest(donId, coordinator, subscriptionId, data, dataVersion, callbackGasLimit); } - // @inheritdoc IFunctionsRouter + /// @inheritdoc IFunctionsRouter function sendRequestToProposed( uint64 subscriptionId, bytes calldata data, @@ -226,6 +234,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, Subscription memory subscription = getSubscription(subscriptionId); Consumer memory consumer = getConsumer(msg.sender, subscriptionId); + uint72 adminFee = s_config.adminFee; // Forward request to DON FunctionsResponse.Commitment memory commitment = coordinator.startRequest( @@ -236,7 +245,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, dataVersion: dataVersion, flags: getFlags(subscriptionId), callbackGasLimit: callbackGasLimit, - adminFee: s_config.adminFee, + adminFee: adminFee, initiatedRequests: consumer.initiatedRequests, completedRequests: consumer.completedRequests, availableBalance: subscription.balance - subscription.blockedBalance, @@ -244,11 +253,16 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, }) ); + // Do not allow setting a comittment for a requestId that already exists + if (s_requestCommitments[commitment.requestId] != bytes32(0)) { + revert DuplicateRequestId(commitment.requestId); + } + // Store a commitment about the request s_requestCommitments[commitment.requestId] = keccak256( abi.encode( FunctionsResponse.Commitment({ - adminFee: s_config.adminFee, + adminFee: adminFee, coordinator: address(coordinator), client: msg.sender, subscriptionId: subscriptionId, @@ -285,7 +299,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, // | Responses | // ================================================================ - // @inheritdoc IFunctionsRouter + /// @inheritdoc IFunctionsRouter function fulfill( bytes memory response, bytes memory err, @@ -300,23 +314,27 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, revert OnlyCallableFromCoordinator(); } - if (s_requestCommitments[commitment.requestId] == bytes32(0)) { - resultCode = FunctionsResponse.FulfillResult.INVALID_REQUEST_ID; - emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); - return (resultCode, 0); - } + { + bytes32 commitmentHash = s_requestCommitments[commitment.requestId]; - if (keccak256(abi.encode(commitment)) != s_requestCommitments[commitment.requestId]) { - resultCode = FunctionsResponse.FulfillResult.INVALID_COMMITMENT; - emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); - return (resultCode, 0); - } + if (commitmentHash == bytes32(0)) { + resultCode = FunctionsResponse.FulfillResult.INVALID_REQUEST_ID; + emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); + return (resultCode, 0); + } + + if (keccak256(abi.encode(commitment)) != commitmentHash) { + resultCode = FunctionsResponse.FulfillResult.INVALID_COMMITMENT; + emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); + return (resultCode, 0); + } - // Check that the transmitter has supplied enough gas for the callback to succeed - if (gasleft() < commitment.callbackGasLimit + commitment.gasOverheadAfterCallback) { - resultCode = FunctionsResponse.FulfillResult.INSUFFICIENT_GAS_PROVIDED; - emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); - return (resultCode, 0); + // Check that the transmitter has supplied enough gas for the callback to succeed + if (gasleft() < commitment.callbackGasLimit + commitment.gasOverheadAfterCallback) { + resultCode = FunctionsResponse.FulfillResult.INSUFFICIENT_GAS_PROVIDED; + emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); + return (resultCode, 0); + } } { @@ -383,6 +401,18 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, uint32 callbackGasLimit, address client ) private returns (CallbackResult memory) { + bool destinationNoLongerExists; + // solhint-disable-next-line no-inline-assembly + assembly { + // solidity calls check that a contract actually exists at the destination, so we do the same + destinationNoLongerExists := iszero(extcodesize(client)) + } + if (destinationNoLongerExists) { + // Return without attempting callback + // The subscription will still be charged to reimburse transmitter's gas overhead + return CallbackResult({success: false, gasUsed: 0, returnData: new bytes(0)}); + } + bytes memory encodedCallback = abi.encodeWithSelector( s_config.handleOracleFulfillmentSelector, requestId, @@ -404,13 +434,6 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, // solhint-disable-next-line no-inline-assembly assembly { - // solidity calls check that a contract actually exists at the destination, so we do the same - // Note we do this check prior to measuring gas so gasForCallExactCheck (our "cushion") - // doesn't need to account for it. - if iszero(extcodesize(client)) { - revert(0, 0) - } - let g := gas() // Compute g -= gasForCallExactCheck and check for underflow // The gas actually passed to the callee is _min(gasAmount, 63//64*gas available). @@ -451,7 +474,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, // | Route methods | // ================================================================ - // @inheritdoc IRouterBase + /// @inheritdoc IFunctionsRouter function getContractById(bytes32 id) public view override returns (address) { address currentImplementation = s_route[id]; if (currentImplementation == address(0)) { @@ -460,7 +483,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, return currentImplementation; } - // @inheritdoc IRouterBase + /// @inheritdoc IFunctionsRouter function getProposedContractById(bytes32 id) public view override returns (address) { // Iterations will not exceed MAX_PROPOSAL_SET_LENGTH for (uint8 i = 0; i < s_proposedContractSet.ids.length; ++i) { @@ -475,12 +498,12 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, // | Contract Proposal methods | // ================================================================ - // @inheritdoc IRouterBase + /// @inheritdoc IFunctionsRouter function getProposedContractSet() external view override returns (bytes32[] memory, address[] memory) { return (s_proposedContractSet.ids, s_proposedContractSet.to); } - // @inheritdoc IRouterBase + /// @inheritdoc IFunctionsRouter function proposeContractsUpdate( bytes32[] memory proposedContractSetIds, address[] memory proposedContractSetAddresses @@ -501,21 +524,18 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, ) { revert InvalidProposal(); } - } - - s_proposedContractSet = ContractProposalSet({ids: proposedContractSetIds, to: proposedContractSetAddresses}); - // NOTE: iterations of this loop will not exceed MAX_PROPOSAL_SET_LENGTH - for (uint256 i = 0; i < proposedContractSetIds.length; ++i) { emit ContractProposed({ - proposedContractSetId: proposedContractSetIds[i], - proposedContractSetFromAddress: s_route[proposedContractSetIds[i]], - proposedContractSetToAddress: proposedContractSetAddresses[i] + proposedContractSetId: id, + proposedContractSetFromAddress: s_route[id], + proposedContractSetToAddress: proposedContract }); } + + s_proposedContractSet = ContractProposalSet({ids: proposedContractSetIds, to: proposedContractSetAddresses}); } - // @inheritdoc IRouterBase + /// @inheritdoc IFunctionsRouter function updateContracts() external override onlyOwner { // Iterations will not exceed MAX_PROPOSAL_SET_LENGTH for (uint256 i = 0; i < s_proposedContractSet.ids.length; ++i) { @@ -533,17 +553,17 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, // ================================================================ // Favoring internal functions over actual modifiers to reduce contract size - // Used within FunctionsSubscriptions.sol + /// @dev Used within FunctionsSubscriptions.sol function _whenNotPaused() internal view override { _requireNotPaused(); } - // Used within FunctionsSubscriptions.sol + /// @dev Used within FunctionsSubscriptions.sol function _onlyRouterOwner() internal view override { _validateOwnership(); } - // Used within FunctionsSubscriptions.sol + /// @dev Used within FunctionsSubscriptions.sol function _onlySenderThatAcceptedToS() internal view override { address currentImplementation = s_route[s_allowListId]; if (currentImplementation == address(0)) { @@ -555,12 +575,12 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, } } - // @inheritdoc IRouterBase + /// @inheritdoc IFunctionsRouter function pause() external override onlyOwner { _pause(); } - // @inheritdoc IRouterBase + /// @inheritdoc IFunctionsRouter function unpause() external override onlyOwner { _unpause(); } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsSubscriptions.sol b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsSubscriptions.sol index cabe8b0d284..864225fd38c 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsSubscriptions.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsSubscriptions.sol @@ -13,9 +13,9 @@ import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/tok import {SafeERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; -// @title Functions Subscriptions contract -// @notice Contract that coordinates payment from users to the nodes of the Decentralized Oracle Network (DON). -// @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. +/// @title Functions Subscriptions contract +/// @notice Contract that coordinates payment from users to the nodes of the Decentralized Oracle Network (DON). +/// @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Receiver { using SafeERC20 for IERC20; using FunctionsResponse for FunctionsResponse.Commitment; @@ -24,7 +24,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // | Balance state | // ================================================================ // link token address - address internal immutable i_linkToken; + IERC20 internal immutable i_linkToken; // s_totalLinkBalance tracks the total LINK sent to/from // this contract through onTokenTransfer, cancelSubscription and oracleWithdraw. @@ -32,7 +32,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // sent tokens using transfer and so we may need to use recoverFunds. uint96 private s_totalLinkBalance; - // @dev NOP balances are held as a single amount. The breakdown is held by the Coordinator. + /// @dev NOP balances are held as a single amount. The breakdown is held by the Coordinator. mapping(address coordinator => uint96 balanceJuelsLink) private s_withdrawableTokens; // ================================================================ @@ -42,7 +42,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // loop through all the current subscriptions via .getSubscription(). uint64 private s_currentSubscriptionId; - mapping(uint64 subscriptionId => IFunctionsSubscriptions.Subscription) private s_subscriptions; + mapping(uint64 subscriptionId => Subscription) private s_subscriptions; // Maintains the list of keys in s_consumers. // We do this for 2 reasons: @@ -50,7 +50,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // 2. To be able to return the list of all consumers in getSubscription. // Note that we need the s_consumers map to be able to directly check if a // consumer is valid without reading all the consumers from storage. - mapping(address consumer => mapping(uint64 subscriptionId => IFunctionsSubscriptions.Consumer)) private s_consumers; + mapping(address consumer => mapping(uint64 subscriptionId => Consumer)) private s_consumers; event SubscriptionCreated(uint64 indexed subscriptionId, address owner); event SubscriptionFunded(uint64 indexed subscriptionId, uint256 oldBalance, uint256 newBalance); @@ -70,7 +70,6 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece error MustBeSubscriptionOwner(); error TimeoutNotExceeded(); error MustBeProposedOwner(address proposedOwner); - error TotalBalanceInvariantViolated(uint256 totalBalance, uint256 deductionAttempt); // Should never happen event FundsRecovered(address to, uint256 amount); // ================================================================ @@ -90,15 +89,15 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // | Initialization | // ================================================================ constructor(address link) { - i_linkToken = link; + i_linkToken = IERC20(link); } // ================================================================ // | Request/Response | // ================================================================ - // @notice Sets a request as in-flight - // @dev Only callable within the Router + /// @notice Sets a request as in-flight + /// @dev Only callable within the Router function _markRequestInFlight(address client, uint64 subscriptionId, uint96 estimatedTotalCostJuels) internal { // Earmark subscription funds s_subscriptions[subscriptionId].blockedBalance += estimatedTotalCostJuels; @@ -107,8 +106,8 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece s_consumers[client][subscriptionId].initiatedRequests += 1; } - // @notice Moves funds from one subscription account to another. - // @dev Only callable by the Coordinator contract that is saved in the request commitment + /// @notice Moves funds from one subscription account to another. + /// @dev Only callable by the Coordinator contract that is saved in the request commitment function _pay( uint64 subscriptionId, uint96 estimatedTotalCostJuels, @@ -121,16 +120,17 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece uint96 callbackGasCostJuels = juelsPerGas * gasUsed; uint96 totalCostJuels = costWithoutCallbackJuels + adminFee + callbackGasCostJuels; - // Charge the subscription - if (s_subscriptions[subscriptionId].balance < totalCostJuels) { + if ( + s_subscriptions[subscriptionId].balance < totalCostJuels || + s_subscriptions[subscriptionId].blockedBalance < estimatedTotalCostJuels + ) { revert InsufficientBalance(s_subscriptions[subscriptionId].balance); } + + // Charge the subscription s_subscriptions[subscriptionId].balance -= totalCostJuels; // Unblock earmarked funds - if (s_subscriptions[subscriptionId].blockedBalance < estimatedTotalCostJuels) { - revert InsufficientBalance(s_subscriptions[subscriptionId].balance); - } s_subscriptions[subscriptionId].blockedBalance -= estimatedTotalCostJuels; // Pay the DON's fees and gas reimbursement @@ -149,21 +149,21 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // | Owner methods | // ================================================================ - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function ownerCancelSubscription(uint64 subscriptionId) external override { _onlyRouterOwner(); _isExistingSubscription(subscriptionId); - _cancelSubscriptionHelper(subscriptionId, s_subscriptions[subscriptionId].owner); + _cancelSubscriptionHelper(subscriptionId, s_subscriptions[subscriptionId].owner, false); } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function recoverFunds(address to) external override { _onlyRouterOwner(); - uint256 externalBalance = IERC20(i_linkToken).balanceOf(address(this)); + uint256 externalBalance = i_linkToken.balanceOf(address(this)); uint256 internalBalance = uint256(s_totalLinkBalance); if (internalBalance < externalBalance) { uint256 amount = externalBalance - internalBalance; - IERC20(i_linkToken).safeTransfer(to, amount); + i_linkToken.safeTransfer(to, amount); emit FundsRecovered(to, amount); } // If the balances are equal, nothing to be done. @@ -173,7 +173,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // | Fund withdrawal | // ================================================================ - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function oracleWithdraw(address recipient, uint96 amount) external override { _whenNotPaused(); @@ -184,18 +184,15 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece if (currentBalance < amount) { revert InsufficientBalance(currentBalance); } - if (s_totalLinkBalance < amount) { - revert TotalBalanceInvariantViolated(s_totalLinkBalance, amount); - } s_withdrawableTokens[msg.sender] -= amount; s_totalLinkBalance -= amount; - IERC20(i_linkToken).safeTransfer(recipient, amount); + i_linkToken.safeTransfer(recipient, amount); } - // @notice Owner withdraw LINK earned through admin fees - // @notice If amount is 0 the full balance will be withdrawn - // @param recipient where to send the funds - // @param amount amount to withdraw + /// @notice Owner withdraw LINK earned through admin fees + /// @notice If amount is 0 the full balance will be withdrawn + /// @param recipient where to send the funds + /// @param amount amount to withdraw function ownerWithdraw(address recipient, uint96 amount) external { _onlyRouterOwner(); if (amount == 0) { @@ -205,13 +202,10 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece if (currentBalance < amount) { revert InsufficientBalance(currentBalance); } - if (s_totalLinkBalance < amount) { - revert TotalBalanceInvariantViolated(s_totalLinkBalance, amount); - } s_withdrawableTokens[address(this)] -= amount; s_totalLinkBalance -= amount; - IERC20(i_linkToken).safeTransfer(recipient, amount); + i_linkToken.safeTransfer(recipient, amount); } // ================================================================ @@ -219,11 +213,11 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // ================================================================ // This function is to be invoked when using LINK.transferAndCall - // @dev Note to fund the subscription, use transferAndCall. For example - // @dev LINKTOKEN.transferAndCall( - // @dev address(ROUTER), - // @dev amount, - // @dev abi.encode(subscriptionId)); + /// @dev Note to fund the subscription, use transferAndCall. For example + /// @dev LINKTOKEN.transferAndCall( + /// @dev address(ROUTER), + /// @dev amount, + /// @dev abi.encode(subscriptionId)); function onTokenTransfer(address /* sender */, uint256 amount, bytes calldata data) external override { _whenNotPaused(); if (msg.sender != address(i_linkToken)) { @@ -248,42 +242,63 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // | Subscription management | // ================================================================ - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function getTotalBalance() external view override returns (uint96) { return s_totalLinkBalance; } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function getSubscriptionCount() external view override returns (uint64) { return s_currentSubscriptionId; } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function getSubscription(uint64 subscriptionId) public view override returns (Subscription memory) { _isExistingSubscription(subscriptionId); return s_subscriptions[subscriptionId]; } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions + function getSubscriptionsInRange( + uint64 subscriptionIdStart, + uint64 subscriptionIdEnd + ) external view override returns (Subscription[] memory subscriptions) { + if ( + subscriptionIdStart > subscriptionIdEnd || + subscriptionIdEnd > s_currentSubscriptionId || + s_currentSubscriptionId == 0 + ) { + revert InvalidCalldata(); + } + + subscriptions = new Subscription[]((subscriptionIdEnd - subscriptionIdStart) + 1); + for (uint256 i = 0; i <= subscriptionIdEnd - subscriptionIdStart; ++i) { + subscriptions[i] = s_subscriptions[uint64(subscriptionIdStart + i)]; + } + + return subscriptions; + } + + /// @inheritdoc IFunctionsSubscriptions function getConsumer(address client, uint64 subscriptionId) public view override returns (Consumer memory) { return s_consumers[client][subscriptionId]; } - // Used within this file & FunctionsRouter.sol + /// @dev Used within this file & FunctionsRouter.sol function _isExistingSubscription(uint64 subscriptionId) internal view { if (s_subscriptions[subscriptionId].owner == address(0)) { revert InvalidSubscription(); } } - // Used within FunctionsRouter.sol + /// @dev Used within FunctionsRouter.sol function _isAllowedConsumer(address client, uint64 subscriptionId) internal view { if (!s_consumers[client][subscriptionId].allowed) { revert InvalidConsumer(); } } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function createSubscription() external override returns (uint64 subscriptionId) { _whenNotPaused(); _onlySenderThatAcceptedToS(); @@ -303,7 +318,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece return subscriptionId; } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function createSubscriptionWithConsumer(address consumer) external override returns (uint64 subscriptionId) { _whenNotPaused(); _onlySenderThatAcceptedToS(); @@ -327,7 +342,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece return subscriptionId; } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function proposeSubscriptionOwnerTransfer(uint64 subscriptionId, address newOwner) external override { _whenNotPaused(); _onlySubscriptionOwner(subscriptionId); @@ -341,7 +356,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece emit SubscriptionOwnerTransferRequested(subscriptionId, msg.sender, newOwner); } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function acceptSubscriptionOwnerTransfer(uint64 subscriptionId) external override { _whenNotPaused(); _onlySenderThatAcceptedToS(); @@ -356,16 +371,14 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece emit SubscriptionOwnerTransferred(subscriptionId, previousOwner, msg.sender); } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function removeConsumer(uint64 subscriptionId, address consumer) external override { _whenNotPaused(); _onlySubscriptionOwner(subscriptionId); _onlySenderThatAcceptedToS(); Consumer memory consumerData = s_consumers[consumer][subscriptionId]; - if (!consumerData.allowed) { - revert InvalidConsumer(); - } + _isAllowedConsumer(consumer, subscriptionId); if (consumerData.initiatedRequests != consumerData.completedRequests) { revert CannotRemoveWithPendingRequests(); } @@ -384,10 +397,10 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece emit SubscriptionConsumerRemoved(subscriptionId, consumer); } - // overriden in FunctionsRouter.sol + /// @dev Overriden in FunctionsRouter.sol function _getMaxConsumers() internal view virtual returns (uint16); - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function addConsumer(uint64 subscriptionId, address consumer) external override { _whenNotPaused(); _onlySubscriptionOwner(subscriptionId); @@ -395,7 +408,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // Already maxed, cannot add any more consumers. uint16 maximumConsumers = _getMaxConsumers(); - if (s_subscriptions[subscriptionId].consumers.length == maximumConsumers) { + if (s_subscriptions[subscriptionId].consumers.length >= maximumConsumers) { revert TooManyConsumers(maximumConsumers); } if (s_consumers[consumer][subscriptionId].allowed) { @@ -410,36 +423,55 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece emit SubscriptionConsumerAdded(subscriptionId, consumer); } - // @inheritdoc IFunctionsSubscriptions - function cancelSubscription(uint64 subscriptionId, address to) external override { - _whenNotPaused(); - _onlySubscriptionOwner(subscriptionId); - _onlySenderThatAcceptedToS(); - - if (pendingRequestExists(subscriptionId)) { - revert CannotRemoveWithPendingRequests(); - } + /// @dev Overriden in FunctionsRouter.sol + function _getSubscriptionDepositDetails() internal virtual returns (uint16, uint72); - _cancelSubscriptionHelper(subscriptionId, to); - } - - function _cancelSubscriptionHelper(uint64 subscriptionId, address to) private { + function _cancelSubscriptionHelper(uint64 subscriptionId, address toAddress, bool checkDepositRefundability) private { Subscription memory subscription = s_subscriptions[subscriptionId]; uint96 balance = subscription.balance; + uint64 completedRequests = 0; + // NOTE: loop iterations are bounded by config.maxConsumers // If no consumers, does nothing. for (uint256 i = 0; i < subscription.consumers.length; ++i) { - delete s_consumers[subscription.consumers[i]][subscriptionId]; + address consumer = subscription.consumers[i]; + completedRequests += s_consumers[consumer][subscriptionId].completedRequests; + delete s_consumers[consumer][subscriptionId]; } delete s_subscriptions[subscriptionId]; - s_totalLinkBalance -= balance; - IERC20(i_linkToken).safeTransfer(to, uint256(balance)); + (uint16 subscriptionDepositMinimumRequests, uint72 subscriptionDepositJuels) = _getSubscriptionDepositDetails(); + + // If subscription has not made enough requests, deposit will be forfeited + if (checkDepositRefundability && completedRequests < subscriptionDepositMinimumRequests) { + uint96 deposit = subscriptionDepositJuels > balance ? balance : subscriptionDepositJuels; + if (deposit > 0) { + s_withdrawableTokens[address(this)] += deposit; + balance -= deposit; + } + } + + if (balance > 0) { + s_totalLinkBalance -= balance; + i_linkToken.safeTransfer(toAddress, uint256(balance)); + } + emit SubscriptionCanceled(subscriptionId, toAddress, balance); + } + + /// @inheritdoc IFunctionsSubscriptions + function cancelSubscription(uint64 subscriptionId, address to) external override { + _whenNotPaused(); + _onlySubscriptionOwner(subscriptionId); + _onlySenderThatAcceptedToS(); + + if (pendingRequestExists(subscriptionId)) { + revert CannotRemoveWithPendingRequests(); + } - emit SubscriptionCanceled(subscriptionId, to, balance); + _cancelSubscriptionHelper(subscriptionId, to, true); } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function pendingRequestExists(uint64 subscriptionId) public view override returns (bool) { address[] memory consumers = s_subscriptions[subscriptionId].consumers; // NOTE: loop iterations are bounded by config.maxConsumers @@ -452,14 +484,14 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece return false; } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function setFlags(uint64 subscriptionId, bytes32 flags) external override { _onlyRouterOwner(); _isExistingSubscription(subscriptionId); s_subscriptions[subscriptionId].flags = flags; } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function getFlags(uint64 subscriptionId) public view returns (bytes32) { return s_subscriptions[subscriptionId].flags; } @@ -468,7 +500,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // | Request Timeout | // ================================================================ - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function timeoutRequests(FunctionsResponse.Commitment[] calldata requestsToTimeoutByCommitment) external override { _whenNotPaused(); @@ -513,12 +545,12 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece } } - // Overriden in FunctionsRouter.sol + /// @dev Overriden in FunctionsRouter.sol function _onlySenderThatAcceptedToS() internal virtual; - // Overriden in FunctionsRouter.sol + /// @dev Overriden in FunctionsRouter.sol function _onlyRouterOwner() internal virtual; - // Overriden in FunctionsRouter.sol + /// @dev Overriden in FunctionsRouter.sol function _whenNotPaused() internal virtual; } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/Routable.sol b/contracts/src/v0.8/functions/dev/1_0_0/Routable.sol index 8c09eba5d79..b50b1e603f9 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/Routable.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/Routable.sol @@ -4,9 +4,9 @@ pragma solidity ^0.8.19; import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; import {IOwnableFunctionsRouter} from "./interfaces/IOwnableFunctionsRouter.sol"; -// @title This abstract should be inherited by contracts that will be used -// as the destinations to a route (id=>contract) on the Router. -// It provides a Router getter and modifiers +/// @title This abstract should be inherited by contracts that will be used +/// as the destinations to a route (id=>contract) on the Router. +/// It provides a Router getter and modifiers. abstract contract Routable is ITypeAndVersion { IOwnableFunctionsRouter private immutable i_router; @@ -14,7 +14,7 @@ abstract contract Routable is ITypeAndVersion { error OnlyCallableByRouter(); error OnlyCallableByRouterOwner(); - // @dev Initializes the contract. + /// @dev Initializes the contract. constructor(address router) { if (router == address(0)) { revert RouterMustBeSet(); @@ -22,12 +22,12 @@ abstract contract Routable is ITypeAndVersion { i_router = IOwnableFunctionsRouter(router); } - // @notice Return the Router + /// @notice Return the Router function _getRouter() internal view returns (IOwnableFunctionsRouter router) { return i_router; } - // @notice Reverts if called by anyone other than the router. + /// @notice Reverts if called by anyone other than the router. modifier onlyRouter() { if (msg.sender != address(i_router)) { revert OnlyCallableByRouter(); @@ -35,7 +35,7 @@ abstract contract Routable is ITypeAndVersion { _; } - // @notice Reverts if called by anyone other than the router owner. + /// @notice Reverts if called by anyone other than the router owner. modifier onlyRouterOwner() { if (msg.sender != i_router.owner()) { revert OnlyCallableByRouterOwner(); diff --git a/contracts/src/v0.8/functions/dev/1_0_0/accessControl/TermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/dev/1_0_0/accessControl/TermsOfServiceAllowList.sol index 2ce107c9861..c4bd524b522 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/accessControl/TermsOfServiceAllowList.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/accessControl/TermsOfServiceAllowList.sol @@ -10,12 +10,12 @@ import {ConfirmedOwner} from "../../../../shared/access/ConfirmedOwner.sol"; import {Address} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/Address.sol"; import {EnumerableSet} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableSet.sol"; -// @notice A contract to handle access control of subscription management dependent on signing a Terms of Service +/// @notice A contract to handle access control of subscription management dependent on signing a Terms of Service contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, ITypeAndVersion, ConfirmedOwner { using Address for address; using EnumerableSet for EnumerableSet.AddressSet; - // @inheritdoc ITypeAndVersion + /// @inheritdoc ITypeAndVersion string public constant override typeAndVersion = "Functions Terms of Service Allow List v1.0.0"; EnumerableSet.AddressSet private s_allowedSenders; @@ -53,14 +53,14 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, // | Configuration | // ================================================================ - // @notice Gets the contracts's configuration - // @return config + /// @notice Gets the contracts's configuration + /// @return config function getConfig() external view returns (Config memory) { return s_config; } - // @notice Sets the contracts's configuration - // @param config - See the contents of the TermsOfServiceAllowList.Config struct for more information + /// @notice Sets the contracts's configuration + /// @param config - See the contents of the TermsOfServiceAllowList.Config struct for more information function updateConfig(Config memory config) public onlyOwner { s_config = config; emit ConfigUpdated(config); @@ -70,12 +70,12 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, // | Allow methods | // ================================================================ - // @inheritdoc ITermsOfServiceAllowList + /// @inheritdoc ITermsOfServiceAllowList function getMessage(address acceptor, address recipient) public pure override returns (bytes32) { return keccak256(abi.encodePacked(acceptor, recipient)); } - // @inheritdoc ITermsOfServiceAllowList + /// @inheritdoc ITermsOfServiceAllowList function acceptTermsOfService(address acceptor, address recipient, bytes32 r, bytes32 s, uint8 v) external override { if (s_blockedSenders[recipient]) { revert RecipientIsBlocked(); @@ -102,12 +102,12 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, emit AddedAccess(recipient); } - // @inheritdoc ITermsOfServiceAllowList + /// @inheritdoc ITermsOfServiceAllowList function getAllAllowedSenders() external view override returns (address[] memory) { return s_allowedSenders.values(); } - // @inheritdoc IAccessController + /// @inheritdoc IAccessController function hasAccess(address user, bytes calldata /* data */) external view override returns (bool) { if (!s_config.enabled) { return true; @@ -119,7 +119,7 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, // | Block methods | // ================================================================ - // @inheritdoc ITermsOfServiceAllowList + /// @inheritdoc ITermsOfServiceAllowList function isBlockedSender(address sender) external view override returns (bool) { if (!s_config.enabled) { return false; @@ -127,14 +127,14 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, return s_blockedSenders[sender]; } - // @inheritdoc ITermsOfServiceAllowList + /// @inheritdoc ITermsOfServiceAllowList function blockSender(address sender) external override onlyOwner { s_allowedSenders.remove(sender); s_blockedSenders[sender] = true; emit BlockedAccess(sender); } - // @inheritdoc ITermsOfServiceAllowList + /// @inheritdoc ITermsOfServiceAllowList function unblockSender(address sender) external override onlyOwner { s_blockedSenders[sender] = false; emit UnblockedAccess(sender); diff --git a/contracts/src/v0.8/functions/dev/1_0_0/accessControl/interfaces/ITermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/dev/1_0_0/accessControl/interfaces/ITermsOfServiceAllowList.sol index b83375ee01f..af4daa18bc3 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/accessControl/interfaces/ITermsOfServiceAllowList.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/accessControl/interfaces/ITermsOfServiceAllowList.sol @@ -1,40 +1,40 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -// @notice A contract to handle access control of subscription management dependent on signing a Terms of Service +/// @notice A contract to handle access control of subscription management dependent on signing a Terms of Service interface ITermsOfServiceAllowList { - // @notice Return the message data for the proof given to accept the Terms of Service - // @param acceptor - The wallet address that has accepted the Terms of Service on the UI - // @param recipient - The recipient address that the acceptor is taking responsibility for - // @return Hash of the message data + /// @notice Return the message data for the proof given to accept the Terms of Service + /// @param acceptor - The wallet address that has accepted the Terms of Service on the UI + /// @param recipient - The recipient address that the acceptor is taking responsibility for + /// @return Hash of the message data function getMessage(address acceptor, address recipient) external pure returns (bytes32); - // @notice Check if the address is blocked for usage - // @param sender The transaction sender's address - // @return True or false + /// @notice Check if the address is blocked for usage + /// @param sender The transaction sender's address + /// @return True or false function isBlockedSender(address sender) external returns (bool); - // @notice Get a list of all allowed senders - // @dev WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - // to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - // this function has an unbounded cost, and using it as part of a state-changing function may render the function - // uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. - // @return addresses - all allowed addresses + /// @notice Get a list of all allowed senders + /// @dev WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + /// to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + /// this function has an unbounded cost, and using it as part of a state-changing function may render the function + /// uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + /// @return addresses - all allowed addresses function getAllAllowedSenders() external view returns (address[] memory); - // @notice Allows access to the sender based on acceptance of the Terms of Service - // @param acceptor - The wallet address that has accepted the Terms of Service on the UI - // @param recipient - The recipient address that the acceptor is taking responsibility for - // @param r - ECDSA signature r data produced by the Chainlink Functions Subscription UI - // @param s - ECDSA signature s produced by the Chainlink Functions Subscription UI - // @param v - ECDSA signature v produced by the Chainlink Functions Subscription UI + /// @notice Allows access to the sender based on acceptance of the Terms of Service + /// @param acceptor - The wallet address that has accepted the Terms of Service on the UI + /// @param recipient - The recipient address that the acceptor is taking responsibility for + /// @param r - ECDSA signature r data produced by the Chainlink Functions Subscription UI + /// @param s - ECDSA signature s produced by the Chainlink Functions Subscription UI + /// @param v - ECDSA signature v produced by the Chainlink Functions Subscription UI function acceptTermsOfService(address acceptor, address recipient, bytes32 r, bytes32 s, uint8 v) external; - // @notice Removes a sender's access if already authorized, and disallows re-accepting the Terms of Service - // @param sender - Address of the sender to block + /// @notice Removes a sender's access if already authorized, and disallows re-accepting the Terms of Service + /// @param sender - Address of the sender to block function blockSender(address sender) external; - // @notice Re-allows a previously blocked sender to accept the Terms of Service - // @param sender - Address of the sender to unblock + /// @notice Re-allows a previously blocked sender to accept the Terms of Service + /// @param sender - Address of the sender to unblock function unblockSender(address sender) external; } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/example/FunctionsClientExample.sol b/contracts/src/v0.8/functions/dev/1_0_0/example/FunctionsClientExample.sol index 5feee704ef5..f0f154c07b2 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/example/FunctionsClientExample.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/example/FunctionsClientExample.sol @@ -5,9 +5,7 @@ import {FunctionsClient} from "../FunctionsClient.sol"; import {ConfirmedOwner} from "../../../../shared/access/ConfirmedOwner.sol"; import {FunctionsRequest} from "../libraries/FunctionsRequest.sol"; -/** - * @title Chainlink Functions example Client contract implementation - */ +/// @title Chainlink Functions example Client contract implementation contract FunctionsClientExample is FunctionsClient, ConfirmedOwner { using FunctionsRequest for FunctionsRequest.Request; @@ -23,13 +21,11 @@ contract FunctionsClientExample is FunctionsClient, ConfirmedOwner { constructor(address router) FunctionsClient(router) ConfirmedOwner(msg.sender) {} - /** - * @notice Send a simple request - * @param source JavaScript source code - * @param encryptedSecretsReferences Encrypted secrets payload - * @param args List of arguments accessible from within the source code - * @param subscriptionId Billing ID - */ + /// @notice Send a simple request + /// @param source JavaScript source code + /// @param encryptedSecretsReferences Encrypted secrets payload + /// @param args List of arguments accessible from within the source code + /// @param subscriptionId Billing ID function sendRequest( string calldata source, bytes calldata encryptedSecretsReferences, @@ -44,13 +40,11 @@ contract FunctionsClientExample is FunctionsClient, ConfirmedOwner { s_lastRequestId = _sendRequest(req.encodeCBOR(), subscriptionId, MAX_CALLBACK_GAS, jobId); } - /** - * @notice Store latest result/error - * @param requestId The request ID, returned by sendRequest() - * @param response Aggregated response from the user code - * @param err Aggregated error from the user code or from the execution pipeline - * Either response or error parameter will be set, but never both - */ + /// @notice Store latest result/error + /// @param requestId The request ID, returned by sendRequest() + /// @param response Aggregated response from the user code + /// @param err Aggregated error from the user code or from the execution pipeline + /// @dev Either response or error parameter will be set, but never both function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override { if (s_lastRequestId != requestId) { revert UnexpectedRequestID(requestId); diff --git a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsBilling.sol b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsBilling.sol index 00ff17ee14d..6291d05e57c 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsBilling.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsBilling.sol @@ -1,44 +1,44 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -// @title Chainlink Functions DON billing interface. +/// @title Chainlink Functions DON billing interface. interface IFunctionsBilling { - // @notice Return the current conversion from WEI of ETH to LINK from the configured Chainlink data feed - // @return weiPerUnitLink - The amount of WEI in one LINK + /// @notice Return the current conversion from WEI of ETH to LINK from the configured Chainlink data feed + /// @return weiPerUnitLink - The amount of WEI in one LINK function getWeiPerUnitLink() external view returns (uint256); - // @notice Determine the fee that will be split between Node Operators for servicing a request - // @param requestCBOR - CBOR encoded Chainlink Functions request data, use FunctionsRequest library to encode a request - // @return fee - Cost in Juels (1e18) of LINK + /// @notice Determine the fee that will be split between Node Operators for servicing a request + /// @param requestCBOR - CBOR encoded Chainlink Functions request data, use FunctionsRequest library to encode a request + /// @return fee - Cost in Juels (1e18) of LINK function getDONFee(bytes memory requestCBOR) external view returns (uint72); - // @notice Determine the fee that will be paid to the Router owner for operating the network - // @return fee - Cost in Juels (1e18) of LINK + /// @notice Determine the fee that will be paid to the Router owner for operating the network + /// @return fee - Cost in Juels (1e18) of LINK function getAdminFee() external view returns (uint72); - // @notice Estimate the total cost that will be charged to a subscription to make a request: transmitter gas re-reimbursement, plus DON fee, plus Registry fee - // @param - subscriptionId An identifier of the billing account - // @param - data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - // @param - callbackGasLimit Gas limit for the fulfillment callback - // @param - gasPriceGwei The blockchain's gas price to estimate with - // @return - billedCost Cost in Juels (1e18) of LINK + /// @notice Estimate the total cost that will be charged to a subscription to make a request: transmitter gas re-reimbursement, plus DON fee, plus Registry fee + /// @param - subscriptionId An identifier of the billing account + /// @param - data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request + /// @param - callbackGasLimit Gas limit for the fulfillment callback + /// @param - gasPriceWei The blockchain's gas price to estimate with + /// @return - billedCost Cost in Juels (1e18) of LINK function estimateCost( uint64 subscriptionId, bytes calldata data, uint32 callbackGasLimit, - uint256 gasPriceGwei + uint256 gasPriceWei ) external view returns (uint96); - // @notice Remove a request commitment that the Router has determined to be stale - // @param requestId - The request ID to remove - function deleteCommitment(bytes32 requestId) external returns (bool); + /// @notice Remove a request commitment that the Router has determined to be stale + /// @param requestId - The request ID to remove + function deleteCommitment(bytes32 requestId) external; - // @notice Oracle withdraw LINK earned through fulfilling requests - // @notice If amount is 0 the full balance will be withdrawn - // @param recipient where to send the funds - // @param amount amount to withdraw + /// @notice Oracle withdraw LINK earned through fulfilling requests + /// @notice If amount is 0 the full balance will be withdrawn + /// @param recipient where to send the funds + /// @param amount amount to withdraw function oracleWithdraw(address recipient, uint96 amount) external; - // @notice Withdraw all LINK earned by Oracles through fulfilling requests + /// @notice Withdraw all LINK earned by Oracles through fulfilling requests function oracleWithdrawAll() external; } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsClient.sol b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsClient.sol index 5fbee58274e..f28a41666b5 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsClient.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsClient.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -// @title Chainlink Functions client interface. +/// @title Chainlink Functions client interface. interface IFunctionsClient { - // @notice Chainlink Functions response handler called by the Functions Router - // during fullilment from the designated transmitter node in an OCR round. - // @param requestId The requestId returned by FunctionsClient.sendRequest(). - // @param response Aggregated response from the request's source code. - // @param err Aggregated error either from the request's source code or from the execution pipeline. - // @dev Either response or error parameter will be set, but never both. + /// @notice Chainlink Functions response handler called by the Functions Router + /// during fullilment from the designated transmitter node in an OCR round. + /// @param requestId The requestId returned by FunctionsClient.sendRequest(). + /// @param response Aggregated response from the request's source code. + /// @param err Aggregated error either from the request's source code or from the execution pipeline. + /// @dev Either response or error parameter will be set, but never both. function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external; } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsCoordinator.sol b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsCoordinator.sol index 5a0d07415bd..4e2bd703dc4 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsCoordinator.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsCoordinator.sol @@ -3,34 +3,34 @@ pragma solidity ^0.8.19; import {FunctionsResponse} from "../libraries/FunctionsResponse.sol"; -// @title Chainlink Functions DON Coordinator interface. +/// @title Chainlink Functions DON Coordinator interface. interface IFunctionsCoordinator { - // @notice Returns the DON's threshold encryption public key used to encrypt secrets - // @dev All nodes on the DON have separate key shares of the threshold decryption key - // and nodes must participate in a threshold decryption OCR round to decrypt secrets - // @return thresholdPublicKey the DON's threshold encryption public key + /// @notice Returns the DON's threshold encryption public key used to encrypt secrets + /// @dev All nodes on the DON have separate key shares of the threshold decryption key + /// and nodes must participate in a threshold decryption OCR round to decrypt secrets + /// @return thresholdPublicKey the DON's threshold encryption public key function getThresholdPublicKey() external view returns (bytes memory); - // @notice Sets the DON's threshold encryption public key used to encrypt secrets - // @dev Used to rotate the key - // @param thresholdPublicKey The new public key + /// @notice Sets the DON's threshold encryption public key used to encrypt secrets + /// @dev Used to rotate the key + /// @param thresholdPublicKey The new public key function setThresholdPublicKey(bytes calldata thresholdPublicKey) external; - // @notice Returns the DON's secp256k1 public key that is used to encrypt secrets - // @dev All nodes on the DON have the corresponding private key - // needed to decrypt the secrets encrypted with the public key - // @return publicKey the DON's public key + /// @notice Returns the DON's secp256k1 public key that is used to encrypt secrets + /// @dev All nodes on the DON have the corresponding private key + /// needed to decrypt the secrets encrypted with the public key + /// @return publicKey the DON's public key function getDONPublicKey() external view returns (bytes memory); - // @notice Sets DON's secp256k1 public key used to encrypt secrets - // @dev Used to rotate the key - // @param donPublicKey The new public key + /// @notice Sets DON's secp256k1 public key used to encrypt secrets + /// @dev Used to rotate the key + /// @param donPublicKey The new public key function setDONPublicKey(bytes calldata donPublicKey) external; - // @notice Receives a request to be emitted to the DON for processing - // @param request The request metadata - // @dev see the struct for field descriptions - // @return commitment - The parameters of the request that must be held consistent at response time + /// @notice Receives a request to be emitted to the DON for processing + /// @param request The request metadata + /// @dev see the struct for field descriptions + /// @return commitment - The parameters of the request that must be held consistent at response time function startRequest( FunctionsResponse.RequestMeta calldata request ) external returns (FunctionsResponse.Commitment memory commitment); diff --git a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsRouter.sol b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsRouter.sol index ebc1dbd4538..5f93aac873e 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsRouter.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsRouter.sol @@ -3,29 +3,29 @@ pragma solidity ^0.8.19; import {FunctionsResponse} from "../libraries/FunctionsResponse.sol"; -// @title Chainlink Functions Router interface. +/// @title Chainlink Functions Router interface. interface IFunctionsRouter { - // @notice The identifier of the route to retrieve the address of the access control contract - // The access control contract controls which accounts can manage subscriptions - // @return id - bytes32 id that can be passed to the "getContractById" of the Router + /// @notice The identifier of the route to retrieve the address of the access control contract + /// The access control contract controls which accounts can manage subscriptions + /// @return id - bytes32 id that can be passed to the "getContractById" of the Router function getAllowListId() external view returns (bytes32); - // @notice Set the identifier of the route to retrieve the address of the access control contract - // The access control contract controls which accounts can manage subscriptions + /// @notice Set the identifier of the route to retrieve the address of the access control contract + /// The access control contract controls which accounts can manage subscriptions function setAllowListId(bytes32 allowListId) external; - // @notice Get the flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network - // @return adminFee + /// @notice Get the flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network + /// @return adminFee function getAdminFee() external view returns (uint72 adminFee); - // @notice Sends a request using the provided subscriptionId - // @param subscriptionId - A unique subscription ID allocated by billing system, - // a client can make requests from different contracts referencing the same subscription - // @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request - // @param dataVersion - Gas limit for the fulfillment callback - // @param callbackGasLimit - Gas limit for the fulfillment callback - // @param donId - An identifier used to determine which route to send the request along - // @return requestId - A unique request identifier + /// @notice Sends a request using the provided subscriptionId + /// @param subscriptionId - A unique subscription ID allocated by billing system, + /// a client can make requests from different contracts referencing the same subscription + /// @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request + /// @param dataVersion - Gas limit for the fulfillment callback + /// @param callbackGasLimit - Gas limit for the fulfillment callback + /// @param donId - An identifier used to determine which route to send the request along + /// @return requestId - A unique request identifier function sendRequest( uint64 subscriptionId, bytes calldata data, @@ -34,14 +34,14 @@ interface IFunctionsRouter { bytes32 donId ) external returns (bytes32); - // @notice Sends a request to the proposed contracts - // @param subscriptionId - A unique subscription ID allocated by billing system, - // a client can make requests from different contracts referencing the same subscription - // @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request - // @param dataVersion - Gas limit for the fulfillment callback - // @param callbackGasLimit - Gas limit for the fulfillment callback - // @param donId - An identifier used to determine which route to send the request along - // @return requestId - A unique request identifier + /// @notice Sends a request to the proposed contracts + /// @param subscriptionId - A unique subscription ID allocated by billing system, + /// a client can make requests from different contracts referencing the same subscription + /// @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request + /// @param dataVersion - Gas limit for the fulfillment callback + /// @param callbackGasLimit - Gas limit for the fulfillment callback + /// @param donId - An identifier used to determine which route to send the request along + /// @return requestId - A unique request identifier function sendRequestToProposed( uint64 subscriptionId, bytes calldata data, @@ -50,18 +50,18 @@ interface IFunctionsRouter { bytes32 donId ) external returns (bytes32); - // @notice Fulfill the request by: - // - calling back the data that the Oracle returned to the client contract - // - pay the DON for processing the request - // @dev Only callable by the Coordinator contract that is saved in the commitment - // @param response response data from DON consensus - // @param err error from DON consensus - // @param juelsPerGas - current rate of juels/gas - // @param costWithoutFulfillment - The cost of processing the request (in Juels of LINK ), without fulfillment - // @param transmitter - The Node that transmitted the OCR report - // @param commitment - The parameters of the request that must be held consistent between request and response time - // @return fulfillResult - - // @return callbackGasCostJuels - + /// @notice Fulfill the request by: + /// - calling back the data that the Oracle returned to the client contract + /// - pay the DON for processing the request + /// @dev Only callable by the Coordinator contract that is saved in the commitment + /// @param response response data from DON consensus + /// @param err error from DON consensus + /// @param juelsPerGas - current rate of juels/gas + /// @param costWithoutFulfillment - The cost of processing the request (in Juels of LINK ), without fulfillment + /// @param transmitter - The Node that transmitted the OCR report + /// @param commitment - The parameters of the request that must be held consistent between request and response time + /// @return fulfillResult - + /// @return callbackGasCostJuels - function fulfill( bytes memory response, bytes memory err, @@ -71,39 +71,39 @@ interface IFunctionsRouter { FunctionsResponse.Commitment memory commitment ) external returns (FunctionsResponse.FulfillResult, uint96); - // @notice Validate requested gas limit is below the subscription max. - // @param subscriptionId subscription ID - // @param callbackGasLimit desired callback gas limit + /// @notice Validate requested gas limit is below the subscription max. + /// @param subscriptionId subscription ID + /// @param callbackGasLimit desired callback gas limit function isValidCallbackGasLimit(uint64 subscriptionId, uint32 callbackGasLimit) external view; - // @notice Get the current contract given an ID - // @param id A bytes32 identifier for the route - // @return contract The current contract address + /// @notice Get the current contract given an ID + /// @param id A bytes32 identifier for the route + /// @return contract The current contract address function getContractById(bytes32 id) external view returns (address); - // @notice Get the proposed next contract given an ID - // @param id A bytes32 identifier for the route - // @return contract The current or proposed contract address + /// @notice Get the proposed next contract given an ID + /// @param id A bytes32 identifier for the route + /// @return contract The current or proposed contract address function getProposedContractById(bytes32 id) external view returns (address); - // @notice Return the latest proprosal set - // @return ids The identifiers of the contracts to update - // @return to The addresses of the contracts that will be updated to + /// @notice Return the latest proprosal set + /// @return ids The identifiers of the contracts to update + /// @return to The addresses of the contracts that will be updated to function getProposedContractSet() external view returns (bytes32[] memory, address[] memory); - // @notice Proposes one or more updates to the contract routes - // @dev Only callable by owner + /// @notice Proposes one or more updates to the contract routes + /// @dev Only callable by owner function proposeContractsUpdate(bytes32[] memory proposalSetIds, address[] memory proposalSetAddresses) external; - // @notice Updates the current contract routes to the proposed contracts - // @dev Only callable by owner + /// @notice Updates the current contract routes to the proposed contracts + /// @dev Only callable by owner function updateContracts() external; - // @dev Puts the system into an emergency stopped state. - // @dev Only callable by owner + /// @dev Puts the system into an emergency stopped state. + /// @dev Only callable by owner function pause() external; - // @dev Takes the system out of an emergency stopped state. - // @dev Only callable by owner + /// @dev Takes the system out of an emergency stopped state. + /// @dev Only callable by owner function unpause() external; } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsSubscriptions.sol b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsSubscriptions.sol index 4072307edb8..eafd6f4fe99 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsSubscriptions.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsSubscriptions.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; import {FunctionsResponse} from "../libraries/FunctionsResponse.sol"; -// @title Chainlink Functions Subscription interface. +/// @title Chainlink Functions Subscription interface. interface IFunctionsSubscriptions { struct Subscription { uint96 balance; // ═════════╗ Common LINK balance that is controlled by the Router to be used for all consumer requests. @@ -20,114 +20,121 @@ interface IFunctionsSubscriptions { uint64 completedRequests; // ══╝ The number of requests that have successfully completed or timed out } - // @notice Get details about a subscription. - // @param subscriptionId - the ID of the subscription - // @return subscription - see IFunctionsSubscriptions.Subscription for more information on the structure + /// @notice Get details about a subscription. + /// @param subscriptionId - the ID of the subscription + /// @return subscription - see IFunctionsSubscriptions.Subscription for more information on the structure function getSubscription(uint64 subscriptionId) external view returns (Subscription memory); - // @notice Get details about a consumer of a subscription. - // @param client - the consumer contract address - // @param subscriptionId - the ID of the subscription - // @return consumer - see IFunctionsSubscriptions.Consumer for more information on the structure + /// @notice Retrieve details about multiple subscriptions using an inclusive range + /// @param subscriptionIdStart - the ID of the subscription to start the range at + /// @param subscriptionIdEnd - the ID of the subscription to end the range at + /// @return subscriptions - see IFunctionsSubscriptions.Subscription for more information on the structure + function getSubscriptionsInRange( + uint64 subscriptionIdStart, + uint64 subscriptionIdEnd + ) external view returns (Subscription[] memory); + + /// @notice Get details about a consumer of a subscription. + /// @param client - the consumer contract address + /// @param subscriptionId - the ID of the subscription + /// @return consumer - see IFunctionsSubscriptions.Consumer for more information on the structure function getConsumer(address client, uint64 subscriptionId) external view returns (Consumer memory); - // @notice Get details about the total amount of LINK within the system - // @return totalBalance - total Juels of LINK held by the contract + /// @notice Get details about the total amount of LINK within the system + /// @return totalBalance - total Juels of LINK held by the contract function getTotalBalance() external view returns (uint96); - // @notice Get details about the total number of subscription accounts - // @return count - total number of subscriptions in the system + /// @notice Get details about the total number of subscription accounts + /// @return count - total number of subscriptions in the system function getSubscriptionCount() external view returns (uint64); - // @notice Time out all expired requests: unlocks funds and removes the ability for the request to be fulfilled - // @param requestsToTimeoutByCommitment - A list of request commitments to time out - // @dev The commitment can be found on the "OracleRequest" event created when sending the request. + /// @notice Time out all expired requests: unlocks funds and removes the ability for the request to be fulfilled + /// @param requestsToTimeoutByCommitment - A list of request commitments to time out + /// @dev The commitment can be found on the "OracleRequest" event created when sending the request. function timeoutRequests(FunctionsResponse.Commitment[] calldata requestsToTimeoutByCommitment) external; - // @notice Oracle withdraw LINK earned through fulfilling requests - // @notice If amount is 0 the full balance will be withdrawn - // @notice Both signing and transmitting wallets will have a balance to withdraw - // @param recipient where to send the funds - // @param amount amount to withdraw + /// @notice Oracle withdraw LINK earned through fulfilling requests + /// @notice If amount is 0 the full balance will be withdrawn + /// @notice Both signing and transmitting wallets will have a balance to withdraw + /// @param recipient where to send the funds + /// @param amount amount to withdraw function oracleWithdraw(address recipient, uint96 amount) external; - // @notice Owner cancel subscription, sends remaining link directly to the subscription owner. - // @dev Only callable by the Router Owner - // @param subscriptionId subscription id - // @dev notably can be called even if there are pending requests, outstanding ones may fail onchain + /// @notice Owner cancel subscription, sends remaining link directly to the subscription owner. + /// @dev Only callable by the Router Owner + /// @param subscriptionId subscription id + /// @dev notably can be called even if there are pending requests, outstanding ones may fail onchain function ownerCancelSubscription(uint64 subscriptionId) external; - // @notice Recover link sent with transfer instead of transferAndCall. - // @dev Only callable by the Router Owner - // @param to address to send link to + /// @notice Recover link sent with transfer instead of transferAndCall. + /// @dev Only callable by the Router Owner + /// @param to address to send link to function recoverFunds(address to) external; - // @notice Create a new subscription. - // @return subscriptionId - A unique subscription id. - // @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. - // @dev Note to fund the subscription, use transferAndCall. For example - // @dev LINKTOKEN.transferAndCall( - // @dev address(ROUTER), - // @dev amount, - // @dev abi.encode(subscriptionId)); + /// @notice Create a new subscription. + /// @return subscriptionId - A unique subscription id. + /// @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. + /// @dev Note to fund the subscription, use transferAndCall. For example + /// @dev LINKTOKEN.transferAndCall( + /// @dev address(ROUTER), + /// @dev amount, + /// @dev abi.encode(subscriptionId)); function createSubscription() external returns (uint64); - // @notice Create a new subscription and add a consumer. - // @return subscriptionId - A unique subscription id. - // @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. - // @dev Note to fund the subscription, use transferAndCall. For example - // @dev LINKTOKEN.transferAndCall( - // @dev address(ROUTER), - // @dev amount, - // @dev abi.encode(subscriptionId)); + /// @notice Create a new subscription and add a consumer. + /// @return subscriptionId - A unique subscription id. + /// @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. + /// @dev Note to fund the subscription, use transferAndCall. For example + /// @dev LINKTOKEN.transferAndCall( + /// @dev address(ROUTER), + /// @dev amount, + /// @dev abi.encode(subscriptionId)); function createSubscriptionWithConsumer(address consumer) external returns (uint64 subscriptionId); - // @notice Propose a new owner for a subscription. - // @dev Only callable by the Subscription's owner - // @param subscriptionId - ID of the subscription - // @param newOwner - proposed new owner of the subscription + /// @notice Propose a new owner for a subscription. + /// @dev Only callable by the Subscription's owner + /// @param subscriptionId - ID of the subscription + /// @param newOwner - proposed new owner of the subscription function proposeSubscriptionOwnerTransfer(uint64 subscriptionId, address newOwner) external; - // @notice Accept an ownership transfer. - // @param subscriptionId - ID of the subscription - // @dev will revert if original owner of subscriptionId has - // not requested that msg.sender become the new owner. + /// @notice Accept an ownership transfer. + /// @param subscriptionId - ID of the subscription + /// @dev will revert if original owner of subscriptionId has not requested that msg.sender become the new owner. function acceptSubscriptionOwnerTransfer(uint64 subscriptionId) external; - // @notice Remove a consumer from a Chainlink Functions subscription. - // @dev Only callable by the Subscription's owner - // @param subscriptionId - ID of the subscription - // @param consumer - Consumer to remove from the subscription + /// @notice Remove a consumer from a Chainlink Functions subscription. + /// @dev Only callable by the Subscription's owner + /// @param subscriptionId - ID of the subscription + /// @param consumer - Consumer to remove from the subscription function removeConsumer(uint64 subscriptionId, address consumer) external; - // @notice Add a consumer to a Chainlink Functions subscription. - // @dev Only callable by the Subscription's owner - // @param subscriptionId - ID of the subscription - // @param consumer - New consumer which can use the subscription + /// @notice Add a consumer to a Chainlink Functions subscription. + /// @dev Only callable by the Subscription's owner + /// @param subscriptionId - ID of the subscription + /// @param consumer - New consumer which can use the subscription function addConsumer(uint64 subscriptionId, address consumer) external; - // @notice Cancel a subscription - // @dev Only callable by the Subscription's owner - // @param subscriptionId - ID of the subscription - // @param to - Where to send the remaining LINK to + /// @notice Cancel a subscription + /// @dev Only callable by the Subscription's owner + /// @param subscriptionId - ID of the subscription + /// @param to - Where to send the remaining LINK to function cancelSubscription(uint64 subscriptionId, address to) external; - // @notice Check to see if there exists a request commitment for all consumers for a given sub. - // @param subscriptionId - ID of the subscription - // @return true if there exists at least one unfulfilled request for the subscription, false - // otherwise. - // @dev Looping is bounded to MAX_CONSUMERS*(number of DONs). - // @dev Used to disable subscription canceling while outstanding request are present. + /// @notice Check to see if there exists a request commitment for all consumers for a given sub. + /// @param subscriptionId - ID of the subscription + /// @return true if there exists at least one unfulfilled request for the subscription, false otherwise. + /// @dev Looping is bounded to MAX_CONSUMERS*(number of DONs). + /// @dev Used to disable subscription canceling while outstanding request are present. function pendingRequestExists(uint64 subscriptionId) external view returns (bool); - // @notice Set subscription specific flags for a subscription. - // Each byte of the flag is used to represent a resource tier that the subscription can utilize. - // @param subscriptionId - ID of the subscription - // @param flags - desired flag values + /// @notice Set subscription specific flags for a subscription. + /// Each byte of the flag is used to represent a resource tier that the subscription can utilize. + /// @param subscriptionId - ID of the subscription + /// @param flags - desired flag values function setFlags(uint64 subscriptionId, bytes32 flags) external; - // @notice Get flags for a given subscription. - // @param subscriptionId - ID of the subscription - // @return flags - current flag values + /// @notice Get flags for a given subscription. + /// @param subscriptionId - ID of the subscription + /// @return flags - current flag values function getFlags(uint64 subscriptionId) external view returns (bytes32); } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IOwnableFunctionsRouter.sol b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IOwnableFunctionsRouter.sol index 5a2f85fd32e..39b84a930aa 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IOwnableFunctionsRouter.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IOwnableFunctionsRouter.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.19; import {IFunctionsRouter} from "./IFunctionsRouter.sol"; import {IOwnable} from "../../../../shared/interfaces/IOwnable.sol"; -// @title Chainlink Functions Router interface with Ownability. +/// @title Chainlink Functions Router interface with Ownability. interface IOwnableFunctionsRouter is IOwnable, IFunctionsRouter { } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsRequest.sol b/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsRequest.sol index 0a669588ed0..efc3a811e6a 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsRequest.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsRequest.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; import {CBOR} from "../../../../vendor/solidity-cborutils/v2.0.0/CBOR.sol"; -// @title Library for encoding the input data of a Functions request into CBOR +/// @title Library for encoding the input data of a Functions request into CBOR library FunctionsRequest { using CBOR for CBOR.CBORBuffer; @@ -27,7 +27,6 @@ library FunctionsRequest { CodeLanguage language; // ════════════╸ The coding language that the source code is written in string source; // ════════════════════╸ Raw source code for Request.codeLocation of Location.Inline, URL for Request.codeLocation of Location.Remote, or slot decimal number for Request.codeLocation of Location.DONHosted bytes encryptedSecretsReference; // ══╸ Encrypted URLs for Request.secretsLocation of Location.Remote (use addSecretsReference()), or CBOR encoded slotid+version for Request.secretsLocation of Location.DONHosted (use addDONHostedSecrets()) - bytes requestSignature; // ═══════════╸ Signature generated by the subscription owner's EOA string[] args; // ════════════════════╸ String arguments that will be passed into the source code bytes[] bytesArgs; // ════════════════╸ Bytes arguments that will be passed into the source code } @@ -37,9 +36,9 @@ library FunctionsRequest { error EmptyArgs(); error NoInlineSecrets(); - // @notice Encodes a Request to CBOR encoded bytes - // @param self The request to encode - // @return CBOR encoded bytes + /// @notice Encodes a Request to CBOR encoded bytes + /// @param self The request to encode + /// @return CBOR encoded bytes function encodeCBOR(Request memory self) internal pure returns (bytes memory) { CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE); @@ -52,11 +51,6 @@ library FunctionsRequest { buffer.writeString("source"); buffer.writeString(self.source); - if (self.requestSignature.length > 0) { - buffer.writeString("requestSignature"); - buffer.writeBytes(self.requestSignature); - } - if (self.args.length > 0) { buffer.writeString("args"); buffer.startArray(); @@ -88,12 +82,12 @@ library FunctionsRequest { return buffer.buf.buf; } - // @notice Initializes a Chainlink Functions Request - // @dev Sets the codeLocation and code on the request - // @param self The uninitialized request - // @param codeLocation The user provided source code location - // @param language The programming language of the user code - // @param source The user provided source code or a url + /// @notice Initializes a Chainlink Functions Request + /// @dev Sets the codeLocation and code on the request + /// @param self The uninitialized request + /// @param codeLocation The user provided source code location + /// @param language The programming language of the user code + /// @param source The user provided source code or a url function initializeRequest( Request memory self, Location codeLocation, @@ -107,17 +101,17 @@ library FunctionsRequest { self.source = source; } - // @notice Initializes a Chainlink Functions Request - // @dev Simplified version of initializeRequest for PoC - // @param self The uninitialized request - // @param javaScriptSource The user provided JS code (must not be empty) + /// @notice Initializes a Chainlink Functions Request + /// @dev Simplified version of initializeRequest for PoC + /// @param self The uninitialized request + /// @param javaScriptSource The user provided JS code (must not be empty) function initializeRequestForInlineJavaScript(Request memory self, string memory javaScriptSource) internal pure { initializeRequest(self, Location.Inline, CodeLanguage.JavaScript, javaScriptSource); } - // @notice Adds Remote user encrypted secrets to a Request - // @param self The initialized request - // @param encryptedSecretsReference Encrypted comma-separated string of URLs pointing to off-chain secrets + /// @notice Adds Remote user encrypted secrets to a Request + /// @param self The initialized request + /// @param encryptedSecretsReference Encrypted comma-separated string of URLs pointing to off-chain secrets function addSecretsReference(Request memory self, bytes memory encryptedSecretsReference) internal pure { if (encryptedSecretsReference.length == 0) revert EmptySecrets(); @@ -125,10 +119,10 @@ library FunctionsRequest { self.encryptedSecretsReference = encryptedSecretsReference; } - // @notice Adds DON-hosted secrets reference to a Request - // @param self The initialized request - // @param slotID Slot ID of the user's secrets hosted on DON - // @param version User data version (for the slotID) + /// @notice Adds DON-hosted secrets reference to a Request + /// @param self The initialized request + /// @param slotID Slot ID of the user's secrets hosted on DON + /// @param version User data version (for the slotID) function addDONHostedSecrets(Request memory self, uint8 slotID, uint64 version) internal pure { CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE); @@ -141,18 +135,18 @@ library FunctionsRequest { self.encryptedSecretsReference = buffer.buf.buf; } - // @notice Sets args for the user run function - // @param self The initialized request - // @param args The array of string args (must not be empty) + /// @notice Sets args for the user run function + /// @param self The initialized request + /// @param args The array of string args (must not be empty) function setArgs(Request memory self, string[] memory args) internal pure { if (args.length == 0) revert EmptyArgs(); self.args = args; } - // @notice Sets bytes args for the user run function - // @param self The initialized request - // @param args The array of bytes args (must not be empty) + /// @notice Sets bytes args for the user run function + /// @param self The initialized request + /// @param args The array of bytes args (must not be empty) function setBytesArgs(Request memory self, bytes[] memory args) internal pure { if (args.length == 0) revert EmptyArgs(); diff --git a/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsResponse.sol b/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsResponse.sol index 71e731b2e33..31a33169226 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsResponse.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsResponse.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; import {IFunctionsSubscriptions} from "../interfaces/IFunctionsSubscriptions.sol"; -// @title Library of types that are used for fulfillment of a Functions request +/// @title Library of types that are used for fulfillment of a Functions request library FunctionsResponse { // Used to send request information from the Router to the Coordinator struct RequestMeta { diff --git a/contracts/src/v0.8/functions/tests/1_0_0/FunctionsCoordinator.t.sol b/contracts/src/v0.8/functions/tests/1_0_0/FunctionsCoordinator.t.sol index c6d560fffc6..cf3a86cce41 100644 --- a/contracts/src/v0.8/functions/tests/1_0_0/FunctionsCoordinator.t.sol +++ b/contracts/src/v0.8/functions/tests/1_0_0/FunctionsCoordinator.t.sol @@ -1,6 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; +import {FunctionsCoordinator} from "../../dev/1_0_0/FunctionsCoordinator.sol"; +import {FunctionsBilling} from "../../dev/1_0_0/FunctionsBilling.sol"; +import {FunctionsRequest} from "../../dev/1_0_0/libraries/FunctionsRequest.sol"; + +import {FunctionsSubscriptionSetup, FunctionsMultipleFulfillmentsSetup} from "./Setup.t.sol"; + // ================================================================ // | Functions Coordinator | // ================================================================ @@ -115,8 +121,61 @@ contract FunctionsBilling__GetJuelsPerGas { } /// @notice #estimateCost -contract FunctionsBilling_EstimateCost { - +contract FunctionsBilling_EstimateCost is FunctionsSubscriptionSetup { + function setUp() public virtual override { + FunctionsSubscriptionSetup.setUp(); + + // Get cost estimate as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + } + + uint256 private constant REASONABLE_GAS_PRICE_CEILING = 1_000_000_000_000_000; // 1 million gwei + + function test_EstimateCost_RevertsIfGasPriceAboveCeiling() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + uint32 callbackGasLimit = 5_500; + uint256 gasPriceWei = REASONABLE_GAS_PRICE_CEILING + 1; + + vm.expectRevert(FunctionsBilling.InvalidCalldata.selector); + + s_functionsCoordinator.estimateCost(s_subscriptionId, requestData, callbackGasLimit, gasPriceWei); + } + + function test_EstimateCost_Success() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + uint32 callbackGasLimit = 5_500; + uint256 gasPriceWei = 1; + + uint96 costEstimate = s_functionsCoordinator.estimateCost( + s_subscriptionId, + requestData, + callbackGasLimit, + gasPriceWei + ); + uint96 expectedCostEstimate = 15725380; + assertEq(costEstimate, expectedCostEstimate); + } } /// @notice #_calculateCostEstimate @@ -150,8 +209,47 @@ contract FunctionsBilling_OracleWithdraw { } /// @notice #oracleWithdrawAll -contract FunctionsBilling_OracleWithdrawAll { - +contract FunctionsBilling_OracleWithdrawAll is FunctionsMultipleFulfillmentsSetup { + function setUp() public virtual override { + // Use no DON fee so that a transmitter has a balance of 0 + s_donFee = 0; + + FunctionsMultipleFulfillmentsSetup.setUp(); + } + + function test_OracleWithdrawAll_RevertIfNotOwner() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert("Only callable by owner"); + s_functionsCoordinator.oracleWithdrawAll(); + } + + function test_OracleWithdrawAll_SuccessPaysTransmittersWithBalance() public { + uint256 transmitter1BalanceBefore = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_1); + assertEq(transmitter1BalanceBefore, 0); + uint256 transmitter2BalanceBefore = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_2); + assertEq(transmitter2BalanceBefore, 0); + uint256 transmitter3BalanceBefore = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_3); + assertEq(transmitter3BalanceBefore, 0); + uint256 transmitter4BalanceBefore = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_4); + assertEq(transmitter4BalanceBefore, 0); + + s_functionsCoordinator.oracleWithdrawAll(); + + uint96 expectedTransmitterBalance = s_fulfillmentCoordinatorBalance / 3; + + uint256 transmitter1BalanceAfter = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_1); + assertEq(transmitter1BalanceAfter, expectedTransmitterBalance); + uint256 transmitter2BalanceAfter = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_2); + assertEq(transmitter2BalanceAfter, expectedTransmitterBalance); + uint256 transmitter3BalanceAfter = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_3); + assertEq(transmitter3BalanceAfter, expectedTransmitterBalance); + // Transmitter 4 has no balance + uint256 transmitter4BalanceAfter = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_4); + assertEq(transmitter4BalanceAfter, 0); + } } /// @notice #_getTransmitters diff --git a/contracts/src/v0.8/functions/tests/1_0_0/FunctionsRouter.t.sol b/contracts/src/v0.8/functions/tests/1_0_0/FunctionsRouter.t.sol index 742a471cb58..4d6e5a1fe0e 100644 --- a/contracts/src/v0.8/functions/tests/1_0_0/FunctionsRouter.t.sol +++ b/contracts/src/v0.8/functions/tests/1_0_0/FunctionsRouter.t.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.19; import {FunctionsRouter} from "../../dev/1_0_0/FunctionsRouter.sol"; import {FunctionsSubscriptions} from "../../dev/1_0_0/FunctionsSubscriptions.sol"; +import {FunctionsCoordinator} from "../../dev/1_0_0/FunctionsCoordinator.sol"; import {FunctionsBilling} from "../../dev/1_0_0/FunctionsBilling.sol"; import {FunctionsRequest} from "../../dev/1_0_0/libraries/FunctionsRequest.sol"; import {FunctionsResponse} from "../../dev/1_0_0/libraries/FunctionsResponse.sol"; @@ -12,7 +13,6 @@ import {FunctionsClientTestHelper} from "./testhelpers/FunctionsClientTestHelper import {FunctionsRouterSetup, FunctionsRoutesSetup, FunctionsSubscriptionSetup, FunctionsClientRequestSetup} from "./Setup.t.sol"; import "forge-std/Vm.sol"; -import "forge-std/console.sol"; // ================================================================ // | Functions Router | @@ -41,6 +41,8 @@ contract FunctionsRouter_GetConfig is FunctionsRouterSetup { assertEq(config.maxCallbackGasLimits[1], getRouterConfig().maxCallbackGasLimits[1]); assertEq(config.maxCallbackGasLimits[2], getRouterConfig().maxCallbackGasLimits[2]); assertEq(config.gasForCallExactCheck, getRouterConfig().gasForCallExactCheck); + assertEq(config.subscriptionDepositMinimumRequests, getRouterConfig().subscriptionDepositMinimumRequests); + assertEq(config.subscriptionDepositJuels, getRouterConfig().subscriptionDepositJuels); } } @@ -62,7 +64,9 @@ contract FunctionsRouter_UpdateConfig is FunctionsRouterSetup { adminFee: s_adminFee, handleOracleFulfillmentSelector: s_handleOracleFulfillmentSelector, maxCallbackGasLimits: maxCallbackGasLimits, - gasForCallExactCheck: 5000 + gasForCallExactCheck: 5000, + subscriptionDepositMinimumRequests: 10, + subscriptionDepositJuels: 5 * 1e18 }); } @@ -380,6 +384,59 @@ contract FunctionsRouter_SendRequest is FunctionsSubscriptionSetup { ); } + function test_SendRequest_RevertIfDuplicateRequestId() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + uint32 callbackGasLimit = 5_000; + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + // Send a first request that will remain pending + bytes32 requestId = s_functionsRouter.sendRequest( + s_subscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + callbackGasLimit, + s_donId + ); + + // Mock the Coordinator to always give back the first requestId + FunctionsResponse.Commitment memory mockCommitment = FunctionsResponse.Commitment({ + adminFee: s_adminFee, + coordinator: address(s_functionsCoordinator), + client: OWNER_ADDRESS, + subscriptionId: s_subscriptionId, + callbackGasLimit: callbackGasLimit, + estimatedTotalCostJuels: 0, + timeoutTimestamp: uint32(block.timestamp + getCoordinatorConfig().requestTimeoutSeconds), + requestId: requestId, + donFee: s_donFee, + gasOverheadBeforeCallback: getCoordinatorConfig().gasOverheadBeforeCallback, + gasOverheadAfterCallback: getCoordinatorConfig().gasOverheadAfterCallback + }); + + vm.mockCall( + address(s_functionsCoordinator), + abi.encodeWithSelector(FunctionsCoordinator.startRequest.selector), + abi.encode(mockCommitment) + ); + + vm.expectRevert(abi.encodeWithSelector(FunctionsRouter.DuplicateRequestId.selector, requestId)); + s_functionsRouter.sendRequest( + s_subscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + callbackGasLimit, + s_donId + ); + } + event RequestStart( bytes32 indexed requestId, bytes32 indexed donId, @@ -1137,7 +1194,10 @@ contract FunctionsRouter_Fulfill is FunctionsClientRequestSetup { assertEq(callbackGasCostJuels, 0); } - function test_Fulfill_SuccessFulfilled() public { + function test_Fulfill_SuccessClientNoLongerExists() public { + // Delete the Client contract in the time between request and fulfillment + vm.etch(address(s_functionsClient), new bytes(0)); + // Send as committed Coordinator vm.stopPrank(); vm.startPrank(address(s_functionsCoordinator)); @@ -1149,6 +1209,49 @@ contract FunctionsRouter_Fulfill is FunctionsClientRequestSetup { address transmitter = NOP_TRANSMITTER_ADDRESS_1; FunctionsResponse.Commitment memory commitment = s_requestCommitment; + // topic0 (function signature, always checked), topic1 (true), topic2 (true), NOT topic3 (false), and data (true). + bool checkTopic1RequestId = true; + bool checkTopic2SubscriptionId = true; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1RequestId, checkTopic2SubscriptionId, checkTopic3, checkData); + emit RequestProcessed({ + requestId: s_requestId, + subscriptionId: s_subscriptionId, + totalCostJuels: s_adminFee + costWithoutCallback, // NOTE: tx.gasprice is at 0, so no callback gas used + transmitter: transmitter, + resultCode: FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR, + response: response, + err: err, + callbackReturnData: new bytes(0) + }); + + vm.recordLogs(); + + (FunctionsResponse.FulfillResult resultCode, uint96 callbackGasCostJuels) = s_functionsRouter.fulfill( + response, + err, + juelsPerGas, + costWithoutCallback, + transmitter, + commitment + ); + + assertEq(uint(resultCode), uint(FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR)); + assertEq(callbackGasCostJuels, 0); + } + + function test_Fulfill_SuccessFulfilled() public { + // Send as committed Coordinator + vm.stopPrank(); + vm.startPrank(address(s_functionsCoordinator)); + + bytes memory response = bytes("hello world!"); + bytes memory err = new bytes(0); + uint96 juelsPerGas = 0; + uint96 costWithoutCallback = 0; + address transmitter = NOP_TRANSMITTER_ADDRESS_1; + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). bool checkTopic1 = false; bool checkTopic2 = false; @@ -1174,7 +1277,7 @@ contract FunctionsRouter_Fulfill is FunctionsClientRequestSetup { juelsPerGas, costWithoutCallback, transmitter, - commitment + s_requestCommitment ); assertEq(uint(resultCode), uint(FunctionsResponse.FulfillResult.FULFILLED)); diff --git a/contracts/src/v0.8/functions/tests/1_0_0/FunctionsSubscriptions.t.sol b/contracts/src/v0.8/functions/tests/1_0_0/FunctionsSubscriptions.t.sol index 2fb0d4219cc..928ede95bf2 100644 --- a/contracts/src/v0.8/functions/tests/1_0_0/FunctionsSubscriptions.t.sol +++ b/contracts/src/v0.8/functions/tests/1_0_0/FunctionsSubscriptions.t.sol @@ -6,8 +6,12 @@ import {FunctionsRouter} from "../../dev/1_0_0/FunctionsRouter.sol"; import {FunctionsSubscriptions} from "../../dev/1_0_0/FunctionsSubscriptions.sol"; import {FunctionsResponse} from "../../dev/1_0_0/libraries/FunctionsResponse.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; + import {FunctionsRouterSetup, FunctionsOwnerAcceptTermsOfServiceSetup, FunctionsClientSetup, FunctionsSubscriptionSetup, FunctionsClientRequestSetup, FunctionsFulfillmentSetup} from "./Setup.t.sol"; +import "forge-std/Vm.sol"; + // ================================================================ // | Functions Subscriptions | // ================================================================ @@ -15,8 +19,8 @@ import {FunctionsRouterSetup, FunctionsOwnerAcceptTermsOfServiceSetup, Functions contract FunctionsSubscriptions_Constructor_Helper is FunctionsSubscriptions { constructor(address link) FunctionsSubscriptions(link) {} - function getLinkToken() public view returns (address) { - return i_linkToken; + function getLinkToken() public view returns (IERC20) { + return IERC20(i_linkToken); } // overrides @@ -24,6 +28,10 @@ contract FunctionsSubscriptions_Constructor_Helper is FunctionsSubscriptions { return 0; } + function _getSubscriptionDepositDetails() internal pure override returns (uint16, uint72) { + return (0, 0); + } + function _onlySenderThatAcceptedToS() internal override {} function _onlyRouterOwner() internal override {} @@ -42,7 +50,7 @@ contract FunctionsSubscriptions_Constructor is BaseTest { } function test_Constructor_Success() public { - assertEq(s_linkToken, s_subscriptionsHelper.getLinkToken()); + assertEq(address(s_linkToken), address(s_subscriptionsHelper.getLinkToken())); } } @@ -93,6 +101,7 @@ contract FunctionsSubscriptions_OwnerCancelSubscription is FunctionsSubscription function test_OwnerCancelSubscription_SuccessDeletesSubscription() public { s_functionsRouter.ownerCancelSubscription(s_subscriptionId); + // Subscription should no longer exist vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); s_functionsRouter.getSubscription(s_subscriptionId); } @@ -349,6 +358,79 @@ contract FunctionsSubscriptions_GetSubscriptionCount is FunctionsSubscriptionSet } } +/// @notice #getSubscriptionsInRange +contract FunctionsSubscriptions_GetSubscriptionsInRange is FunctionsSubscriptionSetup { + function setUp() public virtual override { + FunctionsSubscriptionSetup.setUp(); + + // Create 2 more subscriptions + /* uint64 subscriptionId2 = */ s_functionsRouter.createSubscription(); + uint64 subscriptionId3 = s_functionsRouter.createSubscription(); + + // Give each one unique state + // #1 subscriptionId for requests, #2 empty, #3 proposedOwner of stranger + s_functionsRouter.proposeSubscriptionOwnerTransfer(subscriptionId3, STRANGER_ADDRESS); + } + + function test_GetSubscriptionsInRange_RevertIfStartIsAfterEnd() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert(FunctionsSubscriptions.InvalidCalldata.selector); + + s_functionsRouter.getSubscriptionsInRange(1, 0); + } + + function test_GetSubscriptionsInRange_RevertIfEndIsAfterLastSubscription() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + uint64 lastSubscriptionId = s_functionsRouter.getSubscriptionCount(); + vm.expectRevert(FunctionsSubscriptions.InvalidCalldata.selector); + s_functionsRouter.getSubscriptionsInRange(1, lastSubscriptionId + 1); + } + + function test_GetSubscriptionsInRange_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + uint64 lastSubscriptionId = s_functionsRouter.getSubscriptionCount(); + FunctionsSubscriptions.Subscription[] memory subscriptions = s_functionsRouter.getSubscriptionsInRange( + s_subscriptionId, + lastSubscriptionId + ); + + assertEq(subscriptions.length, 3); + + // Check subscription 1 + assertEq(subscriptions[0].balance, s_subscriptionInitialFunding); + assertEq(subscriptions[0].owner, OWNER_ADDRESS); + assertEq(subscriptions[0].blockedBalance, 0); + assertEq(subscriptions[0].proposedOwner, address(0)); + assertEq(subscriptions[0].consumers[0], address(s_functionsClient)); + assertEq(subscriptions[0].flags, bytes32(0)); + + // Check subscription 2 + assertEq(subscriptions[1].balance, 0); + assertEq(subscriptions[1].owner, OWNER_ADDRESS); + assertEq(subscriptions[1].blockedBalance, 0); + assertEq(subscriptions[1].proposedOwner, address(0)); + assertEq(subscriptions[1].consumers.length, 0); + assertEq(subscriptions[1].flags, bytes32(0)); + + // Check subscription 3 + assertEq(subscriptions[2].balance, 0); + assertEq(subscriptions[2].owner, OWNER_ADDRESS); + assertEq(subscriptions[2].blockedBalance, 0); + assertEq(subscriptions[2].proposedOwner, address(STRANGER_ADDRESS)); + assertEq(subscriptions[2].consumers.length, 0); + assertEq(subscriptions[2].flags, bytes32(0)); + } +} + /// @notice #getSubscription contract FunctionsSubscriptions_GetSubscription is FunctionsSubscriptionSetup { function test_GetSubscription_Success() public { @@ -807,6 +889,24 @@ contract FunctionsSubscriptions_AddConsumer is FunctionsSubscriptionSetup { s_functionsRouter.addConsumer(s_subscriptionId, address(3)); } + function test_AddConsumer_RevertIfMaximumConsumersAfterConfigUpdate() public { + // Fill Consumers to s_maxConsumersPerSubscription + // Already has one from setup + s_functionsRouter.addConsumer(s_subscriptionId, address(1)); + s_functionsRouter.addConsumer(s_subscriptionId, address(2)); + + // Lower maxConsumersPerSubscription + s_maxConsumersPerSubscription = 1; + FunctionsRouter.Config memory newRouterConfig = getRouterConfig(); + s_functionsRouter.updateConfig(newRouterConfig); + + // .AddConsumer should still revert + vm.expectRevert( + abi.encodeWithSelector(FunctionsSubscriptions.TooManyConsumers.selector, s_maxConsumersPerSubscription) + ); + s_functionsRouter.addConsumer(s_subscriptionId, address(3)); + } + event SubscriptionConsumerAdded(uint64 indexed subscriptionId, address consumer); function test_AddConsumer_Success() public { @@ -881,22 +981,149 @@ contract FunctionsSubscriptions_CancelSubscription is FunctionsSubscriptionSetup event SubscriptionCanceled(uint64 indexed subscriptionId, address fundsRecipient, uint256 fundsAmount); - function test_CancelSubscription_Success() public { + function test_CancelSubscription_SuccessForfeitAllBalanceAsDeposit() public { + // No requests have been completed + assertEq(s_functionsRouter.getConsumer(address(s_functionsClient), s_subscriptionId).completedRequests, 0); + // Subscription balance is less than deposit amount + assertLe(s_functionsRouter.getSubscription(s_subscriptionId).balance, s_subscriptionDepositJuels); + uint256 subscriptionOwnerBalanceBefore = s_linkToken.balanceOf(OWNER_ADDRESS); + uint96 expectedRefund = 0; + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). bool checkTopic1 = false; bool checkTopic2 = false; bool checkTopic3 = false; bool checkData = true; vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); - emit SubscriptionCanceled(s_subscriptionId, OWNER_ADDRESS, s_subscriptionInitialFunding); + emit SubscriptionCanceled(s_subscriptionId, OWNER_ADDRESS, expectedRefund); s_functionsRouter.cancelSubscription(s_subscriptionId, OWNER_ADDRESS); uint256 subscriptionOwnerBalanceAfter = s_linkToken.balanceOf(OWNER_ADDRESS); - assertEq(subscriptionOwnerBalanceBefore + s_subscriptionInitialFunding, subscriptionOwnerBalanceAfter); + assertEq(subscriptionOwnerBalanceBefore + expectedRefund, subscriptionOwnerBalanceAfter); + + // Subscription should no longer exist + vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); + s_functionsRouter.getSubscription(s_subscriptionId); + + // Router owner should have expectedDepositWithheld to withdraw + uint96 expectedDepositWithheld = s_subscriptionInitialFunding; + uint256 balanceBeforeWithdraw = s_linkToken.balanceOf(STRANGER_ADDRESS); + s_functionsRouter.ownerWithdraw(STRANGER_ADDRESS, 0); + uint256 balanceAfterWithdraw = s_linkToken.balanceOf(STRANGER_ADDRESS); + assertEq(balanceBeforeWithdraw + expectedDepositWithheld, balanceAfterWithdraw); + } + + function test_CancelSubscription_SuccessForfeitSomeBalanceAsDeposit() public { + // No requests have been completed + assertEq(s_functionsRouter.getConsumer(address(s_functionsClient), s_subscriptionId).completedRequests, 0); + // Subscription balance is more than deposit amount, double fund the subscription + s_linkToken.transferAndCall(address(s_functionsRouter), s_subscriptionInitialFunding, abi.encode(s_subscriptionId)); + assertGe(s_functionsRouter.getSubscription(s_subscriptionId).balance, s_subscriptionDepositJuels); + + uint256 subscriptionOwnerBalanceBefore = s_linkToken.balanceOf(OWNER_ADDRESS); + + uint96 expectedRefund = (s_subscriptionInitialFunding * 2) - s_subscriptionDepositJuels; + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit SubscriptionCanceled(s_subscriptionId, OWNER_ADDRESS, expectedRefund); + + s_functionsRouter.cancelSubscription(s_subscriptionId, OWNER_ADDRESS); + + uint256 subscriptionOwnerBalanceAfter = s_linkToken.balanceOf(OWNER_ADDRESS); + assertEq(subscriptionOwnerBalanceBefore + expectedRefund, subscriptionOwnerBalanceAfter); + + // Subscription should no longer exist + vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); + s_functionsRouter.getSubscription(s_subscriptionId); + + // Router owner should have expectedDepositWithheld to withdraw + uint96 expectedDepositWithheld = s_subscriptionDepositJuels; + uint256 balanceBeforeWithdraw = s_linkToken.balanceOf(STRANGER_ADDRESS); + s_functionsRouter.ownerWithdraw(STRANGER_ADDRESS, 0); + uint256 balanceAfterWithdraw = s_linkToken.balanceOf(STRANGER_ADDRESS); + assertEq(balanceBeforeWithdraw + expectedDepositWithheld, balanceAfterWithdraw); + } + + function test_CancelSubscription_SuccessRecieveDeposit() public { + // Complete 1 request = subscriptionDepositMinimumRequests + vm.recordLogs(); + bytes32 requestId = s_functionsClient.sendRequest( + s_donId, + "return 'hello world';", + new bytes(0), + new string[](0), + new bytes[](0), + s_subscriptionId, + 5500 + ); + + // Get commitment data from OracleRequest event log + Vm.Log[] memory entries = vm.getRecordedLogs(); + (, , , , , , , FunctionsResponse.Commitment memory commitment) = abi.decode( + entries[0].data, + (address, uint64, address, bytes, uint16, bytes32, uint64, FunctionsResponse.Commitment) + ); + + // Send as transmitter 1 + vm.stopPrank(); + vm.startPrank(NOP_TRANSMITTER_ADDRESS_1); + + // Build report + bytes32[] memory requestIds = new bytes32[](1); + requestIds[0] = requestId; + bytes[] memory results = new bytes[](1); + results[0] = bytes("hello world!"); + bytes[] memory errors = new bytes[](1); + // No error + bytes[] memory onchainMetadata = new bytes[](1); + onchainMetadata[0] = abi.encode(commitment); + bytes[] memory offchainMetadata = new bytes[](1); + // No offchain metadata + bytes memory report = abi.encode(requestIds, results, errors, onchainMetadata, offchainMetadata); + + // Build signers + address[31] memory signers; + signers[0] = NOP_SIGNER_ADDRESS_1; + + // Send report + vm.recordLogs(); + s_functionsCoordinator.callReportWithSigners(report, signers); + + // Get actual cost from RequestProcessed event log + Vm.Log[] memory entries2 = vm.getRecordedLogs(); + (uint96 totalCostJuels, , , , , ) = abi.decode( + entries2[2].data, + (uint96, address, FunctionsResponse.FulfillResult, bytes, bytes, bytes) + ); + + // Return to sending as owner + vm.stopPrank(); + vm.startPrank(OWNER_ADDRESS); + + uint256 subscriptionOwnerBalanceBefore = s_linkToken.balanceOf(OWNER_ADDRESS); + + uint96 expectedRefund = s_subscriptionInitialFunding - totalCostJuels; + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit SubscriptionCanceled(s_subscriptionId, OWNER_ADDRESS, expectedRefund); + + s_functionsRouter.cancelSubscription(s_subscriptionId, OWNER_ADDRESS); + + uint256 subscriptionOwnerBalanceAfter = s_linkToken.balanceOf(OWNER_ADDRESS); + assertEq(subscriptionOwnerBalanceBefore + expectedRefund, subscriptionOwnerBalanceAfter); + // Subscription should no longer exist vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); s_functionsRouter.getSubscription(s_subscriptionId); } diff --git a/contracts/src/v0.8/functions/tests/1_0_0/Setup.t.sol b/contracts/src/v0.8/functions/tests/1_0_0/Setup.t.sol index 361f9b2420a..7a911c3bd60 100644 --- a/contracts/src/v0.8/functions/tests/1_0_0/Setup.t.sol +++ b/contracts/src/v0.8/functions/tests/1_0_0/Setup.t.sol @@ -24,6 +24,8 @@ contract FunctionsRouterSetup is BaseTest { uint72 internal s_adminFee = 100; uint72 internal s_donFee = 100; bytes4 internal s_handleOracleFulfillmentSelector = 0x0ca76175; + uint16 s_subscriptionDepositMinimumRequests = 1; + uint72 s_subscriptionDepositJuels = 11 * 1e18; int256 internal LINK_ETH_RATE = 6000000000000000; @@ -55,14 +57,15 @@ contract FunctionsRouterSetup is BaseTest { adminFee: s_adminFee, handleOracleFulfillmentSelector: s_handleOracleFulfillmentSelector, maxCallbackGasLimits: maxCallbackGasLimits, - gasForCallExactCheck: 5000 + gasForCallExactCheck: 5000, + subscriptionDepositMinimumRequests: s_subscriptionDepositMinimumRequests, + subscriptionDepositJuels: s_subscriptionDepositJuels }); } function getCoordinatorConfig() public view returns (FunctionsBilling.Config memory) { return FunctionsBilling.Config({ - maxCallbackGasLimit: 0, // NOTE: unused , TODO: remove feedStalenessSeconds: 24 * 60 * 60, // 1 day gasOverheadAfterCallback: 44_615, // TODO: update gasOverheadBeforeCallback: 44_615, // TODO: update @@ -196,7 +199,7 @@ contract FunctionsClientRequestSetup is FunctionsSubscriptionSetup { bytes memory secrets; string[] memory args = new string[](0); bytes[] memory bytesArgs = new bytes[](0); - uint32 callbackGasLimit = 5000; + uint32 callbackGasLimit = 5500; vm.recordLogs(); s_requestId = s_functionsClient.sendRequest( @@ -254,7 +257,7 @@ contract FunctionsFulfillmentSetup is FunctionsClientRequestSetup { // Get actual cost from RequestProcessed event log Vm.Log[] memory entries = vm.getRecordedLogs(); (uint96 totalCostJuels, , , , , ) = abi.decode( - entries[1].data, + entries[2].data, (uint96, address, FunctionsResponse.FulfillResult, bytes, bytes, bytes) ); // totalCostJuels = costWithoutCallbackJuels + adminFee + callbackGasCostJuels @@ -265,3 +268,134 @@ contract FunctionsFulfillmentSetup is FunctionsClientRequestSetup { vm.startPrank(OWNER_ADDRESS); } } + +contract FunctionsMultipleFulfillmentsSetup is FunctionsFulfillmentSetup { + bytes32 s_requestId2; + FunctionsResponse.Commitment s_requestCommitment2; + bytes32 s_requestId3; + FunctionsResponse.Commitment s_requestCommitment3; + + function setUp() public virtual override { + FunctionsFulfillmentSetup.setUp(); + + // Make 2 additional requests (1 already complete) + + // *** Request #2 *** + vm.recordLogs(); + s_requestId2 = s_functionsClient.sendRequest( + s_donId, + "return 'hello world';", + new bytes(0), + new string[](0), + new bytes[](0), + s_subscriptionId, + 5500 + ); + + // Get commitment data from OracleRequest event log + Vm.Log[] memory entriesAfterRequest2 = vm.getRecordedLogs(); + (, , , , , , , FunctionsResponse.Commitment memory commitment2) = abi.decode( + entriesAfterRequest2[0].data, + (address, uint64, address, bytes, uint16, bytes32, uint64, FunctionsResponse.Commitment) + ); + s_requestCommitment2 = commitment2; + + // Transmit as transmitter 2 + vm.stopPrank(); + vm.startPrank(NOP_TRANSMITTER_ADDRESS_2); + + // Build report + bytes32[] memory requestIds2 = new bytes32[](1); + requestIds2[0] = s_requestId2; + bytes[] memory results2 = new bytes[](1); + results2[0] = bytes("hello world!"); + bytes[] memory errors2 = new bytes[](1); + // No error + bytes[] memory onchainMetadata2 = new bytes[](1); + onchainMetadata2[0] = abi.encode(s_requestCommitment2); + bytes[] memory offchainMetadata2 = new bytes[](1); + // No offchain metadata + bytes memory report2 = abi.encode(requestIds2, results2, errors2, onchainMetadata2, offchainMetadata2); + + // Build signers + address[31] memory signers2; + signers2[0] = NOP_SIGNER_ADDRESS_2; + + // Send report + vm.recordLogs(); + s_functionsCoordinator.callReportWithSigners(report2, signers2); + + // Get actual cost from RequestProcessed event log + Vm.Log[] memory entriesAfterFulfill2 = vm.getRecordedLogs(); + (uint96 totalCostJuels2, , , , , ) = abi.decode( + entriesAfterFulfill2[2].data, + (uint96, address, FunctionsResponse.FulfillResult, bytes, bytes, bytes) + ); + // totalCostJuels = costWithoutCallbackJuels + adminFee + callbackGasCostJuels + s_fulfillmentCoordinatorBalance += totalCostJuels2 - s_adminFee; + s_fulfillmentRouterOwnerBalance += s_adminFee; + + // Return prank to Owner + vm.stopPrank(); + vm.startPrank(OWNER_ADDRESS); + + // *** Request #3 *** + vm.recordLogs(); + s_requestId3 = s_functionsClient.sendRequest( + s_donId, + "return 'hello world';", + new bytes(0), + new string[](0), + new bytes[](0), + s_subscriptionId, + 5500 + ); + + // Get commitment data from OracleRequest event log + Vm.Log[] memory entriesAfterRequest3 = vm.getRecordedLogs(); + (, , , , , , , FunctionsResponse.Commitment memory commitment3) = abi.decode( + entriesAfterRequest3[0].data, + (address, uint64, address, bytes, uint16, bytes32, uint64, FunctionsResponse.Commitment) + ); + s_requestCommitment3 = commitment3; + + // Transmit as transmitter 3 + vm.stopPrank(); + vm.startPrank(NOP_TRANSMITTER_ADDRESS_3); + + // Build report + bytes32[] memory requestIds3 = new bytes32[](1); + requestIds3[0] = s_requestId3; + bytes[] memory results3 = new bytes[](1); + results3[0] = bytes("hello world!"); + bytes[] memory errors3 = new bytes[](1); + // No error + bytes[] memory onchainMetadata3 = new bytes[](1); + onchainMetadata3[0] = abi.encode(s_requestCommitment3); + bytes[] memory offchainMetadata3 = new bytes[](1); + // No offchain metadata + bytes memory report3 = abi.encode(requestIds3, results3, errors3, onchainMetadata3, offchainMetadata3); + + // Build signers + address[31] memory signers3; + signers3[0] = NOP_SIGNER_ADDRESS_3; + + // Send report + vm.recordLogs(); + s_functionsCoordinator.callReportWithSigners(report3, signers3); + + // Get actual cost from RequestProcessed event log + Vm.Log[] memory entriesAfterFulfill3 = vm.getRecordedLogs(); + (uint96 totalCostJuels3, , , , , ) = abi.decode( + entriesAfterFulfill3[2].data, + (uint96, address, FunctionsResponse.FulfillResult, bytes, bytes, bytes) + ); + + // totalCostJuels = costWithoutCallbackJuels + adminFee + callbackGasCostJuels + s_fulfillmentCoordinatorBalance += totalCostJuels3 - s_adminFee; + + // Return prank to Owner + vm.stopPrank(); + vm.startPrank(OWNER_ADDRESS); + } +} diff --git a/contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsTestHelper.sol b/contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsTestHelper.sol index 57ae6e0bbad..73f10071dbc 100644 --- a/contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsTestHelper.sol +++ b/contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsTestHelper.sol @@ -41,12 +41,6 @@ contract FunctionsTestHelper { storeRequest(r); } - function addSignature(bytes memory signature) public { - FunctionsRequest.Request memory r = s_req; - r.requestSignature = signature; - storeRequest(r); - } - function storeRequest(FunctionsRequest.Request memory r) private { s_req.codeLocation = r.codeLocation; s_req.language = r.language; @@ -54,6 +48,5 @@ contract FunctionsTestHelper { s_req.args = r.args; s_req.secretsLocation = r.secretsLocation; s_req.encryptedSecretsReference = r.encryptedSecretsReference; - s_req.requestSignature = r.requestSignature; } } diff --git a/contracts/src/v0.8/llo-feeds/dev/FeeManager.sol b/contracts/src/v0.8/llo-feeds/dev/FeeManager.sol index 2e5d060dca6..94beaedea38 100644 --- a/contracts/src/v0.8/llo-feeds/dev/FeeManager.sol +++ b/contracts/src/v0.8/llo-feeds/dev/FeeManager.sol @@ -32,16 +32,16 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { uint64 private constant PERCENTAGE_SCALAR = 1e18; /// @notice the LINK token address - address private immutable i_linkAddress; + address public immutable i_linkAddress; /// @notice the native token address - address private immutable i_nativeAddress; + address public immutable i_nativeAddress; /// @notice the proxy address - address private immutable i_proxyAddress; + address public immutable i_proxyAddress; /// @notice the reward manager address - IRewardManager private immutable i_rewardManager; + IRewardManager public immutable i_rewardManager; // @notice the mask to apply to get the report version bytes32 private constant REPORT_VERSION_MASK = 0xffff000000000000000000000000000000000000000000000000000000000000; @@ -259,7 +259,7 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { uint256 linkQuantity; uint256 nativeQuantity; uint256 expiresAt; - (, , , linkQuantity, nativeQuantity, expiresAt) = abi.decode( + (, , , nativeQuantity, linkQuantity, expiresAt) = abi.decode( report, (bytes32, uint32, uint32, uint192, uint192, uint32) ); diff --git a/contracts/src/v0.8/llo-feeds/dev/RewardManager.sol b/contracts/src/v0.8/llo-feeds/dev/RewardManager.sol index 3f7e524c02b..d34a1b6e94d 100644 --- a/contracts/src/v0.8/llo-feeds/dev/RewardManager.sol +++ b/contracts/src/v0.8/llo-feeds/dev/RewardManager.sol @@ -10,7 +10,7 @@ import {Common} from "../../libraries/Common.sol"; import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; /** - * @title FeeManager + * @title RewardManager * @author Michael Fletcher * @author Austin Born * @notice This contract will be used to reward any configured recipients within a pool. Recipients will receive a share of their pool relative to their configured weight. @@ -34,7 +34,7 @@ contract RewardManager is IRewardManager, ConfirmedOwner, TypeAndVersionInterfac bytes32[] public s_registeredPoolIds; // @dev The address for the LINK contract - address private immutable i_linkAddress; + address public immutable i_linkAddress; // The total weight of all RewardRecipients. 1e18 = 100% of the pool fees uint64 private constant PERCENTAGE_SCALAR = 1e18; diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol index 6b8858fc93f..bcc5aa7031a 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol @@ -197,8 +197,8 @@ contract BaseFeeManagerTest is Test { feedId, uint32(0), uint32(0), - uint192(DEFAULT_REPORT_LINK_FEE), uint192(DEFAULT_REPORT_NATIVE_FEE), + uint192(DEFAULT_REPORT_LINK_FEE), uint32(block.timestamp), int192(0) ); @@ -210,8 +210,8 @@ contract BaseFeeManagerTest is Test { feedId, uint32(0), uint32(0), - uint192(DEFAULT_REPORT_LINK_FEE), uint192(DEFAULT_REPORT_NATIVE_FEE), + uint192(DEFAULT_REPORT_LINK_FEE), uint32(block.timestamp), int192(0), int192(0), @@ -230,8 +230,8 @@ contract BaseFeeManagerTest is Test { feedId, uint32(0), uint32(0), - uint192(linkFee), uint192(nativeFee), + uint192(linkFee), uint32(expiry), int192(0), int192(0), diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/BaseVerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/BaseVerifierTest.t.sol index 0f4562944b5..0525e3ed14a 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/BaseVerifierTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/BaseVerifierTest.t.sol @@ -261,7 +261,7 @@ contract BaseTestWithConfiguredVerifierAndFeeManager is BaseTest { bytes32 internal v1ConfigDigest; bytes32 internal v3ConfigDigest; - struct V2Report { + struct V3Report { // The feed ID the report has data for bytes32 feedId; // The time the median value was observed on @@ -321,14 +321,14 @@ contract BaseTestWithConfiguredVerifierAndFeeManager is BaseTest { rewardManager.setFeeManager(address(feeManager)); } - function _encodeReport(V2Report memory report) internal pure returns (bytes memory) { + function _encodeReport(V3Report memory report) internal pure returns (bytes memory) { return abi.encode( report.feedId, report.observationsTimestamp, report.validFromTimestamp, - report.linkFee, report.nativeFee, + report.linkFee, report.expiresAt, report.benchmarkPrice, report.bid, @@ -337,7 +337,7 @@ contract BaseTestWithConfiguredVerifierAndFeeManager is BaseTest { } function _generateEncodedBlobWithQuote( - V2Report memory report, + V3Report memory report, bytes32[3] memory reportContext, Signer[] memory signers, bytes memory quote @@ -371,14 +371,14 @@ contract BaseTestWithConfiguredVerifierAndFeeManager is BaseTest { ); } - function _generateV3Report() internal view returns (V2Report memory) { + function _generateV3Report() internal view returns (V3Report memory) { return - V2Report({ + V3Report({ feedId: FEED_ID_V3, observationsTimestamp: OBSERVATIONS_TIMESTAMP, validFromTimestamp: uint32(block.timestamp), - linkFee: uint192(DEFAULT_REPORT_LINK_FEE), nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE), + linkFee: uint192(DEFAULT_REPORT_LINK_FEE), expiresAt: uint32(block.timestamp), benchmarkPrice: MEDIAN, bid: BID, diff --git a/contracts/src/v0.8/mocks/VRFCoordinatorV2Mock.sol b/contracts/src/v0.8/mocks/VRFCoordinatorV2Mock.sol index 8dfb0dca7c5..a263a3be500 100644 --- a/contracts/src/v0.8/mocks/VRFCoordinatorV2Mock.sol +++ b/contracts/src/v0.8/mocks/VRFCoordinatorV2Mock.sol @@ -5,8 +5,9 @@ pragma solidity ^0.8.4; import "../shared/interfaces/LinkTokenInterface.sol"; import "../interfaces/VRFCoordinatorV2Interface.sol"; import "../vrf/VRFConsumerBaseV2.sol"; +import "../shared/access/ConfirmedOwner.sol"; -contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { +contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface, ConfirmedOwner { uint96 public immutable BASE_FEE; uint96 public immutable GAS_PRICE_LINK; uint16 public immutable MAX_CONSUMERS = 100; @@ -17,6 +18,7 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { error TooManyConsumers(); error InvalidConsumer(); error InvalidRandomWords(); + error Reentrant(); event RandomWordsRequested( bytes32 indexed keyHash, @@ -34,7 +36,13 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { event SubscriptionCanceled(uint64 indexed subId, address to, uint256 amount); event ConsumerAdded(uint64 indexed subId, address consumer); event ConsumerRemoved(uint64 indexed subId, address consumer); + event ConfigSet(); + struct Config { + // Reentrancy protection. + bool reentrancyLock; + } + Config private s_config; uint64 s_currentSubId; uint256 s_nextRequestId = 1; uint256 s_nextPreSeed = 100; @@ -52,9 +60,18 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { } mapping(uint256 => Request) s_requests; /* requestId */ /* request */ - constructor(uint96 _baseFee, uint96 _gasPriceLink) { + constructor(uint96 _baseFee, uint96 _gasPriceLink) ConfirmedOwner(msg.sender) { BASE_FEE = _baseFee; GAS_PRICE_LINK = _gasPriceLink; + setConfig(); + } + + /** + * @notice Sets the configuration of the vrfv2 mock coordinator + */ + function setConfig() public onlyOwner { + s_config = Config({reentrancyLock: false}); + emit ConfigSet(); } function consumerIsAdded(uint64 _subId, address _consumer) public view returns (bool) { @@ -85,7 +102,7 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { * @param _requestId the request to fulfill * @param _consumer the VRF randomness consumer to send the result to */ - function fulfillRandomWords(uint256 _requestId, address _consumer) external { + function fulfillRandomWords(uint256 _requestId, address _consumer) external nonReentrant { fulfillRandomWordsWithOverride(_requestId, _consumer, new uint256[](0)); } @@ -114,7 +131,9 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { VRFConsumerBaseV2 v; bytes memory callReq = abi.encodeWithSelector(v.rawFulfillRandomWords.selector, _requestId, _words); + s_config.reentrancyLock = true; (bool success, ) = _consumer.call{gas: req.callbackGasLimit}(callReq); + s_config.reentrancyLock = false; uint96 payment = uint96(BASE_FEE + ((startGas - gasleft()) * GAS_PRICE_LINK)); if (s_subscriptions[req.subId].balance < payment) { @@ -146,7 +165,7 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { uint16 _minimumRequestConfirmations, uint32 _callbackGasLimit, uint32 _numWords - ) external override onlyValidConsumer(_subId, msg.sender) returns (uint256) { + ) external override nonReentrant onlyValidConsumer(_subId, msg.sender) returns (uint256) { if (s_subscriptions[_subId].owner == address(0)) { revert InvalidSubscription(); } @@ -185,7 +204,7 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { return (s_subscriptions[_subId].balance, 0, s_subscriptions[_subId].owner, s_consumers[_subId]); } - function cancelSubscription(uint64 _subId, address _to) external override onlySubOwner(_subId) { + function cancelSubscription(uint64 _subId, address _to) external override onlySubOwner(_subId) nonReentrant { emit SubscriptionCanceled(_subId, _to, s_subscriptions[_subId].balance); delete (s_subscriptions[_subId]); } @@ -221,7 +240,7 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { function removeConsumer( uint64 _subId, address _consumer - ) external override onlySubOwner(_subId) onlyValidConsumer(_subId, _consumer) { + ) external override onlySubOwner(_subId) onlyValidConsumer(_subId, _consumer) nonReentrant { address[] storage consumers = s_consumers[_subId]; for (uint256 i = 0; i < consumers.length; i++) { if (consumers[i] == _consumer) { @@ -237,7 +256,7 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { function getConfig() external - view + pure returns ( uint16 minimumRequestConfirmations, uint32 maxGasLimit, @@ -250,7 +269,7 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { function getFeeConfig() external - view + pure returns ( uint32 fulfillmentFlatFeeLinkPPMTier1, uint32 fulfillmentFlatFeeLinkPPMTier2, @@ -276,19 +295,26 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { ); } - function getFallbackWeiPerUnitLink() external view returns (int256) { + modifier nonReentrant() { + if (s_config.reentrancyLock) { + revert Reentrant(); + } + _; + } + + function getFallbackWeiPerUnitLink() external pure returns (int256) { return 4000000000000000; // 0.004 Ether } - function requestSubscriptionOwnerTransfer(uint64 _subId, address _newOwner) external pure override { + function requestSubscriptionOwnerTransfer(uint64 /*_subId*/, address /*_newOwner*/) external pure override { revert("not implemented"); } - function acceptSubscriptionOwnerTransfer(uint64 _subId) external pure override { + function acceptSubscriptionOwnerTransfer(uint64 /*_subId*/) external pure override { revert("not implemented"); } - function pendingRequestExists(uint64 subId) public view override returns (bool) { + function pendingRequestExists(uint64 /*subId*/) public pure override returns (bool) { revert("not implemented"); } } diff --git a/contracts/src/v0.8/tests/StreamsLookupUpkeep.sol b/contracts/src/v0.8/tests/StreamsLookupUpkeep.sol index 8cdcf71178d..69729a189e2 100644 --- a/contracts/src/v0.8/tests/StreamsLookupUpkeep.sol +++ b/contracts/src/v0.8/tests/StreamsLookupUpkeep.sol @@ -1,7 +1,7 @@ pragma solidity 0.8.16; import "../automation/interfaces/AutomationCompatibleInterface.sol"; -import "../dev/automation/2_1/interfaces/StreamsLookupCompatibleInterface.sol"; +import "../automation/interfaces/StreamsLookupCompatibleInterface.sol"; import {ArbSys} from "../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; interface IVerifierProxy { @@ -15,15 +15,7 @@ interface IVerifierProxy { } contract StreamsLookupUpkeep is AutomationCompatibleInterface, StreamsLookupCompatibleInterface { - event MercuryPerformEvent( - address indexed sender, - uint256 indexed blockNumber, - bytes v0, - bytes v1, - bytes verifiedV0, - bytes verifiedV1, - bytes ed - ); + event MercuryPerformEvent(address indexed sender, uint256 indexed blockNumber, bytes v0, bytes verifiedV0, bytes ed); ArbSys internal constant ARB_SYS = ArbSys(0x0000000000000000000000000000000000000064); // keep these in sync with verifier proxy in RDD @@ -53,12 +45,13 @@ contract StreamsLookupUpkeep is AutomationCompatibleInterface, StreamsLookupComp initialBlock = 0; counter = 0; useArbBlock = _useArbBlock; - feedParamKey = "feedIdHex"; // feedIDs for v0.3 - timeParamKey = "blockNumber"; // timestamp + feedParamKey = "feedIDs"; // feedIDs for v0.3 + timeParamKey = "timestamp"; // timestamp // search feeds in notion: "Schema and Feed ID Registry" feeds = [ - "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", // ETH / USD in production testnet - "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000" // BTC / USD in production testnet + //"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", // ETH / USD in production testnet v0.2 + //"0x4254432d5553442d415242495452554d2d544553544e45540000000000000000" // BTC / USD in production testnet v0.2 + "0x00028c915d6af0fd66bba2d0fc9405226bca8d6806333121a7d9832103d1563c" // ETH / USD in staging testnet v0.3 ]; staging = _staging; verify = _verify; @@ -99,15 +92,21 @@ contract StreamsLookupUpkeep is AutomationCompatibleInterface, StreamsLookupComp if (!eligible()) { return (false, data); } - uint256 blockNumber; - if (useArbBlock) { - blockNumber = ARB_SYS.arbBlockNumber(); + uint256 timeParam; + if (keccak256(abi.encodePacked(feedParamKey)) == keccak256(abi.encodePacked("feedIdHex"))) { + if (useArbBlock) { + timeParam = ARB_SYS.arbBlockNumber(); + } else { + timeParam = block.number; + } } else { - blockNumber = block.number; + // assume this will be feedIDs for v0.3 + timeParam = block.timestamp; } + // encode ARB_SYS as extraData to verify that it is provided to checkCallback correctly. // in reality, this can be any data or empty - revert StreamsLookup(feedParamKey, feeds, timeParamKey, blockNumber, abi.encodePacked(address(ARB_SYS))); + revert StreamsLookup(feedParamKey, feeds, timeParamKey, timeParam, abi.encodePacked(address(ARB_SYS))); } function performUpkeep(bytes calldata performData) external { @@ -129,13 +128,11 @@ contract StreamsLookupUpkeep is AutomationCompatibleInterface, StreamsLookupComp if (verify) { if (staging) { v0 = STAGING_TESTNET_VERIFIER_PROXY.verify(values[0]); - v1 = STAGING_TESTNET_VERIFIER_PROXY.verify(values[1]); } else { v0 = PRODUCTION_TESTNET_VERIFIER_PROXY.verify(values[0]); - v1 = PRODUCTION_TESTNET_VERIFIER_PROXY.verify(values[1]); } } - emit MercuryPerformEvent(msg.sender, blockNumber, values[0], values[1], v0, v1, extraData); + emit MercuryPerformEvent(msg.sender, blockNumber, values[0], v0, extraData); } function eligible() public view returns (bool) { diff --git a/contracts/src/v0.8/tests/VerifiableLoadBase.sol b/contracts/src/v0.8/tests/VerifiableLoadBase.sol index 2832cb05504..69ebb90cc2b 100644 --- a/contracts/src/v0.8/tests/VerifiableLoadBase.sol +++ b/contracts/src/v0.8/tests/VerifiableLoadBase.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.16; import "../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; -import "../dev/automation/2_1/interfaces/IKeeperRegistryMaster.sol"; +import "../automation/interfaces/2_1/IKeeperRegistryMaster.sol"; import {ArbSys} from "../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; -import "../dev/automation/2_1/AutomationRegistrar2_1.sol"; -import {LogTriggerConfig} from "../dev/automation/2_1/AutomationUtils2_1.sol"; +import "../automation/2_1/AutomationRegistrar2_1.sol"; +import {LogTriggerConfig} from "../automation/2_1/AutomationUtils2_1.sol"; abstract contract VerifiableLoadBase is ConfirmedOwner { error IndexOutOfRange(); diff --git a/contracts/src/v0.8/tests/VerifiableLoadLogTriggerUpkeep.sol b/contracts/src/v0.8/tests/VerifiableLoadLogTriggerUpkeep.sol index 355be69d250..45630fcadc6 100644 --- a/contracts/src/v0.8/tests/VerifiableLoadLogTriggerUpkeep.sol +++ b/contracts/src/v0.8/tests/VerifiableLoadLogTriggerUpkeep.sol @@ -2,8 +2,8 @@ pragma solidity 0.8.16; import "./VerifiableLoadBase.sol"; -import "../dev/automation/2_1/interfaces/ILogAutomation.sol"; -import "../dev/automation/2_1/interfaces/StreamsLookupCompatibleInterface.sol"; +import "../automation/interfaces/ILogAutomation.sol"; +import "../automation/interfaces/StreamsLookupCompatibleInterface.sol"; contract VerifiableLoadLogTriggerUpkeep is VerifiableLoadBase, StreamsLookupCompatibleInterface, ILogAutomation { bool public useMercury; @@ -54,12 +54,20 @@ contract VerifiableLoadLogTriggerUpkeep is VerifiableLoadBase, StreamsLookupComp dummyMap[blockhash(blockNum)] = false; } + uint256 timeParam; + if (keccak256(abi.encodePacked(feedParamKey)) == keccak256(abi.encodePacked("feedIdHex"))) { + timeParam = blockNum; + } else { + // assume this will be feedIDs for v0.3 + timeParam = block.timestamp; + } + if (useMercury) { - revert StreamsLookup(feedParamKey, feedsHex, timeParamKey, blockNum, abi.encode(upkeepId, blockNum, addr)); + revert StreamsLookup(feedParamKey, feedsHex, timeParamKey, timeParam, abi.encode(upkeepId, blockNum, addr)); } // if we don't use mercury, create a perform data which resembles the output of checkCallback - bytes[] memory values = new bytes[](2); + bytes[] memory values = new bytes[](feedsHex.length); bytes memory extraData = abi.encode(upkeepId, blockNum, addr); return (true, abi.encode(values, extraData)); } diff --git a/contracts/src/v0.8/tests/VerifiableLoadStreamsLookupUpkeep.sol b/contracts/src/v0.8/tests/VerifiableLoadStreamsLookupUpkeep.sol index 63dd813e1cd..209c60ca974 100644 --- a/contracts/src/v0.8/tests/VerifiableLoadStreamsLookupUpkeep.sol +++ b/contracts/src/v0.8/tests/VerifiableLoadStreamsLookupUpkeep.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.16; import "./VerifiableLoadBase.sol"; -import "../dev/automation/2_1/interfaces/StreamsLookupCompatibleInterface.sol"; +import "../automation/interfaces/StreamsLookupCompatibleInterface.sol"; contract VerifiableLoadStreamsLookupUpkeep is VerifiableLoadBase, StreamsLookupCompatibleInterface { constructor(AutomationRegistrar2_1 _registrar, bool _useArb) VerifiableLoadBase(_registrar, _useArb) {} @@ -34,7 +34,15 @@ contract VerifiableLoadStreamsLookupUpkeep is VerifiableLoadBase, StreamsLookupC return (false, pData); } - revert StreamsLookup(feedParamKey, feedsHex, timeParamKey, blockNum, abi.encode(upkeepId)); + uint256 timeParam; + if (keccak256(abi.encodePacked(feedParamKey)) == keccak256(abi.encodePacked("feedIdHex"))) { + timeParam = blockNum; + } else { + // assume this will be feedIDs for v0.3 + timeParam = block.timestamp; + } + + revert StreamsLookup(feedParamKey, feedsHex, timeParamKey, timeParam, abi.encode(upkeepId)); } function performUpkeep(bytes calldata performData) external { diff --git a/contracts/test/v0.7/Operator.test.ts b/contracts/test/v0.7/Operator.test.ts index 251ee65a7ae..4af846576b3 100644 --- a/contracts/test/v0.7/Operator.test.ts +++ b/contracts/test/v0.7/Operator.test.ts @@ -1024,9 +1024,8 @@ describe('Operator', () => { .deploy(link.address, operator.address, specId) const paymentAmount = toWei('1') await link.transfer(gasGuzzlingConsumer.address, paymentAmount) - const tx = await gasGuzzlingConsumer.gassyRequestEthereumPrice( - paymentAmount, - ) + const tx = + await gasGuzzlingConsumer.gassyRequestEthereumPrice(paymentAmount) const receipt = await tx.wait() request = decodeRunRequest(receipt.logs?.[3]) }) @@ -1480,9 +1479,8 @@ describe('Operator', () => { .deploy(link.address, operator.address, specId) const paymentAmount = toWei('1') await link.transfer(gasGuzzlingConsumer.address, paymentAmount) - const tx = await gasGuzzlingConsumer.gassyRequestEthereumPrice( - paymentAmount, - ) + const tx = + await gasGuzzlingConsumer.gassyRequestEthereumPrice(paymentAmount) const receipt = await tx.wait() request = decodeRunRequest(receipt.logs?.[3]) }) @@ -2087,9 +2085,8 @@ describe('Operator', () => { .deploy(link.address, operator.address, specId) const paymentAmount = toWei('1') await link.transfer(gasGuzzlingConsumer.address, paymentAmount) - const tx = await gasGuzzlingConsumer.gassyMultiWordRequest( - paymentAmount, - ) + const tx = + await gasGuzzlingConsumer.gassyMultiWordRequest(paymentAmount) const receipt = await tx.wait() request = decodeRunRequest(receipt.logs?.[3]) }) @@ -2604,9 +2601,8 @@ describe('Operator', () => { .deploy(link.address, operator.address, specId) const paymentAmount = toWei('1') await link.transfer(gasGuzzlingConsumer.address, paymentAmount) - const tx = await gasGuzzlingConsumer.gassyMultiWordRequest( - paymentAmount, - ) + const tx = + await gasGuzzlingConsumer.gassyMultiWordRequest(paymentAmount) const receipt = await tx.wait() request = decodeRunRequest(receipt.logs?.[3]) }) diff --git a/contracts/test/v0.8/automation/CanaryUpkeep1_2.test.ts b/contracts/test/v0.8/automation/CanaryUpkeep1_2.test.ts deleted file mode 100644 index c94dffa6b84..00000000000 --- a/contracts/test/v0.8/automation/CanaryUpkeep1_2.test.ts +++ /dev/null @@ -1,225 +0,0 @@ -import { ethers } from 'hardhat' -import { BigNumber, Signer } from 'ethers' -import moment from 'moment' -import { assert } from 'chai' -import { CanaryUpkeep12 as CanaryUpkeep } from '../../../typechain/CanaryUpkeep12' -import { CanaryUpkeep1_2__factory as CanaryUpkeepFactory } from '../../../typechain/factories/CanaryUpkeep1_2__factory' -import { KeeperRegistry1_2 as KeeperRegistry } from '../../../typechain/KeeperRegistry1_2' -import { KeeperRegistry1_2__factory as KeeperRegistryFactory } from '../../../typechain/factories/KeeperRegistry1_2__factory' -import { fastForward, reset } from '../../test-helpers/helpers' -import { getUsers, Personas } from '../../test-helpers/setup' -import { evmRevert } from '../../test-helpers/matchers' - -let personas: Personas -let canaryUpkeep: CanaryUpkeep -let canaryUpkeepFactory: CanaryUpkeepFactory -let owner: Signer -let nelly: Signer -let nancy: Signer -let ned: Signer -let keeperAddresses: string[] -let keeperRegistry: KeeperRegistry -let keeperRegistryFactory: KeeperRegistryFactory - -const defaultInterval = 300 -const paymentPremiumPPB = BigNumber.from(250000000) -const flatFeeMicroLink = BigNumber.from(0) -const blockCountPerTurn = BigNumber.from(3) -const stalenessSeconds = BigNumber.from(43820) -const gasCeilingMultiplier = BigNumber.from(1) -const checkGasLimit = BigNumber.from(20000000) -const fallbackGasPrice = BigNumber.from(200) -const fallbackLinkPrice = BigNumber.from(200000000) -const maxPerformGas = BigNumber.from(5000000) -const minUpkeepSpend = BigNumber.from('1000000000000000000') -const transcoder = ethers.constants.AddressZero -const registrar = ethers.constants.AddressZero -const config = { - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder, - registrar, -} - -describe('CanaryUpkeep1_2', () => { - before(async () => { - personas = (await getUsers()).personas - owner = personas.Default - nelly = personas.Nelly - nancy = personas.Nancy - ned = personas.Ned - keeperAddresses = [ - await nelly.getAddress(), - await nancy.getAddress(), - await ned.getAddress(), - ] - }) - beforeEach(async () => { - // @ts-ignore bug in autogen file - keeperRegistryFactory = await ethers.getContractFactory('KeeperRegistry1_2') - keeperRegistry = await keeperRegistryFactory - .connect(owner) - .deploy( - ethers.constants.AddressZero, - ethers.constants.AddressZero, - ethers.constants.AddressZero, - config, - ) - await keeperRegistry.deployed() - - // @ts-ignore bug in autogen file - canaryUpkeepFactory = await ethers.getContractFactory('CanaryUpkeep1_2') - canaryUpkeep = await canaryUpkeepFactory - .connect(owner) - .deploy(keeperRegistry.address, defaultInterval) - await canaryUpkeep.deployed() - }) - - afterEach(async () => { - await reset() - }) - - describe('setInterval()', () => { - it('allows the owner setting interval', async () => { - await canaryUpkeep.connect(owner).setInterval(400) - const newInterval = await canaryUpkeep.getInterval() - assert.equal( - newInterval.toNumber(), - 400, - 'The interval is not updated correctly', - ) - }) - - it('does not allow someone who is not an owner setting interval', async () => { - await evmRevert( - canaryUpkeep.connect(ned).setInterval(400), - 'Only callable by owner', - ) - }) - }) - - describe('checkUpkeep()', () => { - it('returns true when sufficient time passes', async () => { - await fastForward(moment.duration(6, 'minutes').asSeconds()) - await keeperRegistry.setKeepers(keeperAddresses, keeperAddresses) - const [needsUpkeep] = await canaryUpkeep.checkUpkeep('0x') - assert.isTrue(needsUpkeep) - }) - - it('returns false when insufficient time passes', async () => { - await fastForward(moment.duration(2, 'minutes').asSeconds()) - await keeperRegistry.setKeepers(keeperAddresses, keeperAddresses) - const [needsUpkeep] = await canaryUpkeep.checkUpkeep('0x') - assert.isFalse(needsUpkeep) - }) - - it('returns false when keeper array is empty', async () => { - await fastForward(moment.duration(6, 'minutes').asSeconds()) - const [needsUpkeep] = await canaryUpkeep.checkUpkeep('0x') - assert.isTrue(needsUpkeep) - }) - }) - - describe('performUpkeep()', () => { - it('enforces that transaction origin is the anticipated keeper', async () => { - await keeperRegistry.setKeepers(keeperAddresses, keeperAddresses) - - const oldTimestamp = await canaryUpkeep.connect(nelly).getTimestamp() - const oldKeeperIndex = await canaryUpkeep.connect(nelly).getKeeperIndex() - await fastForward(moment.duration(6, 'minutes').asSeconds()) - await canaryUpkeep.connect(nelly).performUpkeep('0x') - const newKeeperIndex = await canaryUpkeep.connect(nelly).getKeeperIndex() - assert.equal( - newKeeperIndex.toNumber() - oldKeeperIndex.toNumber(), - 1, - 'keeper index needs to increment by 1 after performUpkeep', - ) - - const newTimestamp = await canaryUpkeep.connect(nelly).getTimestamp() - const interval = await canaryUpkeep.connect(nelly).getInterval() - assert.isAtLeast( - newTimestamp.toNumber() - oldTimestamp.toNumber(), - interval.toNumber(), - 'timestamp needs to be updated after performUpkeep', - ) - }) - - it('enforces that keeper index will reset to zero after visiting the last keeper', async () => { - await keeperRegistry.setKeepers(keeperAddresses, keeperAddresses) - - await fastForward(moment.duration(6, 'minutes').asSeconds()) - await canaryUpkeep.connect(nelly).performUpkeep('0x') - - await fastForward(moment.duration(6, 'minutes').asSeconds()) - await canaryUpkeep.connect(nancy).performUpkeep('0x') - - await fastForward(moment.duration(6, 'minutes').asSeconds()) - await canaryUpkeep.connect(ned).performUpkeep('0x') - - const keeperIndex = await canaryUpkeep.connect(ned).getKeeperIndex() - assert.equal( - keeperIndex.toNumber(), - 0, - 'Keeper index is not updated properly', - ) - }) - - it('updates the keeper index after the keepers array is shortened', async () => { - await keeperRegistry.setKeepers(keeperAddresses, keeperAddresses) - - await fastForward(moment.duration(6, 'minutes').asSeconds()) - await canaryUpkeep.connect(nelly).performUpkeep('0x') - - await fastForward(moment.duration(6, 'minutes').asSeconds()) - await canaryUpkeep.connect(nancy).performUpkeep('0x') - - let shortAddresses: string[] = [ - await nelly.getAddress(), - await nancy.getAddress(), - ] - await keeperRegistry.setKeepers(shortAddresses, shortAddresses) - - await fastForward(moment.duration(6, 'minutes').asSeconds()) - await canaryUpkeep.connect(nelly).performUpkeep('0x') - const keeperIndex = await canaryUpkeep.getKeeperIndex() - assert.equal( - keeperIndex.toNumber(), - 1, - 'Keeper index is not updated properly', - ) - }) - - it('reverts if the keeper array is empty', async () => { - await evmRevert( - canaryUpkeep.connect(nelly).performUpkeep('0x'), - `NoKeeperNodes`, - ) - }) - - it('reverts if not enough time has passed', async () => { - await keeperRegistry.setKeepers(keeperAddresses, keeperAddresses) - await fastForward(moment.duration(3, 'minutes').asSeconds()) - await evmRevert( - canaryUpkeep.connect(nelly).performUpkeep('0x'), - `InsufficientInterval`, - ) - }) - - it('reverts if an incorrect keeper tries to perform upkeep', async () => { - await keeperRegistry.setKeepers(keeperAddresses, keeperAddresses) - await fastForward(moment.duration(6, 'minutes').asSeconds()) - await evmRevert( - canaryUpkeep.connect(nancy).performUpkeep('0x'), - 'transaction origin is not the anticipated keeper.', - ) - }) - }) -}) diff --git a/contracts/test/v0.8/automation/CronUpkeep.test.ts b/contracts/test/v0.8/automation/CronUpkeep.test.ts index 755b4494c81..f153345b570 100644 --- a/contracts/test/v0.8/automation/CronUpkeep.test.ts +++ b/contracts/test/v0.8/automation/CronUpkeep.test.ts @@ -321,12 +321,10 @@ describe('CronUpkeep', () => { it('creates jobs with sequential IDs', async () => { const cronString1 = '0 * * * *' const cronString2 = '0 1,2,3 */4 5-6 1-2' - const encodedSpec1 = await cronFactoryContract.encodeCronString( - cronString1, - ) - const encodedSpec2 = await cronFactoryContract.encodeCronString( - cronString2, - ) + const encodedSpec1 = + await cronFactoryContract.encodeCronString(cronString1) + const encodedSpec2 = + await cronFactoryContract.encodeCronString(cronString2) const nextTick1 = ( await cronTestHelper.calculateNextTick(cronString1) ).toNumber() diff --git a/contracts/test/v0.8/automation/IKeeperRegistryMaster.test.ts b/contracts/test/v0.8/automation/IKeeperRegistryMaster.test.ts index a3a18473eca..b29b8add1c2 100644 --- a/contracts/test/v0.8/automation/IKeeperRegistryMaster.test.ts +++ b/contracts/test/v0.8/automation/IKeeperRegistryMaster.test.ts @@ -87,7 +87,7 @@ describe('IKeeperRegistryMaster', () => { const checksum = ethers.utils.id(compositeABIs.join('')) const knownChecksum = fs .readFileSync( - 'src/v0.8/dev/automation/2_1/interfaces/IKeeperRegistryMaster.sol', + 'src/v0.8/automation/interfaces/2_1/IKeeperRegistryMaster.sol', ) .toString() .slice(17, 83) // checksum located at top of file diff --git a/contracts/test/v0.8/automation/KeeperRegistry2_1.test.ts b/contracts/test/v0.8/automation/KeeperRegistry2_1.test.ts index b65f2faea50..2f83c133705 100644 --- a/contracts/test/v0.8/automation/KeeperRegistry2_1.test.ts +++ b/contracts/test/v0.8/automation/KeeperRegistry2_1.test.ts @@ -474,9 +474,8 @@ describe('KeeperRegistry2_1', () => { 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', )) as unknown as MockV3AggregatorFactory upkeepMockFactory = await ethers.getContractFactory('UpkeepMock') - upkeepAutoFunderFactory = await ethers.getContractFactory( - 'UpkeepAutoFunder', - ) + upkeepAutoFunderFactory = + await ethers.getContractFactory('UpkeepAutoFunder') mockArbGasInfoFactory = await ethers.getContractFactory('MockArbGasInfo') mockOVMGasPriceOracleFactory = await ethers.getContractFactory( 'MockOVMGasPriceOracle', diff --git a/contracts/test/v0.8/automation/UpkeepTranscoder3_0.test.ts b/contracts/test/v0.8/automation/UpkeepTranscoder3_0.test.ts index 8bad7f63873..2f0f169ab1f 100644 --- a/contracts/test/v0.8/automation/UpkeepTranscoder3_0.test.ts +++ b/contracts/test/v0.8/automation/UpkeepTranscoder3_0.test.ts @@ -164,9 +164,8 @@ async function deployLegacyRegistry1_2( ) { const mock = await upkeepMockFactory.deploy() // @ts-ignore bug in autogen file - const keeperRegistryFactory = await ethers.getContractFactory( - 'KeeperRegistry1_2', - ) + const keeperRegistryFactory = + await ethers.getContractFactory('KeeperRegistry1_2') transcoder = await upkeepTranscoderFactory.connect(owner).deploy() const legacyRegistry = await keeperRegistryFactory .connect(owner) diff --git a/contracts/test/v0.8/automation/UpkeepTranscoder4_0.test.ts b/contracts/test/v0.8/automation/UpkeepTranscoder4_0.test.ts index e6b74d41bd9..970054893d2 100644 --- a/contracts/test/v0.8/automation/UpkeepTranscoder4_0.test.ts +++ b/contracts/test/v0.8/automation/UpkeepTranscoder4_0.test.ts @@ -140,9 +140,8 @@ const encodeUpkeepV12 = (ids: number[], upkeeps: any[], checkDatas: any[]) => { } async function deployRegistry1_2(): Promise<[BigNumber, KeeperRegistry1_2]> { - const keeperRegistryFactory = await ethers.getContractFactory( - 'KeeperRegistry1_2', - ) + const keeperRegistryFactory = + await ethers.getContractFactory('KeeperRegistry1_2') const registry12 = await keeperRegistryFactory .connect(owner) .deploy(linkToken.address, linkEthFeed.address, gasPriceFeed.address, { diff --git a/contracts/test/v0.8/dev/OptimismCrossDomainForwarder.test.ts b/contracts/test/v0.8/dev/OptimismCrossDomainForwarder.test.ts index 76f0e6ddf0a..3b75b412bfd 100644 --- a/contracts/test/v0.8/dev/OptimismCrossDomainForwarder.test.ts +++ b/contracts/test/v0.8/dev/OptimismCrossDomainForwarder.test.ts @@ -40,9 +40,8 @@ before(async () => { describe('OptimismCrossDomainForwarder', () => { beforeEach(async () => { - crossDomainMessenger = await crossDomainMessengerFactory.deploy( - l1OwnerAddress, - ) + crossDomainMessenger = + await crossDomainMessengerFactory.deploy(l1OwnerAddress) forwarder = await forwarderFactory.deploy( crossDomainMessenger.address, l1OwnerAddress, diff --git a/contracts/test/v0.8/dev/OptimismCrossDomainGovernor.test.ts b/contracts/test/v0.8/dev/OptimismCrossDomainGovernor.test.ts index cedc90ab9a9..9ea425bb995 100644 --- a/contracts/test/v0.8/dev/OptimismCrossDomainGovernor.test.ts +++ b/contracts/test/v0.8/dev/OptimismCrossDomainGovernor.test.ts @@ -46,9 +46,8 @@ before(async () => { describe('OptimismCrossDomainGovernor', () => { beforeEach(async () => { - crossDomainMessenger = await crossDomainMessengerFactory.deploy( - l1OwnerAddress, - ) + crossDomainMessenger = + await crossDomainMessengerFactory.deploy(l1OwnerAddress) governor = await governorFactory.deploy( crossDomainMessenger.address, l1OwnerAddress, diff --git a/contracts/test/v0.8/dev/OptimismSequencerUptimeFeed.test.ts b/contracts/test/v0.8/dev/OptimismSequencerUptimeFeed.test.ts index e6b44041a71..2856568793a 100644 --- a/contracts/test/v0.8/dev/OptimismSequencerUptimeFeed.test.ts +++ b/contracts/test/v0.8/dev/OptimismSequencerUptimeFeed.test.ts @@ -108,8 +108,7 @@ describe('OptimismSequencerUptimeFeed', () => { .updateStatus(true, timestamp.add(200)) // Submit another status update with the same status - const currentBlock = await ethers.provider.getBlockNumber() - const latestBlock = await ethers.provider.getBlock(currentBlock) + const latestBlock = await ethers.provider.getBlock('latest') await expect(tx) .to.emit(optimismUptimeFeed, 'RoundUpdated') diff --git a/contracts/test/v0.8/dev/OptimismValidator.test.ts b/contracts/test/v0.8/dev/OptimismValidator.test.ts index a63780a3f3e..120b1057d14 100644 --- a/contracts/test/v0.8/dev/OptimismValidator.test.ts +++ b/contracts/test/v0.8/dev/OptimismValidator.test.ts @@ -75,8 +75,7 @@ describe('OptimismValidator', () => { it('posts sequencer status when there is not status change', async () => { await optimismValidator.addAccess(eoaValidator.address) - const currentBlockNum = await ethers.provider.getBlockNumber() - const currentBlock = await ethers.provider.getBlock(currentBlockNum) + const currentBlock = await ethers.provider.getBlock('latest') const futureTimestamp = currentBlock.timestamp + 5000 await ethers.provider.send('evm_setNextBlockTimestamp', [futureTimestamp]) @@ -100,8 +99,7 @@ describe('OptimismValidator', () => { it('post sequencer offline', async () => { await optimismValidator.addAccess(eoaValidator.address) - const currentBlockNum = await ethers.provider.getBlockNumber() - const currentBlock = await ethers.provider.getBlock(currentBlockNum) + const currentBlock = await ethers.provider.getBlock('latest') const futureTimestamp = currentBlock.timestamp + 10000 await ethers.provider.send('evm_setNextBlockTimestamp', [futureTimestamp]) diff --git a/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts b/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts index b3446ddb154..b0a2a10b201 100644 --- a/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts +++ b/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts @@ -262,7 +262,7 @@ describe('VRFCoordinatorV2Mock', () => { expect(receipt.events[0].args['success']).to.equal(true) assert( receipt.events[0].args['payment'] - .sub(BigNumber.from('100119017000000000')) + .sub(BigNumber.from('100119403000000000')) .lt(BigNumber.from('10000000000')), ) @@ -315,7 +315,7 @@ describe('VRFCoordinatorV2Mock', () => { expect(receipt.events[0].args['success']).to.equal(true) assert( receipt.events[0].args['payment'] - .sub(BigNumber.from('100119017000000000')) + .sub(BigNumber.from('100120516000000000')) .lt(BigNumber.from('10000000000')), ) diff --git a/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol b/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol index d2f52552e43..47fff7ea900 100644 --- a/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol +++ b/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol @@ -48,6 +48,7 @@ contract TrustedBlockhashStoreTest is BaseTest { assertEq(blockhash(unreachableBlock), 0); // Store blockhash from whitelisted address; + uint256[] memory invalidBlockNums = new uint256[](0); uint256[] memory blockNums = new uint256[](1); blockNums[0] = unreachableBlock; bytes32[] memory blockhashes = new bytes32[](1); @@ -64,9 +65,25 @@ contract TrustedBlockhashStoreTest is BaseTest { vm.expectRevert("Only callable by owner"); bhs.setWhitelist(new address[](0)); - // Should store unreachable blocks via whitelisted address. + // Should not store for a mismatched list of block numbers and hashes. changePrank(LINK_WHALE); + vm.expectRevert(TrustedBlockhashStore.InvalidTrustedBlockhashes.selector); + bhs.storeTrusted(invalidBlockNums, blockhashes, recentBlockNumber, blockhash(recentBlockNumber)); + + // Should store unreachable blocks via whitelisted address. bhs.storeTrusted(blockNums, blockhashes, recentBlockNumber, blockhash(recentBlockNumber)); assertEq(bhs.getBlockhash(unreachableBlock), unreachableBlockhash); + + // Change whitelist. Assert that the old whitelisted address can no longer store, + // but the new one can. + address[] memory newWhitelist = new address[](1); + newWhitelist[0] = LINK_WHALE_2; + bhs.setWhitelist(newWhitelist); + + vm.expectRevert(TrustedBlockhashStore.NotInWhitelist.selector); + bhs.storeTrusted(blockNums, blockhashes, recentBlockNumber, blockhash(recentBlockNumber)); + + changePrank(LINK_WHALE_2); + bhs.storeTrusted(blockNums, blockhashes, recentBlockNumber, blockhash(recentBlockNumber)); } } diff --git a/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Mock.t.sol b/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Mock.t.sol new file mode 100644 index 00000000000..ee184bd145e --- /dev/null +++ b/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Mock.t.sol @@ -0,0 +1,382 @@ +pragma solidity 0.8.6; + +import "../BaseTest.t.sol"; +import {VRF} from "../../../../src/v0.8/vrf/VRF.sol"; +import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; +import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; +import {VRFCoordinatorV2Mock} from "../../../../src/v0.8/mocks/VRFCoordinatorV2Mock.sol"; +import {VRFConsumerV2} from "../../../../src/v0.8/vrf/testhelpers/VRFConsumerV2.sol"; +import {VRFCoordinatorV2Plus} from "../../../../src/v0.8/dev/vrf/VRFCoordinatorV2Plus.sol"; + +contract VRFCoordinatorV2MockTest is BaseTest { + MockLinkToken internal s_linkToken; + MockV3Aggregator internal s_linkEthFeed; + VRFCoordinatorV2Mock internal s_vrfCoordinatorV2Mock; + VRFConsumerV2 internal s_vrfConsumerV2; + address internal s_subOwner = address(1234); + address internal s_randomOwner = address(4567); + + // VRF KeyV2 generated from a node; not sensitive information. + // The secret key used to generate this key is: 10. + bytes internal constant UNCOMPRESSED_PUBLIC_KEY = + hex"a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7893aba425419bc27a3b6c7e693a24c696f794c2ed877a1593cbee53b037368d7"; + bytes internal constant COMPRESSED_PUBLIC_KEY = + hex"a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c701"; + bytes32 internal constant KEY_HASH = hex"9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528"; + + uint32 internal constant DEFAULT_CALLBACK_GAS_LIMIT = 500_000; + uint16 internal constant DEFAULT_REQUEST_CONFIRMATIONS = 3; + uint32 internal constant DEFAULT_NUM_WORDS = 1; + + uint96 pointOneLink = 0.1 ether; + uint96 oneLink = 1 ether; + + event SubscriptionCreated(uint64 indexed subId, address owner); + event SubscriptionFunded(uint64 indexed subId, uint256 oldBalance, uint256 newBalance); + event SubscriptionCanceled(uint64 indexed subId, address to, uint256 amount); + event ConsumerAdded(uint64 indexed subId, address consumer); + event ConsumerRemoved(uint64 indexed subId, address consumer); + event RandomWordsRequested( + bytes32 indexed keyHash, + uint256 requestId, + uint256 preSeed, + uint64 indexed subId, + uint16 minimumRequestConfirmations, + uint32 callbackGasLimit, + uint32 numWords, + address indexed sender + ); + event RandomWordsFulfilled(uint256 indexed requestId, uint256 outputSeed, uint96 payment, bool success); + + function setUp() public override { + BaseTest.setUp(); + + // Fund our users. + vm.roll(1); + vm.deal(OWNER, 10_000 ether); + vm.deal(s_subOwner, 20 ether); + + // Deploy link token and link/eth feed. + s_linkToken = new MockLinkToken(); + s_linkEthFeed = new MockV3Aggregator(18, 500000000000000000); // .5 ETH (good for testing) + + // Deploy coordinator and consumer. + s_vrfCoordinatorV2Mock = new VRFCoordinatorV2Mock( + pointOneLink, + 1_000_000_000 // 0.000000001 LINK per gas + ); + address coordinatorAddr = address(s_vrfCoordinatorV2Mock); + s_vrfConsumerV2 = new VRFConsumerV2(coordinatorAddr, address(s_linkToken)); + + s_vrfCoordinatorV2Mock.setConfig(); + } + + function testCreateSubscription() public { + vm.startPrank(s_subOwner); + vm.expectEmit( + true, // no first indexed topic + false, // no second indexed topic + false, // no third indexed topic + true // check data (target coordinator address) + ); + emit SubscriptionCreated(1, s_subOwner); + uint64 subId = s_vrfCoordinatorV2Mock.createSubscription(); + assertEq(subId, 1); + + (uint96 balance, uint64 reqCount, address owner, address[] memory consumers) = s_vrfCoordinatorV2Mock + .getSubscription(subId); + assertEq(balance, 0); + assertEq(reqCount, 0); + assertEq(owner, s_subOwner); + assertEq(consumers.length, 0); + // s_testCoordinator.fundSubscriptionWithEth{value: 10 ether}(subId); + + // Test if subId increments + vm.expectEmit(true, false, false, true); + emit SubscriptionCreated(2, s_subOwner); + subId = s_vrfCoordinatorV2Mock.createSubscription(); + assertEq(subId, 2); + vm.stopPrank(); + } + + function testAddConsumer() public { + vm.startPrank(s_subOwner); + uint64 subId = s_vrfCoordinatorV2Mock.createSubscription(); + vm.expectEmit(true, false, false, true); + emit ConsumerAdded(subId, address(s_vrfConsumerV2)); + s_vrfCoordinatorV2Mock.addConsumer(subId, address(s_vrfConsumerV2)); + + (uint96 balance, uint64 reqCount, address owner, address[] memory consumers) = s_vrfCoordinatorV2Mock + .getSubscription(subId); + assertEq(balance, 0); + assertEq(reqCount, 0); + assertEq(owner, s_subOwner); + assertEq(consumers.length, 1); + assertEq(consumers[0], address(s_vrfConsumerV2)); + vm.stopPrank(); + } + + // cannot add a consumer to a nonexistent subscription + function testAddConsumerToInvalidSub() public { + vm.startPrank(s_subOwner); + bytes4 reason = bytes4(keccak256("InvalidSubscription()")); + vm.expectRevert(toBytes(reason)); + s_vrfCoordinatorV2Mock.addConsumer(1, address(s_vrfConsumerV2)); + vm.stopPrank(); + } + + // cannot add more than the consumer maximum + function testAddMaxConsumers() public { + vm.startPrank(s_subOwner); + uint64 subId = s_vrfCoordinatorV2Mock.createSubscription(); + // Add 100 consumers + for (uint64 i = 101; i <= 200; ++i) { + s_vrfCoordinatorV2Mock.addConsumer(subId, address(bytes20(keccak256(abi.encodePacked(i))))); + } + // Adding 101th consumer should revert + bytes4 reason = bytes4(keccak256("TooManyConsumers()")); + vm.expectRevert(toBytes(reason)); + s_vrfCoordinatorV2Mock.addConsumer(subId, address(s_vrfConsumerV2)); + vm.stopPrank(); + } + + // can remove a consumer from a subscription + function testRemoveConsumerFromSub() public { + vm.startPrank(s_subOwner); + uint64 subId = s_vrfCoordinatorV2Mock.createSubscription(); + + s_vrfCoordinatorV2Mock.addConsumer(subId, address(s_vrfConsumerV2)); + + (, , , address[] memory consumers) = s_vrfCoordinatorV2Mock.getSubscription(subId); + assertEq(consumers.length, 1); + assertEq(consumers[0], address(s_vrfConsumerV2)); + + vm.expectEmit(true, false, false, true); + emit ConsumerRemoved(subId, address(s_vrfConsumerV2)); + s_vrfCoordinatorV2Mock.removeConsumer(subId, address(s_vrfConsumerV2)); + + vm.stopPrank(); + } + + // cannot remove a consumer from a nonexistent subscription + function testRemoveConsumerFromInvalidSub() public { + vm.startPrank(s_subOwner); + bytes4 reason = bytes4(keccak256("InvalidSubscription()")); + vm.expectRevert(toBytes(reason)); + s_vrfCoordinatorV2Mock.removeConsumer(1, address(s_vrfConsumerV2)); + vm.stopPrank(); + } + + // cannot remove a consumer after it is already removed + function testRemoveConsumerAgain() public { + vm.startPrank(s_subOwner); + uint64 subId = s_vrfCoordinatorV2Mock.createSubscription(); + + s_vrfCoordinatorV2Mock.addConsumer(subId, address(s_vrfConsumerV2)); + + (, , , address[] memory consumers) = s_vrfCoordinatorV2Mock.getSubscription(subId); + assertEq(consumers.length, 1); + assertEq(consumers[0], address(s_vrfConsumerV2)); + + vm.expectEmit(true, false, false, true); + emit ConsumerRemoved(subId, address(s_vrfConsumerV2)); + s_vrfCoordinatorV2Mock.removeConsumer(subId, address(s_vrfConsumerV2)); + + // Removing consumer again should revert with InvalidConsumer + bytes4 reason = bytes4(keccak256("InvalidConsumer()")); + vm.expectRevert(toBytes(reason)); + s_vrfCoordinatorV2Mock.removeConsumer(subId, address(s_vrfConsumerV2)); + vm.stopPrank(); + } + + // can fund a subscription + function testFundSubscription() public { + vm.startPrank(s_subOwner); + uint64 subId = s_vrfCoordinatorV2Mock.createSubscription(); + + vm.expectEmit(true, false, false, true); + emit SubscriptionFunded(subId, 0, oneLink); + s_vrfCoordinatorV2Mock.fundSubscription(subId, oneLink); + + (uint96 balance, , , address[] memory consumers) = s_vrfCoordinatorV2Mock.getSubscription(subId); + assertEq(balance, oneLink); + assertEq(consumers.length, 0); + vm.stopPrank(); + } + + // cannot fund a nonexistent subscription + function testFundInvalidSubscription() public { + vm.startPrank(s_subOwner); + + // Removing consumer again should revert with InvalidConsumer + bytes4 reason = bytes4(keccak256("InvalidSubscription()")); + vm.expectRevert(toBytes(reason)); + s_vrfCoordinatorV2Mock.removeConsumer(1, address(s_vrfConsumerV2)); + + vm.stopPrank(); + } + + // can cancel a subscription + function testCancelSubscription() public { + vm.startPrank(s_subOwner); + uint64 subId = s_vrfCoordinatorV2Mock.createSubscription(); + + s_vrfCoordinatorV2Mock.fundSubscription(subId, oneLink); + + vm.expectEmit(true, false, false, true); + emit SubscriptionCanceled(subId, s_subOwner, oneLink); + s_vrfCoordinatorV2Mock.cancelSubscription(subId, s_subOwner); + + bytes4 reason = bytes4(keccak256("InvalidSubscription()")); + vm.expectRevert(toBytes(reason)); + s_vrfCoordinatorV2Mock.getSubscription(subId); + + vm.stopPrank(); + } + + // fails to fulfill without being a valid consumer + function testRequestRandomWordsInvalidConsumer() public { + vm.startPrank(s_subOwner); + uint64 subId = s_vrfCoordinatorV2Mock.createSubscription(); + + s_vrfCoordinatorV2Mock.fundSubscription(subId, oneLink); + + bytes4 reason = bytes4(keccak256("InvalidConsumer()")); + vm.expectRevert(toBytes(reason)); + s_vrfCoordinatorV2Mock.requestRandomWords( + KEY_HASH, + subId, + DEFAULT_REQUEST_CONFIRMATIONS, + DEFAULT_CALLBACK_GAS_LIMIT, + DEFAULT_NUM_WORDS + ); + vm.stopPrank(); + } + + // fails to fulfill with insufficient funds + function testRequestRandomWordsInsufficientFunds() public { + vm.startPrank(s_subOwner); + uint64 subId = s_vrfCoordinatorV2Mock.createSubscription(); + + address consumerAddr = address(s_vrfConsumerV2); + s_vrfCoordinatorV2Mock.addConsumer(subId, address(s_vrfConsumerV2)); + + vm.stopPrank(); + + vm.startPrank(consumerAddr); + + vm.expectEmit(true, false, false, true); + emit RandomWordsRequested( + KEY_HASH, + 1, + 100, + subId, + DEFAULT_REQUEST_CONFIRMATIONS, + DEFAULT_CALLBACK_GAS_LIMIT, + DEFAULT_NUM_WORDS, + address(s_subOwner) + ); + uint256 reqId = s_vrfCoordinatorV2Mock.requestRandomWords( + KEY_HASH, + subId, + DEFAULT_REQUEST_CONFIRMATIONS, + DEFAULT_CALLBACK_GAS_LIMIT, + DEFAULT_NUM_WORDS + ); + + bytes4 reason = bytes4(keccak256("InsufficientBalance()")); + vm.expectRevert(toBytes(reason)); + s_vrfCoordinatorV2Mock.fulfillRandomWords(reqId, consumerAddr); + + vm.stopPrank(); + } + + // can request and fulfill [ @skip-coverage ] + function testRequestRandomWordsHappyPath() public { + vm.startPrank(s_subOwner); + uint64 subId = s_vrfCoordinatorV2Mock.createSubscription(); + + s_vrfCoordinatorV2Mock.fundSubscription(subId, oneLink); + + address consumerAddr = address(s_vrfConsumerV2); + s_vrfCoordinatorV2Mock.addConsumer(subId, consumerAddr); + + vm.expectEmit(true, false, false, true); + emit RandomWordsRequested( + KEY_HASH, + 1, + 100, + subId, + DEFAULT_REQUEST_CONFIRMATIONS, + DEFAULT_CALLBACK_GAS_LIMIT, + DEFAULT_NUM_WORDS, + address(s_subOwner) + ); + uint256 reqId = s_vrfConsumerV2.requestRandomness( + KEY_HASH, + subId, + DEFAULT_REQUEST_CONFIRMATIONS, + DEFAULT_CALLBACK_GAS_LIMIT, + DEFAULT_NUM_WORDS + ); + + vm.expectEmit(true, false, false, true); + emit RandomWordsFulfilled(reqId, 1, 100090236000000000, true); + s_vrfCoordinatorV2Mock.fulfillRandomWords(reqId, consumerAddr); + + vm.stopPrank(); + } + + // Correctly allows for user override of fulfillRandomWords [ @skip-coverage ] + function testRequestRandomWordsUserOverride() public { + vm.startPrank(s_subOwner); + uint64 subId = s_vrfCoordinatorV2Mock.createSubscription(); + + s_vrfCoordinatorV2Mock.fundSubscription(subId, oneLink); + + address consumerAddr = address(s_vrfConsumerV2); + s_vrfCoordinatorV2Mock.addConsumer(subId, consumerAddr); + + vm.expectEmit(true, false, false, true); + emit RandomWordsRequested( + KEY_HASH, + 1, + 100, + subId, + DEFAULT_REQUEST_CONFIRMATIONS, + DEFAULT_CALLBACK_GAS_LIMIT, + 2, + address(s_subOwner) + ); + uint256 reqId = s_vrfConsumerV2.requestRandomness( + KEY_HASH, + subId, + DEFAULT_REQUEST_CONFIRMATIONS, + DEFAULT_CALLBACK_GAS_LIMIT, + 2 + ); + + bytes4 reason = bytes4(keccak256("InvalidRandomWords()")); + vm.expectRevert(toBytes(reason)); + uint256[] memory words1 = new uint256[](5); + words1[0] = 1; + words1[1] = 2; + words1[2] = 3; + words1[3] = 4; + words1[4] = 5; + s_vrfCoordinatorV2Mock.fulfillRandomWordsWithOverride(reqId, consumerAddr, uint256[](words1)); + + vm.expectEmit(true, false, false, true); + uint256[] memory words2 = new uint256[](2); + words1[0] = 2533; + words1[1] = 1768; + emit RandomWordsFulfilled(reqId, 1, 100072314000000000, true); + s_vrfCoordinatorV2Mock.fulfillRandomWordsWithOverride(reqId, consumerAddr, words2); + + vm.stopPrank(); + } + + function toBytes(bytes4 _data) public pure returns (bytes memory) { + return abi.encodePacked(_data); + } +} diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol b/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol index 4d4669d988f..2bfedcc8c1f 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol +++ b/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol @@ -99,7 +99,8 @@ contract VRFV2Plus is BaseTest { ); } - function testSetConfig() public { + // TODO: Fix this test after make foundry-refresh (JIRA ticket VRF-618) + function skipped_testSetConfig() public { // Should setConfig successfully. setConfig(basicFeeConfig); (uint16 minConfs, uint32 gasLimit, ) = s_testCoordinator.getRequestConfig(); @@ -115,7 +116,8 @@ contract VRFV2Plus is BaseTest { s_testCoordinator.setConfig(0, 2_500_000, 1, 50_000, 0, basicFeeConfig); } - function testRegisterProvingKey() public { + // TODO: Fix this test after make foundry-refresh + function skipped_testRegisterProvingKey() public { // Should set the proving key successfully. registerProvingKey(); (, , bytes32[] memory keyHashes) = s_testCoordinator.getRequestConfig(); @@ -239,7 +241,8 @@ contract VRFV2Plus is BaseTest { bool success ); - function testRequestAndFulfillRandomWordsNative() public { + // TODO: Fix this test after make foundry-refresh (JIRA ticket VRF-618) + function skipped_testRequestAndFulfillRandomWordsNative() public { uint32 requestBlock = 10; vm.roll(requestBlock); s_testConsumer.createSubscriptionAndFund(0); @@ -356,7 +359,8 @@ contract VRFV2Plus is BaseTest { assertApproxEqAbs(ethBalanceAfter, ethBalanceBefore - 120_000, 10_000); } - function testRequestAndFulfillRandomWordsLINK() public { + // TODO: Fix this test after make foundry-refresh (JIRA ticket VRF-618) + function skipped_testRequestAndFulfillRandomWordsLINK() public { uint32 requestBlock = 20; vm.roll(requestBlock); s_linkToken.transfer(address(s_testConsumer), 10 ether); diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper.t.sol b/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper.t.sol index 4b506bb8c50..33bc72998f8 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper.t.sol +++ b/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper.t.sol @@ -5,6 +5,7 @@ import {VRF} from "../../../../src/v0.8/vrf/VRF.sol"; import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; import {ExposedVRFCoordinatorV2Plus} from "../../../../src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2Plus.sol"; +import {VRFV2PlusWrapperConsumerBase} from "../../../../src/v0.8/dev/vrf/VRFV2PlusWrapperConsumerBase.sol"; import {VRFV2PlusWrapperConsumerExample} from "../../../../src/v0.8/dev/vrf/testhelpers/VRFV2PlusWrapperConsumerExample.sol"; import {VRFCoordinatorV2Plus} from "../../../../src/v0.8/dev/vrf/VRFCoordinatorV2Plus.sol"; import {VRFV2PlusWrapper} from "../../../../src/v0.8/dev/vrf/VRFV2PlusWrapper.sol"; @@ -70,6 +71,21 @@ contract VRFV2PlusWrapperTest is BaseTest { vrfKeyHash, // keyHash 10 // max number of words ); + ( + , + , + , + uint32 _wrapperGasOverhead, + uint32 _coordinatorGasOverhead, + uint8 _wrapperPremiumPercentage, + bytes32 _keyHash, + uint8 _maxNumWords + ) = s_wrapper.getConfig(); + assertEq(_wrapperGasOverhead, wrapperGasOverhead); + assertEq(_coordinatorGasOverhead, coordinatorGasOverhead); + assertEq(0, _wrapperPremiumPercentage); + assertEq(vrfKeyHash, _keyHash); + assertEq(10, _maxNumWords); } event RandomWordsRequested( @@ -84,11 +100,42 @@ contract VRFV2PlusWrapperTest is BaseTest { address indexed sender ); + function testSetLinkAndLinkEthFeed() public { + VRFV2PlusWrapper wrapper = new VRFV2PlusWrapper(address(0), address(0), address(s_testCoordinator)); + + // Set LINK and LINK/ETH feed on wrapper. + wrapper.setLINK(address(s_linkToken)); + wrapper.setLinkEthFeed(address(s_linkEthFeed)); + assertEq(address(wrapper.s_link()), address(s_linkToken)); + assertEq(address(wrapper.s_linkEthFeed()), address(s_linkEthFeed)); + + // Revert for subsequent assignment. + vm.expectRevert(VRFV2PlusWrapper.LinkAlreadySet.selector); + wrapper.setLINK(address(s_linkToken)); + + // Consumer can set LINK token. + VRFV2PlusWrapperConsumerExample consumer = new VRFV2PlusWrapperConsumerExample(address(0), address(wrapper)); + consumer.setLinkToken(address(s_linkToken)); + + // Revert for subsequent assignment. + vm.expectRevert(VRFV2PlusWrapperConsumerBase.LINKAlreadySet.selector); + consumer.setLinkToken(address(s_linkToken)); + } + function testRequestAndFulfillRandomWordsNativeWrapper() public { // Fund subscription. s_testCoordinator.fundSubscriptionWithEth{value: 10 ether}(s_wrapper.SUBSCRIPTION_ID()); vm.deal(address(s_consumer), 10 ether); + // Get type and version. + assertEq(s_wrapper.typeAndVersion(), "VRFV2Wrapper 1.0.0"); + + // Cannot make request while disabled. + s_wrapper.disable(); + vm.expectRevert("wrapper is disabled"); + s_consumer.makeRequestNative(500_000, 0, 1); + s_wrapper.enable(); + // Request randomness from wrapper. uint32 callbackGasLimit = 1_000_000; vm.expectEmit(true, true, true, true); @@ -114,7 +161,11 @@ contract VRFV2PlusWrapperTest is BaseTest { (uint256 paid, bool fulfilled, bool native) = s_consumer.s_requests(requestId); uint32 expectedPaid = callbackGasLimit + wrapperGasOverhead + coordinatorGasOverhead; + uint256 wrapperNativeCostEstimate = s_wrapper.estimateRequestPriceNative(callbackGasLimit, tx.gasprice); + uint256 wrapperCostCalculation = s_wrapper.calculateRequestPriceNative(callbackGasLimit); assertEq(paid, expectedPaid); + assertEq(uint256(paid), wrapperNativeCostEstimate); + assertEq(wrapperNativeCostEstimate, wrapperCostCalculation); assertEq(fulfilled, false); assertEq(native, true); assertEq(address(s_consumer).balance, 10 ether - expectedPaid); @@ -129,6 +180,13 @@ contract VRFV2PlusWrapperTest is BaseTest { (, bool nowFulfilled, uint256[] memory storedWords) = s_consumer.getRequestStatus(requestId); assertEq(nowFulfilled, true); assertEq(storedWords[0], 123); + + // Withdraw funds from wrapper. + changePrank(LINK_WHALE); + uint256 priorWhaleBalance = LINK_WHALE.balance; + s_wrapper.withdrawNative(LINK_WHALE, paid); + assertEq(LINK_WHALE.balance, priorWhaleBalance + paid); + assertEq(address(s_wrapper).balance, 0); } function testRequestAndFulfillRandomWordsLINKWrapper() public { @@ -162,7 +220,11 @@ contract VRFV2PlusWrapperTest is BaseTest { // Assert that the request was made correctly. (uint256 paid, bool fulfilled, bool native) = s_consumer.s_requests(requestId); uint32 expectedPaid = (callbackGasLimit + wrapperGasOverhead + coordinatorGasOverhead) * 2; + uint256 wrapperCostEstimate = s_wrapper.estimateRequestPrice(callbackGasLimit, tx.gasprice); + uint256 wrapperCostCalculation = s_wrapper.calculateRequestPrice(callbackGasLimit); assertEq(paid, expectedPaid); // 1_030_000 * 2 for link/eth ratio + assertEq(uint256(paid), wrapperCostEstimate); + assertEq(wrapperCostEstimate, wrapperCostCalculation); assertEq(fulfilled, false); assertEq(native, false); assertEq(s_linkToken.balanceOf(address(s_consumer)), 10 ether - expectedPaid); @@ -177,5 +239,12 @@ contract VRFV2PlusWrapperTest is BaseTest { (, bool nowFulfilled, uint256[] memory storedWords) = s_consumer.getRequestStatus(requestId); assertEq(nowFulfilled, true); assertEq(storedWords[0], 456); + + // Withdraw funds from wrapper. + changePrank(LINK_WHALE); + uint256 priorWhaleBalance = s_linkToken.balanceOf(LINK_WHALE); + s_wrapper.withdraw(LINK_WHALE, paid); + assertEq(s_linkToken.balanceOf(LINK_WHALE), priorWhaleBalance + paid); + assertEq(s_linkToken.balanceOf(address(s_wrapper)), 0); } } diff --git a/contracts/test/v0.8/functions/v0/FunctionsOracle.test.ts b/contracts/test/v0.8/functions/v0/FunctionsOracle.test.ts index ae44e1b037e..921c60bfc8f 100644 --- a/contracts/test/v0.8/functions/v0/FunctionsOracle.test.ts +++ b/contracts/test/v0.8/functions/v0/FunctionsOracle.test.ts @@ -351,9 +351,8 @@ describe('FunctionsOracle', () => { }) it('#estimateCost correctly estimates cost [ @skip-coverage ]', async () => { - const [subscriptionBalanceBefore] = await registry.getSubscription( - subscriptionId, - ) + const [subscriptionBalanceBefore] = + await registry.getSubscription(subscriptionId) const request = await client .connect(roles.oracleNode) @@ -376,9 +375,8 @@ describe('FunctionsOracle', () => { .withArgs(requestId, transmitter) .to.emit(registry, 'BillingEnd') - const [subscriptionBalanceAfter] = await registry.getSubscription( - subscriptionId, - ) + const [subscriptionBalanceAfter] = + await registry.getSubscription(subscriptionId) const feeData = await ethers.provider.getFeeData() const estimatedCost = await client.estimateJuelCost( diff --git a/contracts/test/v0.8/functions/v1/Functions.test.ts b/contracts/test/v0.8/functions/v1/Functions.test.ts index b0128b90204..981b3227073 100644 --- a/contracts/test/v0.8/functions/v1/Functions.test.ts +++ b/contracts/test/v0.8/functions/v1/Functions.test.ts @@ -41,7 +41,6 @@ describe('FunctionsTestHelper', () => { 'addSecretsReference', 'addTwoArgs', 'addEmptyArgs', - 'addSignature', ]), ).to.equal(true) }) @@ -170,29 +169,4 @@ describe('FunctionsTestHelper', () => { await expect(ctr.addEmptyArgs()).to.be.revertedWith('EmptyArgs()') }) }) - - describe('#addSignature', () => { - it('emits CBOR encoded request with js source and signature', async () => { - const signatureHex = 'aabbccddeeff' - const js = 'function run(args, responses) {}' - await ctr.initializeRequestForInlineJavaScript(js) - await ctr.addSignature('0x' + signatureHex) - const tx = await ctr.closeEvent() - const [payload] = await parseRequestDataEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual( - { - ...decoded, - language: decoded.language.toNumber(), - codeLocation: decoded.codeLocation.toNumber(), - }, - { - language: 0, - codeLocation: 0, - source: js, - requestSignature: Buffer.from(signatureHex, 'hex'), - }, - ) - }) - }) }) diff --git a/contracts/test/v0.8/functions/v1/FunctionsSubscriptions.test.ts b/contracts/test/v0.8/functions/v1/FunctionsSubscriptions.test.ts index e2f0372be15..86cfb9dd5fc 100644 --- a/contracts/test/v0.8/functions/v1/FunctionsSubscriptions.test.ts +++ b/contracts/test/v0.8/functions/v1/FunctionsSubscriptions.test.ts @@ -370,6 +370,9 @@ describe('Functions Router - Subscriptions', () => { ).to.be.revertedWith(`MustBeSubscriptionOwner()`) }) it('can cancel', async function () { + const strangerBalanceBefore = await contracts.linkToken.balanceOf( + roles.strangerAddress, + ) await contracts.linkToken .connect(roles.subOwner) .transferAndCall( @@ -383,11 +386,13 @@ describe('Functions Router - Subscriptions', () => { .cancelSubscription(subId, roles.strangerAddress), ) .to.emit(contracts.router, 'SubscriptionCanceled') - .withArgs(subId, roles.strangerAddress, BigNumber.from('1000')) + .withArgs(subId, roles.strangerAddress, BigNumber.from('0')) const strangerBalance = await contracts.linkToken.balanceOf( roles.strangerAddress, ) - expect(strangerBalance.toString()).to.equal('1000000000000001000') + expect(strangerBalance.toString()).to.equal( + strangerBalanceBefore.toString(), + ) await expect( contracts.router.connect(roles.subOwner).getSubscription(subId), ).to.be.revertedWith('InvalidSubscription') @@ -493,7 +498,7 @@ describe('Functions Router - Subscriptions', () => { .connect(roles.subOwner) .cancelSubscription(subId, roles.strangerAddress) }, - BigNumber.from('-1000'), + BigNumber.from('0'), ], ] for (const [fn, expectedBalanceChange] of balanceChangingFns) { diff --git a/contracts/test/v0.8/functions/v1/utils.ts b/contracts/test/v0.8/functions/v1/utils.ts index a7a89871f32..0973a5cd845 100644 --- a/contracts/test/v0.8/functions/v1/utils.ts +++ b/contracts/test/v0.8/functions/v1/utils.ts @@ -77,6 +77,8 @@ export type FunctionsRouterConfig = { handleOracleFulfillmentSelector: string maxCallbackGasLimits: number[] gasForCallExactCheck: number + subscriptionDepositMinimumRequests: number + subscriptionDepositJuels: BigNumber } export const functionsRouterConfig: FunctionsRouterConfig = { maxConsumersPerSubscription: 100, @@ -84,9 +86,10 @@ export const functionsRouterConfig: FunctionsRouterConfig = { handleOracleFulfillmentSelector: '0x0ca76175', maxCallbackGasLimits: [300_000, 500_000, 1_000_000], gasForCallExactCheck: 5000, + subscriptionDepositMinimumRequests: 10, + subscriptionDepositJuels: BigNumber.from('1000000000000000000'), } export type CoordinatorConfig = { - maxCallbackGasLimit: number feedStalenessSeconds: number gasOverheadBeforeCallback: number gasOverheadAfterCallback: number @@ -98,7 +101,6 @@ export type CoordinatorConfig = { } const fallbackNativePerUnitLink = 5000000000000000 export const coordinatorConfig: CoordinatorConfig = { - maxCallbackGasLimit: 1_000_000, feedStalenessSeconds: 86_400, gasOverheadBeforeCallback: 44_615, gasOverheadAfterCallback: 44_615, diff --git a/core/chains/chain_kv.go b/core/chains/chain_kv.go index 6224be1c5c3..5094f2885e5 100644 --- a/core/chains/chain_kv.go +++ b/core/chains/chain_kv.go @@ -17,7 +17,6 @@ type ChainsKV[T types.ChainService] struct { var ErrNoSuchChainID = errors.New("chain id does not exist") func NewChainsKV[T types.ChainService](cs map[string]T) *ChainsKV[T] { - return &ChainsKV[T]{ chains: cs, } diff --git a/core/chains/chain_kv_test.go b/core/chains/chain_kv_test.go index f226b6f38be..a30de3090b8 100644 --- a/core/chains/chain_kv_test.go +++ b/core/chains/chain_kv_test.go @@ -89,19 +89,13 @@ func (s *testChainService) HealthReport() map[string]error { return map[string]error{} } -// Implement updated [loop.Relay] interface funcs in preparation for BCF-2441 -// TODO update this comment after BCF-2441 is done +// Implement [types.ChainService] interface func (s *testChainService) GetChainStatus(ctx context.Context) (stat types.ChainStatus, err error) { return } func (s *testChainService) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []types.NodeStatus, nextPageToken string, total int, err error) { return } - func (s *testChainService) Transact(ctx context.Context, from string, to string, amount *big.Int, balanceCheck bool) error { return nil } - -func (s *testChainService) SendTx(ctx context.Context, from string, to string, amount *big.Int, balanceCheck bool) error { - return nil -} diff --git a/core/chains/config.go b/core/chains/config.go index 0111521b304..3556c33a785 100644 --- a/core/chains/config.go +++ b/core/chains/config.go @@ -2,9 +2,6 @@ package chains import ( "errors" - - "github.com/smartcontractkit/chainlink-relay/pkg/logger" - "github.com/smartcontractkit/chainlink-relay/pkg/types" ) var ( @@ -13,26 +10,7 @@ var ( ErrNotFound = errors.New("not found") ) -type ChainConfigs interface { - Chains(offset, limit int, ids ...string) ([]types.ChainStatus, int, error) -} - -type NodeConfigs[I ID, N Node] interface { - Node(name string) (N, error) - Nodes(chainID I) (nodes []N, err error) - - NodeStatus(name string) (types.NodeStatus, error) -} - -// Configs holds chain and node configurations. -// TODO: BCF-2605 audit the usage of this interface and potentially remove it -type Configs[I ID, N Node] interface { - ChainConfigs - NodeConfigs[I, N] -} - // ChainOpts holds options for configuring a Chain -type ChainOpts[I ID, N Node] interface { +type ChainOpts interface { Validate() error - ConfigsAndLogger() (Configs[I, N], logger.Logger) } diff --git a/core/chains/config_v2.go b/core/chains/config_v2.go deleted file mode 100644 index 414179d8495..00000000000 --- a/core/chains/config_v2.go +++ /dev/null @@ -1,86 +0,0 @@ -package chains - -import "github.com/smartcontractkit/chainlink-relay/pkg/types" - -type configsV2AsV1[I ID, N Node] struct { - *configChains - *configNodes[I, N] -} - -type ConfigsV2[I ID, N Node] interface { - chainConfigsV2 - nodeConfigsV2[I, N] -} - -// NewConfigs returns a [Configs] backed by [ConfigsV2]. -func NewConfigs[I ID, N Node](cfgs ConfigsV2[I, N]) Configs[I, N] { - return configsV2AsV1[I, N]{ - newConfigChains[I](cfgs), - newConfigNodes[I, N](cfgs), - } -} - -// configChains is a generic, immutable Configs for chains. -type configChains struct { - v2 chainConfigsV2 -} - -type chainConfigsV2 interface { - Chains(ids ...string) ([]types.ChainStatus, error) -} - -// newConfigChains returns a chains backed by chains. -func newConfigChains[I ID](d chainConfigsV2) *configChains { - return &configChains{v2: d} -} - -func (o *configChains) Chains(offset, limit int, ids ...string) (chains []types.ChainStatus, count int, err error) { - chains, err = o.v2.Chains(ids...) - if err != nil { - return - } - count = len(chains) - if offset < len(chains) { - chains = chains[offset:] - } else { - chains = nil - } - if limit > 0 && len(chains) > limit { - chains = chains[:limit] - } - return -} - -type nodeConfigsV2[I ID, N Node] interface { - Node(name string) (N, error) - Nodes(chainID I) ([]N, error) - - NodeStatus(name string) (types.NodeStatus, error) - NodeStatuses(chainIDs ...string) (nodes []types.NodeStatus, err error) -} - -// configNodes is a generic Configs for nodes. -type configNodes[I ID, N Node] struct { - nodeConfigsV2[I, N] -} - -func newConfigNodes[I ID, N Node](d nodeConfigsV2[I, N]) *configNodes[I, N] { - return &configNodes[I, N]{d} -} - -func (o *configNodes[I, N]) NodeStatusesPaged(offset, limit int, chainIDs ...string) (nodes []types.NodeStatus, count int, err error) { - nodes, err = o.nodeConfigsV2.NodeStatuses(chainIDs...) - if err != nil { - return - } - count = len(nodes) - if offset < len(nodes) { - nodes = nodes[offset:] - } else { - nodes = nil - } - if limit > 0 && len(nodes) > limit { - nodes = nodes[:limit] - } - return -} diff --git a/core/chains/cosmos/chain.go b/core/chains/cosmos/chain.go index 48f4c2f8854..6323806cc1f 100644 --- a/core/chains/cosmos/chain.go +++ b/core/chains/cosmos/chain.go @@ -25,9 +25,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/cosmostxm" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/types" "github.com/smartcontractkit/chainlink/v2/core/chains/internal" "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -56,7 +56,6 @@ type ChainOpts struct { DB *sqlx.DB KeyStore loop.Keystore EventBroadcaster pg.EventBroadcaster - Configs types.Configs } func (o *ChainOpts) Validate() (err error) { @@ -78,21 +77,14 @@ func (o *ChainOpts) Validate() (err error) { if o.EventBroadcaster == nil { err = multierr.Append(err, required("EventBroadcaster")) } - if o.Configs == nil { - err = multierr.Append(err, required("Configs")) - } return } -func (o *ChainOpts) ConfigsAndLogger() (chains.Configs[string, db.Node], logger.Logger) { - return o.Configs, o.Logger -} - func NewChain(cfg *CosmosConfig, opts ChainOpts) (adapters.Chain, error) { if !cfg.IsEnabled() { return nil, fmt.Errorf("cannot create new chain with ID %s, the chain is disabled", *cfg.ChainID) } - c, err := newChain(*cfg.ChainID, cfg, opts.DB, opts.KeyStore, opts.QueryConfig, opts.EventBroadcaster, opts.Configs, opts.Logger) + c, err := newChain(*cfg.ChainID, cfg, opts.DB, opts.KeyStore, opts.QueryConfig, opts.EventBroadcaster, opts.Logger) if err != nil { return nil, err } @@ -103,21 +95,17 @@ var _ adapters.Chain = (*chain)(nil) type chain struct { utils.StartStopOnce - id string - cfg *CosmosConfig - txm *cosmostxm.Txm - // TODO remove this dep after BCF-2441 - // cfs implements the loop.Relayer interface that will be removed - cfgs types.Configs + id string + cfg *CosmosConfig + txm *cosmostxm.Txm lggr logger.Logger } -func newChain(id string, cfg *CosmosConfig, db *sqlx.DB, ks loop.Keystore, logCfg pg.QConfig, eb pg.EventBroadcaster, cfgs types.Configs, lggr logger.Logger) (*chain, error) { +func newChain(id string, cfg *CosmosConfig, db *sqlx.DB, ks loop.Keystore, logCfg pg.QConfig, eb pg.EventBroadcaster, lggr logger.Logger) (*chain, error) { lggr = logger.With(lggr, "cosmosChainID", id) var ch = chain{ id: id, cfg: cfg, - cfgs: cfgs, lggr: logger.Named(lggr, "Chain"), } tc := func() (cosmosclient.ReaderWriter, error) { @@ -126,7 +114,7 @@ func newChain(id string, cfg *CosmosConfig, db *sqlx.DB, ks loop.Keystore, logCf gpe := cosmosclient.NewMustGasPriceEstimator([]cosmosclient.GasPricesEstimator{ cosmosclient.NewClosureGasPriceEstimator(func() (map[string]sdk.DecCoin, error) { return map[string]sdk.DecCoin{ - cfg.FeeToken(): sdk.NewDecCoinFromDec(cfg.FeeToken(), cfg.FallbackGasPrice()), + cfg.GasToken(): sdk.NewDecCoinFromDec(cfg.GasToken(), cfg.FallbackGasPrice()), }, nil }), }, lggr) @@ -143,6 +131,10 @@ func (c *chain) ID() string { return c.id } +func (c *chain) ChainID() relay.ChainID { + return relay.ChainID(c.id) +} + func (c *chain) Config() coscfg.Config { return c.cfg } @@ -159,23 +151,23 @@ func (c *chain) Reader(name string) (cosmosclient.Reader, error) { func (c *chain) getClient(name string) (cosmosclient.ReaderWriter, error) { var node db.Node if name == "" { // Any node - nodes, err := c.cfgs.Nodes(c.id) + nodes, err := c.cfg.ListNodes() if err != nil { - return nil, errors.Wrap(err, "failed to get nodes") + return nil, fmt.Errorf("failed to list nodes: %w", err) } if len(nodes) == 0 { return nil, errors.New("no nodes available") } nodeIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(nodes)))) if err != nil { - return nil, errors.Wrap(err, "could not generate a random node index") + return nil, fmt.Errorf("could not generate a random node index: %w", err) } node = nodes[nodeIndex.Int64()] } else { // Named node var err error - node, err = c.cfgs.Node(name) + node, err = c.cfg.GetNode(name) if err != nil { - return nil, errors.Wrapf(err, "failed to get node named %s", name) + return nil, fmt.Errorf("failed to get node named %s: %w", name, err) } if node.CosmosChainID != c.id { return nil, fmt.Errorf("failed to create client for chain %s with node %s: wrong chain id %s", c.id, name, node.CosmosChainID) @@ -183,7 +175,7 @@ func (c *chain) getClient(name string) (cosmosclient.ReaderWriter, error) { } client, err := cosmosclient.NewClient(c.id, node.TendermintURL, DefaultRequestTimeout, logger.Named(c.lggr, "Client."+name)) if err != nil { - return nil, errors.Wrap(err, "failed to create client") + return nil, fmt.Errorf("failed to create client: %w", err) } c.lggr.Debugw("Created client", "name", node.Name, "tendermint-url", node.TendermintURL) return client, nil @@ -251,7 +243,7 @@ func (c *chain) listNodeStatuses(start, end int) ([]relaytypes.NodeStatus, int, } nodes := c.cfg.Nodes[start:end] for _, node := range nodes { - stat, err := nodeStatus(node, c.id) + stat, err := nodeStatus(node, c.ChainID()) if err != nil { return stats, total, err } diff --git a/core/chains/cosmos/config.go b/core/chains/cosmos/config.go index 878de2130b6..fda791d0dc2 100644 --- a/core/chains/cosmos/config.go +++ b/core/chains/cosmos/config.go @@ -16,7 +16,7 @@ import ( relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/types" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) @@ -77,119 +77,9 @@ func (cs *CosmosConfigs) SetFrom(fs *CosmosConfigs) (err error) { return } -func (cs CosmosConfigs) Chains(ids ...string) (r []relaytypes.ChainStatus, err error) { - for _, ch := range cs { - if ch == nil { - continue - } - if len(ids) > 0 { - var match bool - for _, id := range ids { - if id == *ch.ChainID { - match = true - break - } - } - if !match { - continue - } - } - ch2 := relaytypes.ChainStatus{ - ID: *ch.ChainID, - Enabled: ch.IsEnabled(), - } - ch2.Config, err = ch.TOMLString() - if err != nil { - return - } - r = append(r, ch2) - } - return -} - -func (cs CosmosConfigs) Node(name string) (n db.Node, err error) { - for i := range cs { - for _, n := range cs[i].Nodes { - if n.Name != nil && *n.Name == name { - return legacyNode(n, *cs[i].ChainID), nil - } - } - } - err = fmt.Errorf("node %s: %w", name, chains.ErrNotFound) - return -} - -func (cs CosmosConfigs) nodes(chainID string) (ns CosmosNodes) { - for _, c := range cs { - if *c.ChainID == chainID { - return c.Nodes - } - } - return nil -} - -func (cs CosmosConfigs) Nodes(chainID string) (ns []db.Node, err error) { - nodes := cs.nodes(chainID) - if nodes == nil { - err = fmt.Errorf("no nodes: chain %s: %w", chainID, chains.ErrNotFound) - return - } - for _, n := range nodes { - if n == nil { - continue - } - ns = append(ns, legacyNode(n, chainID)) - } - return - -} - -func (cs CosmosConfigs) NodeStatus(name string) (n relaytypes.NodeStatus, err error) { - for i := range cs { - for _, n := range cs[i].Nodes { - if n.Name != nil && *n.Name == name { - return nodeStatus(n, *cs[i].ChainID) - } - } - } - err = fmt.Errorf("node %s: %w", name, chains.ErrNotFound) - return -} - -func (cs CosmosConfigs) NodeStatuses(chainIDs ...string) (ns []relaytypes.NodeStatus, err error) { - if len(chainIDs) == 0 { - for i := range cs { - for _, n := range cs[i].Nodes { - if n == nil { - continue - } - n2, err := nodeStatus(n, *cs[i].ChainID) - if err != nil { - return nil, err - } - ns = append(ns, n2) - } - } - return - } - for _, id := range chainIDs { - for _, n := range cs.nodes(id) { - if n == nil { - continue - } - n2, err := nodeStatus(n, id) - if err != nil { - return nil, err - } - ns = append(ns, n2) - } - } - return -} - -func nodeStatus(n *coscfg.Node, chainID string) (relaytypes.NodeStatus, error) { +func nodeStatus(n *coscfg.Node, id relay.ChainID) (relaytypes.NodeStatus, error) { var s relaytypes.NodeStatus - s.ChainID = chainID + s.ChainID = id s.Name = *n.Name b, err := toml.Marshal(n) if err != nil { @@ -271,8 +161,8 @@ func setFromChain(c, f *coscfg.Chain) { if f.FallbackGasPrice != nil { c.FallbackGasPrice = f.FallbackGasPrice } - if f.FeeToken != nil { - c.FeeToken = f.FeeToken + if f.GasToken != nil { + c.GasToken = f.GasToken } if f.GasLimitMultiplier != nil { c.GasLimitMultiplier = f.GasLimitMultiplier @@ -335,8 +225,8 @@ func (c *CosmosConfig) FallbackGasPrice() sdk.Dec { return sdkDecFromDecimal(c.Chain.FallbackGasPrice) } -func (c *CosmosConfig) FeeToken() string { - return *c.Chain.FeeToken +func (c *CosmosConfig) GasToken() string { + return *c.Chain.GasToken } func (c *CosmosConfig) GasLimitMultiplier() float64 { @@ -364,6 +254,19 @@ func sdkDecFromDecimal(d *decimal.Decimal) sdk.Dec { return sdk.NewDecFromBigIntWithPrec(i.BigInt(), sdk.Precision) } -func NewConfigs(cfgs chains.ConfigsV2[string, db.Node]) types.Configs { - return chains.NewConfigs(cfgs) +func (c *CosmosConfig) GetNode(name string) (db.Node, error) { + for _, n := range c.Nodes { + if *n.Name == name { + return legacyNode(n, *c.ChainID), nil + } + } + return db.Node{}, fmt.Errorf("%w: node %q", chains.ErrNotFound, name) +} + +func (c *CosmosConfig) ListNodes() ([]db.Node, error) { + var allNodes []db.Node + for _, n := range c.Nodes { + allNodes = append(allNodes, legacyNode(n, *c.ChainID)) + } + return allNodes, nil } diff --git a/core/chains/cosmos/config_test.go b/core/chains/cosmos/config_test.go index 3446e7bcb01..54f91a13620 100644 --- a/core/chains/cosmos/config_test.go +++ b/core/chains/cosmos/config_test.go @@ -1,11 +1,16 @@ package cosmos import ( + "reflect" "testing" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/shopspring/decimal" "github.com/stretchr/testify/assert" + + coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" + "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" + "github.com/smartcontractkit/chainlink-relay/pkg/utils" ) func Test_sdkDecFromDecimal(t *testing.T) { @@ -23,3 +28,69 @@ func Test_sdkDecFromDecimal(t *testing.T) { }) } } + +func TestCosmosConfig_GetNode(t *testing.T) { + type fields struct { + ChainID *string + Nodes CosmosNodes + } + type args struct { + name string + } + tests := []struct { + name string + fields fields + args args + want db.Node + wantErr bool + }{ + { + name: "not found", + args: args{ + name: "not a node", + }, + fields: fields{Nodes: CosmosNodes{}}, + want: db.Node{}, + wantErr: true, + }, + { + name: "success", + args: args{ + name: "node", + }, + fields: fields{ + ChainID: ptr("chainID"), + Nodes: []*coscfg.Node{ + &coscfg.Node{ + Name: ptr("node"), + TendermintURL: &utils.URL{}, + }, + }}, + want: db.Node{ + CosmosChainID: "chainID", + Name: "node", + TendermintURL: "", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &CosmosConfig{ + Nodes: tt.fields.Nodes, + ChainID: tt.fields.ChainID, + } + got, err := c.GetNode(tt.args.name) + if (err != nil) != tt.wantErr { + t.Errorf("CosmosConfig.GetNode() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("CosmosConfig.GetNode() = %v, want %v", got, tt.want) + } + }) + } +} + +func ptr[T any](t T) *T { + return &t +} diff --git a/core/chains/cosmos/cosmostxm/txm.go b/core/chains/cosmos/cosmostxm/txm.go index 84118b9381b..de741e8934f 100644 --- a/core/chains/cosmos/cosmostxm/txm.go +++ b/core/chains/cosmos/cosmostxm/txm.go @@ -500,7 +500,7 @@ func (txm *Txm) GetMsgs(ids ...int64) (adapters.Msgs, error) { // GasPrice returns the gas price from the estimator in the configured fee token. func (txm *Txm) GasPrice() (sdk.DecCoin, error) { prices := txm.gpe.GasPrices() - gasPrice, ok := prices[txm.cfg.FeeToken()] + gasPrice, ok := prices[txm.cfg.GasToken()] if !ok { return sdk.DecCoin{}, errors.New("unexpected empty gas price") } diff --git a/core/chains/cosmos/cosmostxm/txm_internal_test.go b/core/chains/cosmos/cosmostxm/txm_internal_test.go index 17eeb74421a..2f0b4fda06f 100644 --- a/core/chains/cosmos/cosmostxm/txm_internal_test.go +++ b/core/chains/cosmos/cosmostxm/txm_internal_test.go @@ -78,15 +78,15 @@ func TestTxm(t *testing.T) { logCfg := pgtest.NewQConfig(true) chainID := cosmostest.RandomChainID() two := int64(2) - feeToken := "ucosm" + gasToken := "ucosm" cfg := &cosmos.CosmosConfig{Chain: coscfg.Chain{ MaxMsgsPerBatch: &two, - FeeToken: &feeToken, + GasToken: &gasToken, }} cfg.SetDefaults() gpe := cosmosclient.NewMustGasPriceEstimator([]cosmosclient.GasPricesEstimator{ cosmosclient.NewFixedGasPriceEstimator(map[string]cosmostypes.DecCoin{ - cfg.FeeToken(): cosmostypes.NewDecCoinFromDec(cfg.FeeToken(), cosmostypes.MustNewDecFromStr("0.01")), + cfg.GasToken(): cosmostypes.NewDecCoinFromDec(cfg.GasToken(), cosmostypes.MustNewDecFromStr("0.01")), }, lggr.(logger.SugaredLogger), ), diff --git a/core/chains/cosmos/cosmostxm/txm_test.go b/core/chains/cosmos/cosmostxm/txm_test.go index 9966ff44a5b..a3322ed2744 100644 --- a/core/chains/cosmos/cosmostxm/txm_test.go +++ b/core/chains/cosmos/cosmostxm/txm_test.go @@ -38,7 +38,7 @@ func TestTxm_Integration(t *testing.T) { chainID := cosmostest.RandomChainID() cosmosChain := coscfg.Chain{} cosmosChain.SetDefaults() - fallbackGasPrice := sdk.NewDecCoinFromDec(*cosmosChain.FeeToken, sdk.MustNewDecFromStr("0.01")) + fallbackGasPrice := sdk.NewDecCoinFromDec(*cosmosChain.GasToken, sdk.MustNewDecFromStr("0.01")) chainConfig := cosmos.CosmosConfig{ChainID: &chainID, Enabled: ptr(true), Chain: cosmosChain} cfg, db := heavyweight.FullTestDBNoFixturesV2(t, "cosmos_txm", func(c *chainlink.Config, s *chainlink.Secrets) { c.Cosmos = cosmos.CosmosConfigs{&chainConfig} @@ -47,7 +47,7 @@ func TestTxm_Integration(t *testing.T) { logCfg := pgtest.NewQConfig(true) gpe := cosmosclient.NewMustGasPriceEstimator([]cosmosclient.GasPricesEstimator{ cosmosclient.NewFixedGasPriceEstimator(map[string]sdk.DecCoin{ - *cosmosChain.FeeToken: fallbackGasPrice, + *cosmosChain.GasToken: fallbackGasPrice, }, lggr.(logger.SugaredLogger), ), @@ -59,7 +59,7 @@ func TestTxm_Integration(t *testing.T) { ks := keystore.New(db, utils.FastScryptParams, lggr, pgtest.NewQConfig(true)) zeConfig := sdk.GetConfig() fmt.Println(zeConfig) - accounts, testdir, tendermintURL := cosmosclient.SetupLocalCosmosNode(t, chainID, *cosmosChain.FeeToken) + accounts, testdir, tendermintURL := cosmosclient.SetupLocalCosmosNode(t, chainID, *cosmosChain.GasToken) tc, err := cosmosclient.NewClient(chainID, tendermintURL, cosmos.DefaultRequestTimeout, lggr) require.NoError(t, err) @@ -77,8 +77,8 @@ func TestTxm_Integration(t *testing.T) { require.NoError(t, err) an, sn, err := tc.Account(accounts[0].Address) require.NoError(t, err) - resp, err := tc.SignAndBroadcast([]sdk.Msg{banktypes.NewMsgSend(accounts[0].Address, transmitterID, sdk.NewCoins(sdk.NewInt64Coin(*cosmosChain.FeeToken, 100000)))}, - an, sn, gpe.GasPrices()[*cosmosChain.FeeToken], accounts[0].PrivateKey, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) + resp, err := tc.SignAndBroadcast([]sdk.Msg{banktypes.NewMsgSend(accounts[0].Address, transmitterID, sdk.NewCoins(sdk.NewInt64Coin(*cosmosChain.GasToken, 100000)))}, + an, sn, gpe.GasPrices()[*cosmosChain.GasToken], accounts[0].PrivateKey, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) tx, success := cosmosclient.AwaitTxCommitted(t, tc, resp.TxResponse.TxHash) require.True(t, success) require.Equal(t, types.CodeTypeOK, tx.TxResponse.Code) @@ -86,7 +86,7 @@ func TestTxm_Integration(t *testing.T) { // TODO: find a way to pull this test artifact from // the chainlink-cosmos repo instead of copying it to cores testdata - contractID := cosmosclient.DeployTestContract(t, tendermintURL, chainID, *cosmosChain.FeeToken, accounts[0], cosmosclient.Account{ + contractID := cosmosclient.DeployTestContract(t, tendermintURL, chainID, *cosmosChain.GasToken, accounts[0], cosmosclient.Account{ Name: "transmitter", PrivateKey: cosmostxm.NewKeyWrapper(keystoreAdapter, transmitterAddress), Address: transmitterID, diff --git a/core/chains/cosmos/relayer_adapter.go b/core/chains/cosmos/relayer_adapter.go index 899eae01951..ffe4181ceb0 100644 --- a/core/chains/cosmos/relayer_adapter.go +++ b/core/chains/cosmos/relayer_adapter.go @@ -37,8 +37,7 @@ type LoopRelayerChain struct { } func NewLoopRelayerChain(r *pkgcosmos.Relayer, s adapters.Chain) *LoopRelayerChain { - - ra := relay.NewRelayerAdapter(r, s) + ra := relay.NewRelayerServerAdapter(r, s) return &LoopRelayerChain{ Relayer: ra, chain: s, diff --git a/core/chains/cosmos/types/types.go b/core/chains/cosmos/types/types.go index 082ffe1b4cc..69b086a9706 100644 --- a/core/chains/cosmos/types/types.go +++ b/core/chains/cosmos/types/types.go @@ -1,17 +1,5 @@ package types -import ( - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" - - "github.com/smartcontractkit/chainlink/v2/core/chains" -) - -// Configs manages cosmos chains and nodes. -type Configs interface { - chains.ChainConfigs - chains.NodeConfigs[string, db.Node] -} - // NewNode defines a new node to create. type NewNode struct { Name string `json:"name"` diff --git a/core/chains/evm/chain.go b/core/chains/evm/chain.go index 524e84fd51b..6a948a4cdd0 100644 --- a/core/chains/evm/chain.go +++ b/core/chains/evm/chain.go @@ -6,7 +6,6 @@ import ( "fmt" "math/big" "net/url" - "sync" "time" "go.uber.org/multierr" @@ -18,8 +17,6 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/types" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -57,13 +54,6 @@ type Chain interface { BalanceMonitor() monitor.BalanceMonitor LogPoller() logpoller.LogPoller GasEstimator() gas.EvmFeeEstimator - - // TODO remove after BCF-2441 - // This funcs are implemented now in preparation the interface change, which is expected - // to absorb these definitions into [types.ChainService] - GetChainStatus(ctx context.Context) (relaytypes.ChainStatus, error) - ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []relaytypes.NodeStatus, nextPageToken string, total int, err error) - Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error } var ( @@ -77,20 +67,21 @@ type LegacyChains struct { *chains.ChainsKV[Chain] dflt Chain - cfgs evmtypes.Configs + cfgs toml.EVMConfigs } // LegacyChainContainer is container for EVM chains. // //go:generate mockery --quiet --name LegacyChainContainer --output ./mocks/ --case=underscore type LegacyChainContainer interface { - SetDefault(Chain) - Default() (Chain, error) Get(id string) (Chain, error) Len() int List(ids ...string) ([]Chain, error) Slice() []Chain + // BCF-2516: this is only used for EVMORM. When we delete that + // we can promote/move the needed funcs from it to LegacyChainContainer + // so instead of EVMORM().XYZ() we'd have something like legacyChains.XYZ() ChainNodeConfigs() evmtypes.Configs } @@ -99,7 +90,7 @@ var _ LegacyChainContainer = &LegacyChains{} func NewLegacyChains(m map[string]Chain, evmCfgs toml.EVMConfigs) *LegacyChains { return &LegacyChains{ ChainsKV: chains.NewChainsKV[Chain](m), - cfgs: chains.NewConfigs[utils.Big, evmtypes.Node](evmCfgs), + cfgs: evmCfgs, } } @@ -107,27 +98,14 @@ func (c *LegacyChains) ChainNodeConfigs() evmtypes.Configs { return c.cfgs } -// TODO BCR-2510 this may not be needed if EVM is not enabled by default -func (c *LegacyChains) SetDefault(dflt Chain) { - c.dflt = dflt -} - -func (c *LegacyChains) Default() (Chain, error) { - if c.dflt == nil { - return nil, fmt.Errorf("no default chain specified") - } - return c.dflt, nil -} - // backward compatibility. // eth keys are represented as multiple types in the code base; -// *big.Int, string, and int64. this lead to special 'default' handling -// of nil big.Int and empty string. +// *big.Int, string, and int64. // // TODO BCF-2507 unify the type system func (c *LegacyChains) Get(id string) (Chain, error) { if id == nilBigInt.String() || id == emptyString { - return c.Default() + return nil, fmt.Errorf("invalid chain id requested: %q", id) } return c.ChainsKV.Get(id) } @@ -180,9 +158,6 @@ type RelayerConfig struct { MailMon *utils.MailboxMonitor GasEstimator gas.EvmFeeEstimator - init sync.Once - operationalConfigs evmtypes.Configs - // TODO BCF-2513 remove test code from the API // Gen-functions are useful for dependency injection by tests GenEthClient func(*big.Int) client.Client @@ -193,14 +168,6 @@ type RelayerConfig struct { GenGasEstimator func(*big.Int) gas.EvmFeeEstimator } -func (r *RelayerConfig) EVMConfigs() evmtypes.Configs { - if r.operationalConfigs == nil { - r.init.Do(func() { - r.operationalConfigs = chains.NewConfigs[utils.Big, evmtypes.Node](r.AppConfig.EVMConfigs()) - }) - } - return r.operationalConfigs -} func NewTOMLChain(ctx context.Context, chain *toml.EVMConfig, opts ChainRelayExtenderConfig) (Chain, error) { chainID := chain.ChainID l := opts.Logger.With("evmChainID", chainID.String()) @@ -500,9 +467,5 @@ func (opts *ChainRelayExtenderConfig) Check() error { return errors.New("config must be non-nil") } - opts.init.Do(func() { - opts.operationalConfigs = chains.NewConfigs[utils.Big, evmtypes.Node](opts.AppConfig.EVMConfigs()) - }) - return nil } diff --git a/core/chains/evm/chain_test.go b/core/chains/evm/chain_test.go index 3ae8a74bfe2..41f498b3e76 100644 --- a/core/chains/evm/chain_test.go +++ b/core/chains/evm/chain_test.go @@ -5,13 +5,10 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/mocks" configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestLegacyChains(t *testing.T) { @@ -27,29 +24,4 @@ func TestLegacyChains(t *testing.T) { assert.NoError(t, err) assert.Equal(t, c, got) - require.NotPanics(t, func() { - l = evm.NewLegacyChains(m, nil) - assert.NotNil(t, l.ChainNodeConfigs()) - }) -} - -func TestRelayConfigInit(t *testing.T) { - appCfg := configtest.NewGeneralConfig(t, nil) - rCfg := evm.RelayerConfig{ - AppConfig: appCfg, - } - - evmCfg := rCfg.EVMConfigs() - assert.NotNil(t, evmCfg) - - // test lazy init is done only once - // note this kind of swapping should never happen in prod - appCfg2 := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].ChainID = utils.NewBig(big.NewInt(27)) - }) - rCfg.AppConfig = appCfg2 - - newEvmCfg := rCfg.EVMConfigs() - assert.NotNil(t, newEvmCfg) - assert.Equal(t, evmCfg, newEvmCfg) } diff --git a/core/chains/evm/config/chain_scoped.go b/core/chains/evm/config/chain_scoped.go index b2046559b0d..7971a18d4db 100644 --- a/core/chains/evm/config/chain_scoped.go +++ b/core/chains/evm/config/chain_scoped.go @@ -15,9 +15,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" ) -func NewTOMLChainScopedConfig(genCfg gencfg.AppConfig, tomlConfig *toml.EVMConfig, lggr logger.Logger) *ChainScoped { +func NewTOMLChainScopedConfig(appCfg gencfg.AppConfig, tomlConfig *toml.EVMConfig, lggr logger.Logger) *ChainScoped { return &ChainScoped{ - AppConfig: genCfg, + AppConfig: appCfg, evmConfig: &evmConfig{c: tomlConfig}, lggr: lggr} } diff --git a/core/chains/evm/config/mocks/chain_scoped_config.go b/core/chains/evm/config/mocks/chain_scoped_config.go index bf84164cd3e..b8347f6e4bb 100644 --- a/core/chains/evm/config/mocks/chain_scoped_config.go +++ b/core/chains/evm/config/mocks/chain_scoped_config.go @@ -3,8 +3,6 @@ package mocks import ( - big "math/big" - config "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" coreconfig "github.com/smartcontractkit/chainlink/v2/core/config" @@ -100,22 +98,6 @@ func (_m *ChainScopedConfig) Database() coreconfig.Database { return r0 } -// DefaultChainID provides a mock function with given fields: -func (_m *ChainScopedConfig) DefaultChainID() *big.Int { - ret := _m.Called() - - var r0 *big.Int - if rf, ok := ret.Get(0).(func() *big.Int); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - return r0 -} - // EVM provides a mock function with given fields: func (_m *ChainScopedConfig) EVM() config.EVM { ret := _m.Called() @@ -160,22 +142,6 @@ func (_m *ChainScopedConfig) EVMRPCEnabled() bool { return r0 } -// Explorer provides a mock function with given fields: -func (_m *ChainScopedConfig) Explorer() coreconfig.Explorer { - ret := _m.Called() - - var r0 coreconfig.Explorer - if rf, ok := ret.Get(0).(func() coreconfig.Explorer); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.Explorer) - } - } - - return r0 -} - // Feature provides a mock function with given fields: func (_m *ChainScopedConfig) Feature() coreconfig.Feature { ret := _m.Called() diff --git a/core/chains/evm/config/toml/config.go b/core/chains/evm/config/toml/config.go index fdfce23a877..a94e45ae894 100644 --- a/core/chains/evm/config/toml/config.go +++ b/core/chains/evm/config/toml/config.go @@ -3,6 +3,7 @@ package toml import ( "fmt" "net/url" + "strconv" "github.com/ethereum/go-ethereum/core/txpool" "github.com/pelletier/go-toml/v2" @@ -18,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" configutils "github.com/smartcontractkit/chainlink/v2/core/utils/config" @@ -94,7 +96,18 @@ func (cs *EVMConfigs) SetFrom(fs *EVMConfigs) (err error) { return } -func (cs EVMConfigs) Chains(ids ...string) (r []relaytypes.ChainStatus, err error) { +func (cs EVMConfigs) totalChains() int { + total := 0 + for _, ch := range cs { + if ch == nil { + continue + } + total++ + } + return total +} +func (cs EVMConfigs) Chains(ids ...relay.ChainID) (r []relaytypes.ChainStatus, total int, err error) { + total = cs.totalChains() for _, ch := range cs { if ch == nil { continue @@ -140,7 +153,7 @@ func (cs EVMConfigs) NodeStatus(name string) (relaytypes.NodeStatus, error) { for i := range cs { for _, n := range cs[i].Nodes { if n.Name != nil && *n.Name == name { - return nodeStatus(n, cs[i].ChainID.String()) + return nodeStatus(n, relay.ChainID(cs[i].ChainID.String())) } } } @@ -165,7 +178,7 @@ func legacyNode(n *Node, chainID *utils.Big) (v2 types.Node) { return } -func nodeStatus(n *Node, chainID string) (relaytypes.NodeStatus, error) { +func nodeStatus(n *Node, chainID relay.ChainID) (relaytypes.NodeStatus, error) { var s relaytypes.NodeStatus s.ChainID = chainID s.Name = *n.Name @@ -177,39 +190,43 @@ func nodeStatus(n *Node, chainID string) (relaytypes.NodeStatus, error) { return s, nil } -func (cs EVMConfigs) nodes(chainID string) (ns EVMNodes) { +func (cs EVMConfigs) nodes(id relay.ChainID) (ns EVMNodes) { for _, c := range cs { - if c.ChainID.String() == chainID { + if c.ChainID.String() == id { return c.Nodes } } return nil } -func (cs EVMConfigs) Nodes(chainID utils.Big) (ns []types.Node, err error) { - id := chainID.String() - nodes := cs.nodes(id) +func (cs EVMConfigs) Nodes(chainID relay.ChainID) (ns []types.Node, err error) { + evmID, err := ChainIDInt64(chainID) + if err != nil { + return nil, fmt.Errorf("invalid evm chain id %q : %w", chainID, err) + } + nodes := cs.nodes(chainID) if nodes == nil { - err = fmt.Errorf("no nodes: chain %s: %w", &chainID, chains.ErrNotFound) + err = fmt.Errorf("no nodes: chain %q: %w", chainID, chains.ErrNotFound) return } for _, n := range nodes { if n == nil { continue } - ns = append(ns, legacyNode(n, &chainID)) + + ns = append(ns, legacyNode(n, utils.NewBigI(evmID))) } return } -func (cs EVMConfigs) NodeStatuses(chainIDs ...string) (ns []relaytypes.NodeStatus, err error) { +func (cs EVMConfigs) NodeStatuses(chainIDs ...relay.ChainID) (ns []relaytypes.NodeStatus, err error) { if len(chainIDs) == 0 { for i := range cs { for _, n := range cs[i].Nodes { if n == nil { continue } - n2, err := nodeStatus(n, cs[i].ChainID.String()) + n2, err := nodeStatus(n, relay.ChainID(cs[i].ChainID.String())) if err != nil { return nil, err } @@ -785,3 +802,11 @@ func (n *Node) SetFrom(f *Node) { n.Order = f.Order } } + +func ChainIDInt64(cid relay.ChainID) (int64, error) { + i, err := strconv.Atoi(cid) + if err != nil { + return int64(0), err + } + return int64(i), nil +} diff --git a/core/chains/evm/forwarders/orm.go b/core/chains/evm/forwarders/orm.go index 594d4d442b2..287698d22f6 100644 --- a/core/chains/evm/forwarders/orm.go +++ b/core/chains/evm/forwarders/orm.go @@ -34,7 +34,7 @@ func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) *orm { // CreateForwarder creates the Forwarder address associated with the current EVM chain id. func (o *orm) CreateForwarder(addr common.Address, evmChainId utils.Big) (fwd Forwarder, err error) { - sql := `INSERT INTO evm_forwarders (address, evm_chain_id, created_at, updated_at) VALUES ($1, $2, now(), now()) RETURNING *` + sql := `INSERT INTO evm.forwarders (address, evm_chain_id, created_at, updated_at) VALUES ($1, $2, now(), now()) RETURNING *` err = o.q.Get(&fwd, sql, addr, evmChainId) return fwd, err } @@ -50,7 +50,7 @@ func (o *orm) DeleteForwarder(id int64, cleanup func(tx pg.Queryer, evmChainID i var rowsAffected int64 err = o.q.Transaction(func(tx pg.Queryer) error { - err = tx.Get(&dest, `SELECT evm_chain_id, address FROM evm_forwarders WHERE id = $1`, id) + err = tx.Get(&dest, `SELECT evm_chain_id, address FROM evm.forwarders WHERE id = $1`, id) if err != nil { return err } @@ -60,7 +60,7 @@ func (o *orm) DeleteForwarder(id int64, cleanup func(tx pg.Queryer, evmChainID i } } - result, err2 := o.q.Exec(`DELETE FROM evm_forwarders WHERE id = $1`, id) + result, err2 := o.q.Exec(`DELETE FROM evm.forwarders WHERE id = $1`, id) // If the forwarder wasn't found, we still want to delete the filter. // In that case, the transaction must return nil, even though DeleteForwarder // will return sql.ErrNoRows @@ -80,12 +80,12 @@ func (o *orm) DeleteForwarder(id int64, cleanup func(tx pg.Queryer, evmChainID i // FindForwarders returns all forwarder addresses from offset up until limit. func (o *orm) FindForwarders(offset, limit int) (fwds []Forwarder, count int, err error) { - sql := `SELECT count(*) FROM evm_forwarders` + sql := `SELECT count(*) FROM evm.forwarders` if err = o.q.Get(&count, sql); err != nil { return } - sql = `SELECT * FROM evm_forwarders ORDER BY created_at DESC, id DESC LIMIT $1 OFFSET $2` + sql = `SELECT * FROM evm.forwarders ORDER BY created_at DESC, id DESC LIMIT $1 OFFSET $2` if err = o.q.Select(&fwds, sql, limit, offset); err != nil { return } @@ -94,7 +94,7 @@ func (o *orm) FindForwarders(offset, limit int) (fwds []Forwarder, count int, er // FindForwardersByChain returns all forwarder addresses for a chain. func (o *orm) FindForwardersByChain(evmChainId utils.Big) (fwds []Forwarder, err error) { - sql := `SELECT * FROM evm_forwarders where evm_chain_id = $1 ORDER BY created_at DESC, id DESC` + sql := `SELECT * FROM evm.forwarders where evm_chain_id = $1 ORDER BY created_at DESC, id DESC` err = o.q.Select(&fwds, sql, evmChainId) return } @@ -108,7 +108,7 @@ func (o *orm) FindForwardersInListByChain(evmChainId utils.Big, addrs []common.A } query, args, err := sqlx.Named(` - SELECT * FROM evm_forwarders + SELECT * FROM evm.forwarders WHERE evm_chain_id = :chainid AND address IN (:addresses) ORDER BY created_at DESC, id DESC`, diff --git a/core/chains/evm/headtracker/head_tracker_test.go b/core/chains/evm/headtracker/head_tracker_test.go index cf8399ceeda..330142b9dc0 100644 --- a/core/chains/evm/headtracker/head_tracker_test.go +++ b/core/chains/evm/headtracker/head_tracker_test.go @@ -38,7 +38,7 @@ import ( ) func firstHead(t *testing.T, db *sqlx.DB) (h evmtypes.Head) { - if err := db.Get(&h, `SELECT * FROM evm_heads ORDER BY number ASC LIMIT 1`); err != nil { + if err := db.Get(&h, `SELECT * FROM evm.heads ORDER BY number ASC LIMIT 1`); err != nil { t.Fatal(err) } return h @@ -428,7 +428,7 @@ func TestHeadTracker_SwitchesToLongestChainWithHeadSamplingEnabled(t *testing.T) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) checker := commonmocks.NewHeadTrackable[*evmtypes.Head, gethCommon.Hash](t) - orm := headtracker.NewORM(db, logger, config.Database(), *config.DefaultChainID()) + orm := headtracker.NewORM(db, logger, config.Database(), *evmtest.MustGetDefaultChainID(t, config.EVMConfigs())) csCfg := evmtest.NewChainScopedConfig(t, config) ht := createHeadTrackerWithChecker(t, ethClient, csCfg.EVM(), csCfg.EVM().HeadTracker(), orm, checker) @@ -779,7 +779,7 @@ func TestHeadTracker_Backfill(t *testing.T) { } ethClient := evmtest.NewEthClientMock(t) - ethClient.On("ConfiguredChainID", mock.Anything).Return(cfg.DefaultChainID(), nil) + ethClient.On("ConfiguredChainID", mock.Anything).Return(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()), nil) ht := createHeadTrackerWithNeverSleeper(t, ethClient, cfg, orm) err := ht.Backfill(ctx, &h12, 2) @@ -796,7 +796,7 @@ func TestHeadTracker_Backfill(t *testing.T) { } ethClient := evmtest.NewEthClientMock(t) - ethClient.On("ConfiguredChainID", mock.Anything).Return(cfg.DefaultChainID(), nil) + ethClient.On("ConfiguredChainID", mock.Anything).Return(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()), nil) ethClient.On("HeadByHash", mock.Anything, head10.Hash). Return(&head10, nil) @@ -832,7 +832,7 @@ func TestHeadTracker_Backfill(t *testing.T) { } ethClient := evmtest.NewEthClientMock(t) - ethClient.On("ConfiguredChainID", mock.Anything).Return(cfg.DefaultChainID(), nil) + ethClient.On("ConfiguredChainID", mock.Anything).Return(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()), nil) ht := createHeadTrackerWithNeverSleeper(t, ethClient, cfg, orm) @@ -865,7 +865,7 @@ func TestHeadTracker_Backfill(t *testing.T) { } ethClient := evmtest.NewEthClientMock(t) - ethClient.On("ConfiguredChainID", mock.Anything).Return(cfg.DefaultChainID(), nil) + ethClient.On("ConfiguredChainID", mock.Anything).Return(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()), nil) ht := createHeadTrackerWithNeverSleeper(t, ethClient, cfg, orm) @@ -883,7 +883,7 @@ func TestHeadTracker_Backfill(t *testing.T) { orm := headtracker.NewORM(db, logger, cfg.Database(), cltest.FixtureChainID) ethClient := evmtest.NewEthClientMock(t) - ethClient.On("ConfiguredChainID", mock.Anything).Return(cfg.DefaultChainID(), nil) + ethClient.On("ConfiguredChainID", mock.Anything).Return(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()), nil) ethClient.On("HeadByHash", mock.Anything, head0.Hash). Return(&head0, nil) @@ -911,7 +911,7 @@ func TestHeadTracker_Backfill(t *testing.T) { } ethClient := evmtest.NewEthClientMock(t) - ethClient.On("ConfiguredChainID", mock.Anything).Return(cfg.DefaultChainID(), nil) + ethClient.On("ConfiguredChainID", mock.Anything).Return(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()), nil) ethClient.On("HeadByHash", mock.Anything, head10.Hash). Return(&head10, nil). Once() @@ -942,7 +942,7 @@ func TestHeadTracker_Backfill(t *testing.T) { } ethClient := evmtest.NewEthClientMock(t) - ethClient.On("ConfiguredChainID", mock.Anything).Return(cfg.DefaultChainID(), nil) + ethClient.On("ConfiguredChainID", mock.Anything).Return(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()), nil) ethClient.On("HeadByHash", mock.Anything, head10.Hash). Return(&head10, nil) ethClient.On("HeadByHash", mock.Anything, head8.Hash). @@ -967,7 +967,7 @@ func TestHeadTracker_Backfill(t *testing.T) { logger := logger.TestLogger(t) orm := headtracker.NewORM(db, logger, cfg.Database(), cltest.FixtureChainID) ethClient := evmtest.NewEthClientMock(t) - ethClient.On("ConfiguredChainID", mock.Anything).Return(cfg.DefaultChainID(), nil) + ethClient.On("ConfiguredChainID", mock.Anything).Return(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()), nil) ethClient.On("HeadByHash", mock.Anything, h14.Hash).Return(&h14, nil).Once() ethClient.On("HeadByHash", mock.Anything, h13.Hash).Return(&h13, nil).Once() ethClient.On("HeadByHash", mock.Anything, h12.Hash).Return(nil, errors.New("not found")).Once() diff --git a/core/chains/evm/headtracker/orm.go b/core/chains/evm/headtracker/orm.go index 02747752148..426df68b301 100644 --- a/core/chains/evm/headtracker/orm.go +++ b/core/chains/evm/headtracker/orm.go @@ -43,7 +43,7 @@ func (orm *orm) IdempotentInsertHead(ctx context.Context, head *evmtypes.Head) e // listener guarantees head.EVMChainID to be equal to orm.chainID q := orm.q.WithOpts(pg.WithParentCtx(ctx)) query := ` - INSERT INTO evm_heads (hash, number, parent_hash, created_at, timestamp, l1_block_number, evm_chain_id, base_fee_per_gas) VALUES ( + INSERT INTO evm.heads (hash, number, parent_hash, created_at, timestamp, l1_block_number, evm_chain_id, base_fee_per_gas) VALUES ( :hash, :number, :parent_hash, :created_at, :timestamp, :l1_block_number, :evm_chain_id, :base_fee_per_gas) ON CONFLICT (evm_chain_id, hash) DO NOTHING` err := q.ExecQNamed(query, head) @@ -53,11 +53,11 @@ func (orm *orm) IdempotentInsertHead(ctx context.Context, head *evmtypes.Head) e func (orm *orm) TrimOldHeads(ctx context.Context, n uint) (err error) { q := orm.q.WithOpts(pg.WithParentCtx(ctx)) return q.ExecQ(` - DELETE FROM evm_heads + DELETE FROM evm.heads WHERE evm_chain_id = $1 AND number < ( SELECT min(number) FROM ( SELECT number - FROM evm_heads + FROM evm.heads WHERE evm_chain_id = $1 ORDER BY number DESC LIMIT $2 @@ -68,7 +68,7 @@ func (orm *orm) TrimOldHeads(ctx context.Context, n uint) (err error) { func (orm *orm) LatestHead(ctx context.Context) (head *evmtypes.Head, err error) { head = new(evmtypes.Head) q := orm.q.WithOpts(pg.WithParentCtx(ctx)) - err = q.Get(head, `SELECT * FROM evm_heads WHERE evm_chain_id = $1 ORDER BY number DESC, created_at DESC, id DESC LIMIT 1`, orm.chainID) + err = q.Get(head, `SELECT * FROM evm.heads WHERE evm_chain_id = $1 ORDER BY number DESC, created_at DESC, id DESC LIMIT 1`, orm.chainID) if errors.Is(err, sql.ErrNoRows) { return nil, nil } @@ -78,7 +78,7 @@ func (orm *orm) LatestHead(ctx context.Context) (head *evmtypes.Head, err error) func (orm *orm) LatestHeads(ctx context.Context, limit uint) (heads []*evmtypes.Head, err error) { q := orm.q.WithOpts(pg.WithParentCtx(ctx)) - err = q.Select(&heads, `SELECT * FROM evm_heads WHERE evm_chain_id = $1 ORDER BY number DESC, created_at DESC, id DESC LIMIT $2`, orm.chainID, limit) + err = q.Select(&heads, `SELECT * FROM evm.heads WHERE evm_chain_id = $1 ORDER BY number DESC, created_at DESC, id DESC LIMIT $2`, orm.chainID, limit) err = errors.Wrap(err, "LatestHeads failed") return } @@ -86,7 +86,7 @@ func (orm *orm) LatestHeads(ctx context.Context, limit uint) (heads []*evmtypes. func (orm *orm) HeadByHash(ctx context.Context, hash common.Hash) (head *evmtypes.Head, err error) { q := orm.q.WithOpts(pg.WithParentCtx(ctx)) head = new(evmtypes.Head) - err = q.Get(head, `SELECT * FROM evm_heads WHERE evm_chain_id = $1 AND hash = $2`, orm.chainID, hash) + err = q.Get(head, `SELECT * FROM evm.heads WHERE evm_chain_id = $1 AND hash = $2`, orm.chainID, hash) if errors.Is(err, sql.ErrNoRows) { return nil, nil } diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index 69a3143859f..227688fce16 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -657,7 +657,7 @@ func (lp *logPoller) backfill(ctx context.Context, start, end int64) error { } } if batchSize == 1 { - lp.lggr.Criticalw("Too many log results in a single block, failed to retrieve logs! Node may run in a degraded state unless LogBackfillBatchSize is increased", "err", err, "from", from, "to", to, "LogBackfillBatchSize", lp.backfillBatchSize) + lp.lggr.Criticalw("Too many log results in a single block, failed to retrieve logs! Node may be running in a degraded state.", "err", err, "from", from, "to", to, "LogBackfillBatchSize", lp.backfillBatchSize) return err } batchSize /= 2 @@ -743,7 +743,7 @@ func (lp *logPoller) getCurrentBlockMaybeHandleReorg(ctx context.Context, curren // that applications see them and take action upon it, however that // results in significantly slower reads since we must then compute // the canonical set per read. Typically, if an application took action on a log - // it would be saved elsewhere e.g. eth_txes, so it seems better to just support the fast reads. + // it would be saved elsewhere e.g. evm.txes, so it seems better to just support the fast reads. // Its also nicely analogous to reading from the chain itself. err2 = lp.orm.q.WithOpts(pg.WithParentCtx(ctx)).Transaction(func(tx pg.Queryer) error { // These deletes are bounded by reorg depth, so they are @@ -1043,7 +1043,7 @@ func (lp *logPoller) GetBlocksRange(ctx context.Context, numbers []uint64, qopts } // Fill any remaining blocks from the client. - blocksFoundFromRPC, err := lp.fillRemainingBlocksFromRPC(ctx, numbers, blocksFound) + blocksFoundFromRPC, err := lp.fillRemainingBlocksFromRPC(ctx, blocksRequested, blocksFound) if err != nil { return nil, err } @@ -1069,12 +1069,12 @@ func (lp *logPoller) GetBlocksRange(ctx context.Context, numbers []uint64, qopts func (lp *logPoller) fillRemainingBlocksFromRPC( ctx context.Context, - blocksRequested []uint64, + blocksRequested map[uint64]struct{}, blocksFound map[uint64]LogPollerBlock, ) (map[uint64]LogPollerBlock, error) { var reqs []rpc.BatchElem var remainingBlocks []uint64 - for _, num := range blocksRequested { + for num := range blocksRequested { if _, ok := blocksFound[num]; !ok { req := rpc.BatchElem{ Method: "eth_getBlockByNumber", diff --git a/core/chains/evm/logpoller/orm.go b/core/chains/evm/logpoller/orm.go index 08a4d558fbf..3c678aeed36 100644 --- a/core/chains/evm/logpoller/orm.go +++ b/core/chains/evm/logpoller/orm.go @@ -34,7 +34,7 @@ func NewORM(chainID *big.Int, db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) * // InsertBlock is idempotent to support replays. func (o *ORM) InsertBlock(h common.Hash, n int64, t time.Time, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) - err := q.ExecQ(`INSERT INTO evm_log_poller_blocks (evm_chain_id, block_hash, block_number, block_timestamp, created_at) + err := q.ExecQ(`INSERT INTO evm.log_poller_blocks (evm_chain_id, block_hash, block_number, block_timestamp, created_at) VALUES ($1, $2, $3, $4, NOW()) ON CONFLICT DO NOTHING`, utils.NewBig(o.chainID), h[:], n, t) return err } @@ -54,7 +54,7 @@ func (o *ORM) InsertFilter(filter Filter, qopts ...pg.QOpt) (err error) { for _, ev := range filter.EventSigs { events = append(events, ev.Bytes()) } - return q.ExecQ(`INSERT INTO evm_log_poller_filters + return q.ExecQ(`INSERT INTO evm.log_poller_filters (name, evm_chain_id, retention, created_at, address, event) SELECT * FROM (SELECT $1, $2::NUMERIC, $3::BIGINT, NOW()) x, @@ -67,7 +67,7 @@ func (o *ORM) InsertFilter(filter Filter, qopts ...pg.QOpt) (err error) { // DeleteFilter removes all events,address pairs associated with the Filter func (o *ORM) DeleteFilter(name string, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) - return q.ExecQ(`DELETE FROM evm_log_poller_filters WHERE name = $1 AND evm_chain_id = $2`, name, utils.NewBig(o.chainID)) + return q.ExecQ(`DELETE FROM evm.log_poller_filters WHERE name = $1 AND evm_chain_id = $2`, name, utils.NewBig(o.chainID)) } // LoadFiltersForChain returns all filters for this chain @@ -78,7 +78,7 @@ func (o *ORM) LoadFilters(qopts ...pg.QOpt) (map[string]Filter, error) { ARRAY_AGG(DISTINCT address)::BYTEA[] AS addresses, ARRAY_AGG(DISTINCT event)::BYTEA[] AS event_sigs, MAX(retention) AS retention - FROM evm_log_poller_filters WHERE evm_chain_id = $1 + FROM evm.log_poller_filters WHERE evm_chain_id = $1 GROUP BY name`, utils.NewBig(o.chainID)) filters := make(map[string]Filter) for _, filter := range rows { @@ -91,7 +91,7 @@ func (o *ORM) LoadFilters(qopts ...pg.QOpt) (map[string]Filter, error) { func (o *ORM) SelectBlockByHash(h common.Hash, qopts ...pg.QOpt) (*LogPollerBlock, error) { q := o.q.WithOpts(qopts...) var b LogPollerBlock - if err := q.Get(&b, `SELECT * FROM evm_log_poller_blocks WHERE block_hash = $1 AND evm_chain_id = $2`, h, utils.NewBig(o.chainID)); err != nil { + if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE block_hash = $1 AND evm_chain_id = $2`, h, utils.NewBig(o.chainID)); err != nil { return nil, err } return &b, nil @@ -100,7 +100,7 @@ func (o *ORM) SelectBlockByHash(h common.Hash, qopts ...pg.QOpt) (*LogPollerBloc func (o *ORM) SelectBlockByNumber(n int64, qopts ...pg.QOpt) (*LogPollerBlock, error) { q := o.q.WithOpts(qopts...) var b LogPollerBlock - if err := q.Get(&b, `SELECT * FROM evm_log_poller_blocks WHERE block_number = $1 AND evm_chain_id = $2`, n, utils.NewBig(o.chainID)); err != nil { + if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE block_number = $1 AND evm_chain_id = $2`, n, utils.NewBig(o.chainID)); err != nil { return nil, err } return &b, nil @@ -109,7 +109,7 @@ func (o *ORM) SelectBlockByNumber(n int64, qopts ...pg.QOpt) (*LogPollerBlock, e func (o *ORM) SelectLatestBlock(qopts ...pg.QOpt) (*LogPollerBlock, error) { q := o.q.WithOpts(qopts...) var b LogPollerBlock - if err := q.Get(&b, `SELECT * FROM evm_log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1`, utils.NewBig(o.chainID)); err != nil { + if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1`, utils.NewBig(o.chainID)); err != nil { return nil, err } return &b, nil @@ -118,11 +118,11 @@ func (o *ORM) SelectLatestBlock(qopts ...pg.QOpt) (*LogPollerBlock, error) { func (o *ORM) SelectLatestLogEventSigWithConfs(eventSig common.Hash, address common.Address, confs int, qopts ...pg.QOpt) (*Log, error) { q := o.q.WithOpts(qopts...) var l Log - if err := q.Get(&l, `SELECT * FROM evm_logs + if err := q.Get(&l, `SELECT * FROM evm.logs WHERE evm_chain_id = $1 AND event_sig = $2 AND address = $3 - AND (block_number + $4) <= (SELECT COALESCE(block_number, 0) FROM evm_log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) + AND (block_number + $4) <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) ORDER BY (block_number, log_index) DESC LIMIT 1`, utils.NewBig(o.chainID), eventSig, address, confs); err != nil { return nil, err } @@ -132,19 +132,19 @@ func (o *ORM) SelectLatestLogEventSigWithConfs(eventSig common.Hash, address com // DeleteBlocksAfter delete all blocks after and including start. func (o *ORM) DeleteBlocksAfter(start int64, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) - return q.ExecQ(`DELETE FROM evm_log_poller_blocks WHERE block_number >= $1 AND evm_chain_id = $2`, start, utils.NewBig(o.chainID)) + return q.ExecQ(`DELETE FROM evm.log_poller_blocks WHERE block_number >= $1 AND evm_chain_id = $2`, start, utils.NewBig(o.chainID)) } // DeleteBlocksBefore delete all blocks before and including end. func (o *ORM) DeleteBlocksBefore(end int64, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) - _, err := q.Exec(`DELETE FROM evm_log_poller_blocks WHERE block_number <= $1 AND evm_chain_id = $2`, end, utils.NewBig(o.chainID)) + _, err := q.Exec(`DELETE FROM evm.log_poller_blocks WHERE block_number <= $1 AND evm_chain_id = $2`, end, utils.NewBig(o.chainID)) return err } func (o *ORM) DeleteLogsAfter(start int64, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) - return q.ExecQ(`DELETE FROM evm_logs WHERE block_number >= $1 AND evm_chain_id = $2`, start, utils.NewBig(o.chainID)) + return q.ExecQ(`DELETE FROM evm.logs WHERE block_number >= $1 AND evm_chain_id = $2`, start, utils.NewBig(o.chainID)) } type Exp struct { @@ -161,9 +161,9 @@ func (o *ORM) DeleteExpiredLogs(qopts ...pg.QOpt) error { return q.ExecQ(`WITH r AS ( SELECT address, event, MAX(retention) AS retention - FROM evm_log_poller_filters WHERE evm_chain_id=$1 + FROM evm.log_poller_filters WHERE evm_chain_id=$1 GROUP BY evm_chain_id,address, event HAVING NOT 0 = ANY(ARRAY_AGG(retention)) - ) DELETE FROM evm_logs l USING r + ) DELETE FROM evm.logs l USING r WHERE l.evm_chain_id = $1 AND l.address=r.address AND l.event_sig=r.event AND l.created_at <= STATEMENT_TIMESTAMP() - (r.retention / 10^9 * interval '1 second')`, // retention is in nanoseconds (time.Duration aka BIGINT) utils.NewBig(o.chainID)) @@ -185,7 +185,7 @@ func (o *ORM) InsertLogs(logs []Log, qopts ...pg.QOpt) error { end = len(logs) } - err := q.ExecQNamed(`INSERT INTO evm_logs + err := q.ExecQNamed(`INSERT INTO evm.logs (evm_chain_id, log_index, block_hash, block_number, block_timestamp, address, event_sig, topics, tx_hash, data, created_at) VALUES (:evm_chain_id, :log_index, :block_hash, :block_number, :block_timestamp, :address, :event_sig, :topics, :tx_hash, :data, NOW()) ON CONFLICT DO NOTHING`, logs[start:end]) @@ -206,7 +206,7 @@ func (o *ORM) InsertLogs(logs []Log, qopts ...pg.QOpt) error { func (o *ORM) SelectLogsByBlockRange(start, end int64) ([]Log, error) { var logs []Log err := o.q.Select(&logs, ` - SELECT * FROM evm_logs + SELECT * FROM evm.logs WHERE block_number >= $1 AND block_number <= $2 AND evm_chain_id = $3 ORDER BY (block_number, log_index, created_at)`, start, end, utils.NewBig(o.chainID)) if err != nil { @@ -220,10 +220,10 @@ func (o *ORM) SelectLogsByBlockRangeFilter(start, end int64, address common.Addr var logs []Log q := o.q.WithOpts(qopts...) err := q.Select(&logs, ` - SELECT * FROM evm_logs - WHERE evm_logs.block_number >= $1 AND evm_logs.block_number <= $2 AND evm_logs.evm_chain_id = $3 + SELECT * FROM evm.logs + WHERE evm.logs.block_number >= $1 AND evm.logs.block_number <= $2 AND evm.logs.evm_chain_id = $3 AND address = $4 AND event_sig = $5 - ORDER BY (evm_logs.block_number, evm_logs.log_index)`, start, end, utils.NewBig(o.chainID), address, eventSig.Bytes()) + ORDER BY (evm.logs.block_number, evm.logs.log_index)`, start, end, utils.NewBig(o.chainID), address, eventSig.Bytes()) if err != nil { return nil, err } @@ -235,12 +235,12 @@ func (o *ORM) SelectLogsCreatedAfter(eventSig []byte, address common.Address, af var logs []Log q := o.q.WithOpts(qopts...) err := q.Select(&logs, ` - SELECT * FROM evm_logs + SELECT * FROM evm.logs WHERE evm_chain_id = $1 AND address = $2 AND event_sig = $3 AND created_at > $4 - AND (block_number + $5) <= (SELECT COALESCE(block_number, 0) FROM evm_log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) + AND (block_number + $5) <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) ORDER BY created_at ASC`, utils.NewBig(o.chainID), address, eventSig, after, confs) if err != nil { return nil, err @@ -267,12 +267,12 @@ func (o *ORM) SelectLogsWithSigsByBlockRangeFilter(start, end int64, address com ` SELECT * -FROM evm_logs -WHERE evm_logs.block_number BETWEEN :start AND :end - AND evm_logs.evm_chain_id = :chainid - AND evm_logs.address = :address - AND evm_logs.event_sig IN (:EventSigs) -ORDER BY (evm_logs.block_number, evm_logs.log_index)`, a) +FROM evm.logs +WHERE evm.logs.block_number BETWEEN :start AND :end + AND evm.logs.evm_chain_id = :chainid + AND evm.logs.address = :address + AND evm.logs.event_sig IN (:EventSigs) +ORDER BY (evm.logs.block_number, evm.logs.log_index)`, a) if err != nil { return nil, errors.Wrap(err, "sqlx Named") } @@ -292,7 +292,7 @@ func (o *ORM) GetBlocksRange(start uint64, end uint64, qopts ...pg.QOpt) ([]LogP var blocks []LogPollerBlock q := o.q.WithOpts(qopts...) err := q.Select(&blocks, ` - SELECT * FROM evm_log_poller_blocks + SELECT * FROM evm.log_poller_blocks WHERE block_number >= $1 AND block_number <= $2 AND evm_chain_id = $3 ORDER BY block_number ASC`, start, end, utils.NewBig(o.chainID)) if err != nil { @@ -309,13 +309,13 @@ func (o *ORM) SelectLatestLogEventSigsAddrsWithConfs(fromBlock int64, addresses q := o.q.WithOpts(qopts...) err := q.Select(&logs, ` - SELECT * FROM evm_logs WHERE (block_number, address, event_sig) IN ( - SELECT MAX(block_number), address, event_sig FROM evm_logs + SELECT * FROM evm.logs WHERE (block_number, address, event_sig) IN ( + SELECT MAX(block_number), address, event_sig FROM evm.logs WHERE evm_chain_id = $1 AND event_sig = ANY($2) AND address = ANY($3) AND block_number > $4 AND - block_number <= (SELECT COALESCE(block_number, 0) FROM evm_log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $5 + block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $5 GROUP BY event_sig, address ) ORDER BY block_number ASC @@ -334,12 +334,12 @@ func (o *ORM) SelectLatestBlockNumberEventSigsAddrsWithConfs(fromBlock int64, ev q := o.q.WithOpts(qopts...) err := q.Get(&blockNumber, ` - SELECT COALESCE(MAX(block_number), 0) FROM evm_logs + SELECT COALESCE(MAX(block_number), 0) FROM evm.logs WHERE evm_chain_id = $1 AND event_sig = ANY($2) AND address = ANY($3) AND block_number > $4 AND - block_number <= (SELECT COALESCE(block_number, 0) FROM evm_log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $5`, + block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $5`, o.chainID.Int64(), sigs, addrs, fromBlock, confs) if err != nil { return 0, err @@ -351,13 +351,13 @@ func (o *ORM) SelectDataWordRange(address common.Address, eventSig common.Hash, var logs []Log q := o.q.WithOpts(qopts...) err := q.Select(&logs, - `SELECT * FROM evm_logs - WHERE evm_logs.evm_chain_id = $1 + `SELECT * FROM evm.logs + WHERE evm.logs.evm_chain_id = $1 AND address = $2 AND event_sig = $3 AND substring(data from 32*$4+1 for 32) >= $5 AND substring(data from 32*$4+1 for 32) <= $6 - AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm_log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $7 - ORDER BY (evm_logs.block_number, evm_logs.log_index)`, utils.NewBig(o.chainID), address, eventSig.Bytes(), wordIndex, wordValueMin.Bytes(), wordValueMax.Bytes(), confs) + AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $7 + ORDER BY (evm.logs.block_number, evm.logs.log_index)`, utils.NewBig(o.chainID), address, eventSig.Bytes(), wordIndex, wordValueMin.Bytes(), wordValueMax.Bytes(), confs) if err != nil { return nil, err } @@ -368,12 +368,12 @@ func (o *ORM) SelectDataWordGreaterThan(address common.Address, eventSig common. var logs []Log q := o.q.WithOpts(qopts...) err := q.Select(&logs, - `SELECT * FROM evm_logs - WHERE evm_logs.evm_chain_id = $1 + `SELECT * FROM evm.logs + WHERE evm.logs.evm_chain_id = $1 AND address = $2 AND event_sig = $3 AND substring(data from 32*$4+1 for 32) >= $5 - AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm_log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $6 - ORDER BY (evm_logs.block_number, evm_logs.log_index)`, utils.NewBig(o.chainID), address, eventSig.Bytes(), wordIndex, wordValueMin.Bytes(), confs) + AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $6 + ORDER BY (evm.logs.block_number, evm.logs.log_index)`, utils.NewBig(o.chainID), address, eventSig.Bytes(), wordIndex, wordValueMin.Bytes(), confs) if err != nil { return nil, err } @@ -388,12 +388,12 @@ func (o *ORM) SelectIndexLogsTopicGreaterThan(address common.Address, eventSig c var logs []Log q := o.q.WithOpts(qopts...) err := q.Select(&logs, - `SELECT * FROM evm_logs - WHERE evm_logs.evm_chain_id = $1 + `SELECT * FROM evm.logs + WHERE evm.logs.evm_chain_id = $1 AND address = $2 AND event_sig = $3 AND topics[$4] >= $5 - AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm_log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $6 - ORDER BY (evm_logs.block_number, evm_logs.log_index)`, utils.NewBig(o.chainID), address, eventSig.Bytes(), topicIndex+1, topicValueMin.Bytes(), confs) + AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $6 + ORDER BY (evm.logs.block_number, evm.logs.log_index)`, utils.NewBig(o.chainID), address, eventSig.Bytes(), topicIndex+1, topicValueMin.Bytes(), confs) if err != nil { return nil, err } @@ -408,13 +408,13 @@ func (o *ORM) SelectIndexLogsTopicRange(address common.Address, eventSig common. var logs []Log q := o.q.WithOpts(qopts...) err := q.Select(&logs, - `SELECT * FROM evm_logs - WHERE evm_logs.evm_chain_id = $1 + `SELECT * FROM evm.logs + WHERE evm.logs.evm_chain_id = $1 AND address = $2 AND event_sig = $3 AND topics[$4] >= $5 AND topics[$4] <= $6 - AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm_log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $7 - ORDER BY (evm_logs.block_number, evm_logs.log_index)`, utils.NewBig(o.chainID), address, eventSig.Bytes(), topicIndex+1, topicValueMin.Bytes(), topicValueMax.Bytes(), confs) + AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $7 + ORDER BY (evm.logs.block_number, evm.logs.log_index)`, utils.NewBig(o.chainID), address, eventSig.Bytes(), topicIndex+1, topicValueMin.Bytes(), topicValueMax.Bytes(), confs) if err != nil { return nil, err } @@ -431,12 +431,12 @@ func (o *ORM) SelectIndexedLogs(address common.Address, eventSig common.Hash, to topicValuesBytes := concatBytes(topicValues) // Add 1 since postgresql arrays are 1-indexed. err := q.Select(&logs, ` - SELECT * FROM evm_logs - WHERE evm_logs.evm_chain_id = $1 + SELECT * FROM evm.logs + WHERE evm.logs.evm_chain_id = $1 AND address = $2 AND event_sig = $3 AND topics[$4] = ANY($5) - AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm_log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $6 - ORDER BY (evm_logs.block_number, evm_logs.log_index)`, utils.NewBig(o.chainID), address, eventSig.Bytes(), topicIndex+1, topicValuesBytes, confs) + AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $6 + ORDER BY (evm.logs.block_number, evm.logs.log_index)`, utils.NewBig(o.chainID), address, eventSig.Bytes(), topicIndex+1, topicValuesBytes, confs) if err != nil { return nil, err } @@ -453,11 +453,11 @@ func (o *ORM) SelectIndexedLogsByBlockRangeFilter(start, end int64, address comm topicValuesBytes := concatBytes(topicValues) q := o.q.WithOpts(qopts...) err := q.Select(&logs, ` - SELECT * FROM evm_logs - WHERE evm_logs.block_number >= $1 AND evm_logs.block_number <= $2 AND evm_logs.evm_chain_id = $3 + SELECT * FROM evm.logs + WHERE evm.logs.block_number >= $1 AND evm.logs.block_number <= $2 AND evm.logs.evm_chain_id = $3 AND address = $4 AND event_sig = $5 AND topics[$6] = ANY($7) - ORDER BY (evm_logs.block_number, evm_logs.log_index)`, start, end, utils.NewBig(o.chainID), address, eventSig.Bytes(), topicIndex+1, topicValuesBytes) + ORDER BY (evm.logs.block_number, evm.logs.log_index)`, start, end, utils.NewBig(o.chainID), address, eventSig.Bytes(), topicIndex+1, topicValuesBytes) if err != nil { return nil, err } @@ -478,12 +478,12 @@ func (o *ORM) SelectIndexedLogsCreatedAfter(address common.Address, eventSig com topicValuesBytes := concatBytes(topicValues) // Add 1 since postgresql arrays are 1-indexed. err := q.Select(&logs, ` - SELECT * FROM evm_logs - WHERE evm_logs.evm_chain_id = $1 + SELECT * FROM evm.logs + WHERE evm.logs.evm_chain_id = $1 AND address = $2 AND event_sig = $3 AND topics[$4] = ANY($5) AND created_at > $6 - AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm_log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $7 + AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $7 ORDER BY created_at ASC`, utils.NewBig(o.chainID), address, eventSig.Bytes(), topicIndex+1, topicValuesBytes, after, confs) if err != nil { return nil, err @@ -502,25 +502,25 @@ func (o *ORM) SelectIndexedLogsWithSigsExcluding(sigA, sigB common.Hash, topicIn err := q.Select(&logs, ` SELECT * - FROM evm_logs + FROM evm.logs WHERE evm_chain_id = $1 AND address = $2 AND event_sig = $3 AND block_number BETWEEN $6 AND $7 - AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm_log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $8 + AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $8 EXCEPT SELECT a.* - FROM evm_logs AS a - INNER JOIN evm_logs B + FROM evm.logs AS a + INNER JOIN evm.logs B ON a.evm_chain_id = b.evm_chain_id AND a.address = b.address AND a.topics[$5] = b.topics[$5] AND a.event_sig = $3 AND b.event_sig = $4 AND b.block_number BETWEEN $6 AND $7 - AND b.block_number <= (SELECT COALESCE(block_number, 0) FROM evm_log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $8 + AND b.block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $8 ORDER BY block_number,log_index ASC `, utils.NewBig(o.chainID), address, sigA.Bytes(), sigB.Bytes(), topicIndex+1, startBlock, endBlock, confs) diff --git a/core/chains/evm/mocks/legacy_chain_container.go b/core/chains/evm/mocks/legacy_chain_container.go index fe906234f16..d8dfa209a08 100644 --- a/core/chains/evm/mocks/legacy_chain_container.go +++ b/core/chains/evm/mocks/legacy_chain_container.go @@ -30,32 +30,6 @@ func (_m *LegacyChainContainer) ChainNodeConfigs() types.Configs { return r0 } -// Default provides a mock function with given fields: -func (_m *LegacyChainContainer) Default() (evm.Chain, error) { - ret := _m.Called() - - var r0 evm.Chain - var r1 error - if rf, ok := ret.Get(0).(func() (evm.Chain, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() evm.Chain); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(evm.Chain) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // Get provides a mock function with given fields: id func (_m *LegacyChainContainer) Get(id string) (evm.Chain, error) { ret := _m.Called(id) @@ -128,11 +102,6 @@ func (_m *LegacyChainContainer) List(ids ...string) ([]evm.Chain, error) { return r0, r1 } -// SetDefault provides a mock function with given fields: _a0 -func (_m *LegacyChainContainer) SetDefault(_a0 evm.Chain) { - _m.Called(_a0) -} - // Slice provides a mock function with given fields: func (_m *LegacyChainContainer) Slice() []evm.Chain { ret := _m.Called() diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 649cbfd3bfd..e1133e8ef21 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -618,7 +618,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi } // Simulate a "PruneQueue" call - assert.NoError(t, utils.JustError(db.Exec(`DELETE FROM eth_txes WHERE state = 'unstarted'`))) + assert.NoError(t, utils.JustError(db.Exec(`DELETE FROM evm.txes WHERE state = 'unstarted'`))) close(chBlock) }() @@ -729,7 +729,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) // Crashed right after we commit the database transaction that saved - // the nonce to the eth_tx so evm_key_states.next_nonce has not been + // the nonce to the eth_tx so evm.key_states.next_nonce has not been // incremented yet inProgressEthTx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -1009,7 +1009,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // We assume success and hand off to eth confirmer to eventually mark it as failed var latestID int64 var etx1 txmgr.Tx - require.NoError(t, db.Get(&latestID, "SELECT max(id) FROM eth_txes")) + require.NoError(t, db.Get(&latestID, "SELECT max(id) FROM evm.txes")) etx1, err = txStore.FindTxWithAttempts(latestID) require.NoError(t, err) require.NotNil(t, etx1.BroadcastAt) @@ -1056,7 +1056,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // Check that the key had its nonce reset var nonce int64 - err := db.Get(&nonce, `SELECT next_nonce FROM evm_key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) + err = db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) require.NoError(t, err) // Saved NextNonce must be the same as before because this transaction // was not accepted by the eth node and never can be @@ -1126,7 +1126,6 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr), evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) eb = txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), evmcfg.Database().Listener(), ethKeyStore, eventBroadcaster, txBuilder, nil, lggr, &testCheckerFactory{}, false) - require.NoError(t, err) { retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) assert.NoError(t, err) @@ -1174,7 +1173,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // Check that the key had its nonce reset var nonce int64 - err := db.Get(&nonce, `SELECT next_nonce FROM evm_key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) + err = db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) require.NoError(t, err) // Saved NextNonce must be the same as before because this transaction // was not accepted by the eth node and never can be @@ -1479,7 +1478,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.True(t, retryable) // TEARDOWN: Clear out the unsent tx before the next test - pgtest.MustExec(t, db, `DELETE FROM eth_txes WHERE nonce = $1`, localNextNonce) + pgtest.MustExec(t, db, `DELETE FROM evm.txes WHERE nonce = $1`, localNextNonce) }) t.Run("eth tx is left in progress if eth node returns insufficient eth", func(t *testing.T) { @@ -1510,7 +1509,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.Nil(t, attempt.BroadcastBeforeBlockNum) }) - pgtest.MustExec(t, db, `DELETE FROM eth_txes`) + pgtest.MustExec(t, db, `DELETE FROM evm.txes`) t.Run("eth tx is left in progress if nonce is too high", func(t *testing.T) { localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) @@ -1538,7 +1537,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.Equal(t, txmgrtypes.TxAttemptInProgress, attempt.State) assert.Nil(t, attempt.BroadcastBeforeBlockNum) - pgtest.MustExec(t, db, `DELETE FROM eth_txes`) + pgtest.MustExec(t, db, `DELETE FROM evm.txes`) }) t.Run("eth node returns underpriced transaction and bumping gas doesn't increase it in EIP-1559 mode", func(t *testing.T) { @@ -1568,7 +1567,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { require.Contains(t, err.Error(), "bumped gas tip cap of 1 wei is less than or equal to original gas tip cap of 1 wei") assert.True(t, retryable) - pgtest.MustExec(t, db, `DELETE FROM eth_txes`) + pgtest.MustExec(t, db, `DELETE FROM evm.txes`) }) t.Run("eth node returns underpriced transaction in EIP-1559 mode, bumps until inclusion", func(t *testing.T) { @@ -1617,7 +1616,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.False(t, retryable) // TEARDOWN: Clear out the unsent tx before the next test - pgtest.MustExec(t, db, `DELETE FROM eth_txes WHERE nonce = $1`, localNextNonce) + pgtest.MustExec(t, db, `DELETE FROM evm.txes WHERE nonce = $1`, localNextNonce) }) } @@ -1672,7 +1671,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { // Check that the key did not have its nonce incremented var nonce int64 - err = db.Get(&nonce, `SELECT next_nonce FROM evm_key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) + err = db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) require.NoError(t, err) require.Equal(t, int64(localNonce), nonce) }) @@ -1704,7 +1703,7 @@ func TestEthBroadcaster_IncrementNextNonce(t *testing.T) { // Nonce bumped to 1 var nonce int64 - err := db.Get(&nonce, `SELECT next_nonce FROM evm_key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, keyState.Address.Address()) + err := db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, keyState.Address.Address()) require.NoError(t, err) require.Equal(t, int64(1), nonce) } @@ -1771,7 +1770,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { sub := pgmocks.NewSubscription(t) sub.On("Events").Return(make(<-chan pg.Event)) sub.On("Close") - eventBroadcaster.On("Subscribe", "insert_on_eth_txes", "").Return(sub, nil) + eventBroadcaster.On("Subscribe", "evm.insert_on_txes", "").Return(sub, nil) estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr), evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil) checkerFactory := &testCheckerFactory{} @@ -1808,12 +1807,12 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { // Check keyState to make sure it has correct nonce assigned var nonce int64 - err := db.Get(&nonce, `SELECT next_nonce FROM evm_key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) + err := db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) require.NoError(t, err) assert.Equal(t, int64(ethNodeNonce), nonce) // The disabled key did not get updated - err = db.Get(&nonce, `SELECT next_nonce FROM evm_key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, disabledAddress) + err = db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, disabledAddress) require.NoError(t, err) assert.Equal(t, int64(0), nonce) }) @@ -1842,12 +1841,12 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { // Check keyState to make sure it has correct nonce assigned var nonce int64 - err := db.Get(&nonce, `SELECT next_nonce FROM evm_key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) + err := db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) require.NoError(t, err) assert.Equal(t, int64(ethNodeNonce), nonce) // The disabled key did not get updated - err = db.Get(&nonce, `SELECT next_nonce FROM evm_key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, disabledAddress) + err = db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, disabledAddress) require.NoError(t, err) assert.Equal(t, int64(0), nonce) }) diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index 3818335298e..555ea09ff3a 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -824,7 +824,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt_scoped_to_key(t etx2_9 := cltest.MustInsertUnconfirmedEthTx(t, txStore, 3, fromAddress1_2) // there also happens to be a confirmed tx with a higher nonce from a different chain in the DB etx_other_chain := cltest.MustInsertUnconfirmedEthTx(t, txStore, 8, fromAddress2_1) - pgtest.MustExec(t, db, `UPDATE eth_txes SET state='confirmed' WHERE id = $1`, etx_other_chain.ID) + pgtest.MustExec(t, db, `UPDATE evm.txes SET state='confirmed' WHERE id = $1`, etx_other_chain.ID) attempt2_9 := newBroadcastLegacyEthTxAttempt(t, etx2_9.ID, int64(1)) require.NoError(t, txStore.InsertTxAttempt(&attempt2_9)) @@ -914,7 +914,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { attempt3_1 := newBroadcastLegacyEthTxAttempt(t, etx3.ID, int64(1)) require.NoError(t, txStore.InsertTxAttempt(&attempt3_1)) - pgtest.MustExec(t, db, `UPDATE eth_tx_attempts SET broadcast_before_block_num = 41 WHERE broadcast_before_block_num IS NULL`) + pgtest.MustExec(t, db, `UPDATE evm.tx_attempts SET broadcast_before_block_num = 41 WHERE broadcast_before_block_num IS NULL`) t.Run("marks buried eth_txes as 'confirmed_missing_receipt'", func(t *testing.T) { txmReceipt0 := evmtypes.Receipt{ @@ -1400,7 +1400,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { nonce++ attempt1_1 := etx1.TxAttempts[0] dbAttempt := txmgr.DbEthTxAttemptFromEthTxAttempt(&attempt1_1) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, tooNew, attempt1_1.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, tooNew, attempt1_1.ID)) attempt1_2 := newBroadcastLegacyEthTxAttempt(t, etx1.ID) attempt1_2.BroadcastBeforeBlockNum = &onTheMoney attempt1_2.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(30000)} @@ -1417,7 +1417,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { nonce++ attempt2_1 := etx2.TxAttempts[0] dbAttempt = txmgr.DbEthTxAttemptFromEthTxAttempt(&attempt2_1) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, tooNew, attempt2_1.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, tooNew, attempt2_1.ID)) t.Run("returns nothing when the transaction has attempts that are too new", func(t *testing.T) { etxs, err := ec.FindTxsRequiringRebroadcast(testutils.Context(t), lggr, evmFromAddress, currentHead, gasBumpThreshold, 10, 0, &cltest.FixtureChainID) @@ -1464,13 +1464,13 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { nonce++ attempt3_1 := etx3.TxAttempts[0] dbAttempt = txmgr.DbEthTxAttemptFromEthTxAttempt(&attempt3_1) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt3_1.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt3_1.ID)) // NOTE: It should ignore qualifying eth_txes from a different address etxOther := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, otherAddress) attemptOther1 := etxOther.TxAttempts[0] dbAttempt = txmgr.DbEthTxAttemptFromEthTxAttempt(&attemptOther1) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attemptOther1.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attemptOther1.ID)) t.Run("returns the transaction if it is unconfirmed with an attempt that is older than gasBumpThreshold blocks", func(t *testing.T) { etxs, err := ec.FindTxsRequiringRebroadcast(testutils.Context(t), lggr, evmFromAddress, currentHead, gasBumpThreshold, 10, 0, &cltest.FixtureChainID) @@ -1520,14 +1520,14 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { nonce++ attempt4_1 := etx4.TxAttempts[0] dbAttempt = txmgr.DbEthTxAttemptFromEthTxAttempt(&attemptOther1) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt4_1.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt4_1.ID)) t.Run("ignores pending transactions for another key", func(t *testing.T) { // Re-use etx3 nonce for another key, it should not affect the results for this key etxOther := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, (*etx3.Sequence).Int64(), otherAddress) aOther := etxOther.TxAttempts[0] dbAttempt = txmgr.DbEthTxAttemptFromEthTxAttempt(&aOther) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, aOther.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, aOther.ID)) etxs, err := ec.FindTxsRequiringRebroadcast(testutils.Context(t), lggr, evmFromAddress, currentHead, gasBumpThreshold, 6, 0, &cltest.FixtureChainID) require.NoError(t, err) @@ -1660,7 +1660,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, nonce, fromAddress, originalBroadcastAt) attempt1 := etx.TxAttempts[0] dbAttempt := txmgr.DbEthTxAttemptFromEthTxAttempt(&attempt1) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt1.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt1.ID)) // Send transaction and assume success. ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return(clienttypes.Successful, nil).Once() @@ -1704,7 +1704,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, nonce, fromAddress, originalBroadcastAt) attempt1 := etx.TxAttempts[0] dbAttempt := txmgr.DbEthTxAttemptFromEthTxAttempt(&attempt1) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt1.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt1.ID)) // Send transaction and assume success. ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return(clienttypes.Successful, nil).Once() @@ -1754,7 +1754,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { nonce++ attempt1_1 := etx.TxAttempts[0] var dbAttempt txmgr.DbEthTxAttempt - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt1_1.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt1_1.ID)) t.Run("re-sends previous transaction on keystore error", func(t *testing.T) { // simulate bumped transaction that is somehow impossible to sign @@ -1889,7 +1889,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { require.Len(t, etx.TxAttempts, 2) }) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt1_2.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt1_2.ID)) var attempt1_3 txmgr.TxAttempt t.Run("creates new attempt with higher gas price if transaction is already in mempool (e.g. due to previous crash before we could save the new attempt)", func(t *testing.T) { @@ -1927,7 +1927,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { assert.Equal(t, txmgrtypes.TxAttemptBroadcast, attempt1_3.State) }) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt1_3.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt1_3.ID)) var attempt1_4 txmgr.TxAttempt t.Run("saves new attempt even for transaction that has already been confirmed (nonce already used)", func(t *testing.T) { @@ -1975,12 +1975,12 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { }) // Mark original tx as confirmed so we won't pick it up any more - pgtest.MustExec(t, db, `UPDATE eth_txes SET state = 'confirmed'`) + pgtest.MustExec(t, db, `UPDATE evm.txes SET state = 'confirmed'`) etx2 := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, nonce, fromAddress) nonce++ attempt2_1 := etx2.TxAttempts[0] - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt2_1.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt2_1.ID)) var attempt2_2 txmgr.TxAttempt t.Run("saves in_progress attempt on temporary error and returns error", func(t *testing.T) { @@ -2048,7 +2048,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { }) // Set BroadcastBeforeBlockNum again so the next test will pick it up - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt2_2.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt2_2.ID)) t.Run("assumes that 'nonce too low' error means confirmed_missing_receipt", func(t *testing.T) { expectedBumpedGasPrice := big.NewInt(25000000000) @@ -2087,7 +2087,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { etx3 := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, nonce, fromAddress) nonce++ attempt3_1 := etx3.TxAttempts[0] - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1, gas_price=$2 WHERE id=$3 RETURNING *`, oldEnough, assets.NewWeiI(35000000000), attempt3_1.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1, gas_price=$2 WHERE id=$3 RETURNING *`, oldEnough, assets.NewWeiI(35000000000), attempt3_1.ID)) var attempt3_2 txmgr.TxAttempt @@ -2125,7 +2125,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { assert.Equal(t, expectedBumpedGasPrice.Int64(), attempt3_2.TxFee.Legacy.ToInt().Int64()) }) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt3_2.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt3_2.ID)) var attempt3_3 txmgr.TxAttempt t.Run("handles case where transaction is already known somehow", func(t *testing.T) { @@ -2160,7 +2160,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { assert.Equal(t, expectedBumpedGasPrice.Int64(), attempt3_3.TxFee.Legacy.ToInt().Int64()) }) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt3_3.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt3_3.ID)) var attempt3_4 txmgr.TxAttempt t.Run("pretends it was accepted and continues the cycle if rejected for being temporarily underpriced", func(t *testing.T) { @@ -2199,7 +2199,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { assert.Equal(t, expectedBumpedGasPrice.Int64(), attempt3_4.TxFee.Legacy.ToInt().Int64()) }) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt3_4.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt3_4.ID)) t.Run("resubmits at the old price and does not create a new attempt if one of the bumped transactions would exceed EVM.GasEstimator.PriceMax", func(t *testing.T) { // Set price such that the next bump will exceed EVM.GasEstimator.PriceMax @@ -2230,7 +2230,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { assert.Equal(t, gasPrice.Int64(), attempt3_4.TxFee.Legacy.ToInt().Int64()) }) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt3_4.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt3_4.ID)) t.Run("resubmits at the old price and does not create a new attempt if the current price is exactly EVM.GasEstimator.PriceMax", func(t *testing.T) { // Set price such that the current price is already at EVM.GasEstimator.PriceMax @@ -2264,7 +2264,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // The EIP-1559 etx and attempt etx4 := cltest.MustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, nonce, fromAddress) attempt4_1 := etx4.TxAttempts[0] - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1, gas_tip_cap=$2, gas_fee_cap=$3 WHERE id=$4 RETURNING *`, + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1, gas_tip_cap=$2, gas_fee_cap=$3 WHERE id=$4 RETURNING *`, oldEnough, assets.GWei(35), assets.GWei(100), attempt4_1.ID)) var attempt4_2 txmgr.TxAttempt @@ -2301,7 +2301,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { assert.Equal(t, txmgrtypes.TxAttemptBroadcast, attempt1_2.State) }) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1, gas_tip_cap=$2, gas_fee_cap=$3 WHERE id=$4 RETURNING *`, + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1, gas_tip_cap=$2, gas_fee_cap=$3 WHERE id=$4 RETURNING *`, oldEnough, assets.GWei(999), assets.GWei(1000), attempt4_2.ID)) t.Run("EIP-1559: resubmits at the old price and does not create a new attempt if one of the bumped EIP-1559 transactions would have its tip cap exceed EVM.GasEstimator.PriceMax", func(t *testing.T) { @@ -2331,7 +2331,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { assert.Equal(t, assets.GWei(1000).Int64(), attempt4_2.TxFee.DynamicFeeCap.ToInt().Int64()) }) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1, gas_tip_cap=$2, gas_fee_cap=$3 WHERE id=$4 RETURNING *`, + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1, gas_tip_cap=$2, gas_fee_cap=$3 WHERE id=$4 RETURNING *`, oldEnough, assets.GWei(45), assets.GWei(100), attempt4_2.ID)) t.Run("EIP-1559: saves attempt anyway if replacement transaction is underpriced because the bumped gas price is insufficiently higher than the previous one", func(t *testing.T) { @@ -2431,7 +2431,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh nonce++ legacyAttempt := etx.TxAttempts[0] dbAttempt := txmgr.DbEthTxAttemptFromEthTxAttempt(&legacyAttempt) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, legacyAttempt.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, legacyAttempt.ID)) // Fail a few times with terminally underpriced ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return( @@ -2463,7 +2463,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh nonce++ dxFeeAttempt := etx.TxAttempts[0] dbAttempt := txmgr.DbEthTxAttemptFromEthTxAttempt(&dxFeeAttempt) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, dxFeeAttempt.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, dxFeeAttempt.ID)) // Fail a few times with terminally underpriced ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return( @@ -2514,7 +2514,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { nonce++ attempt1_1 := etx.TxAttempts[0] dbAttempt := txmgr.DbEthTxAttemptFromEthTxAttempt(&attempt1_1) - require.NoError(t, db.Get(&dbAttempt, `UPDATE eth_tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt1_1.ID)) + require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt1_1.ID)) var attempt1_2 txmgr.TxAttempt insufficientEthError := errors.New("insufficient funds for gas * price + value") @@ -2623,7 +2623,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { var dbAttempts []txmgr.DbEthTxAttempt - require.NoError(t, db.Select(&dbAttempts, "SELECT * FROM eth_tx_attempts WHERE state = 'insufficient_eth'")) + require.NoError(t, db.Select(&dbAttempts, "SELECT * FROM evm.tx_attempts WHERE state = 'insufficient_eth'")) require.Len(t, dbAttempts, 0) }) } @@ -2954,7 +2954,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 1, 1, fromAddress) cltest.MustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, etx.TxAttempts[0].Hash) - pgtest.MustExec(t, db, `UPDATE eth_txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) + pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) err = ec.ResumePendingTaskRuns(testutils.Context(t), &head) require.NoError(t, err) @@ -2974,7 +2974,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 2, 1, fromAddress) cltest.MustInsertEthReceipt(t, txStore, head.Number, head.Hash, etx.TxAttempts[0].Hash) - pgtest.MustExec(t, db, `UPDATE eth_txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) + pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) err = ec.ResumePendingTaskRuns(testutils.Context(t), &head) require.NoError(t, err) @@ -2996,10 +2996,10 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { pgtest.MustExec(t, db, `UPDATE pipeline_runs SET state = 'suspended' WHERE id = $1`, run.ID) etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 3, 1, fromAddress) - pgtest.MustExec(t, db, `UPDATE eth_txes SET meta='{"FailOnRevert": true}'`) + pgtest.MustExec(t, db, `UPDATE evm.txes SET meta='{"FailOnRevert": true}'`) receipt := cltest.MustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, etx.TxAttempts[0].Hash) - pgtest.MustExec(t, db, `UPDATE eth_txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) + pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) go func() { err2 := ec.ResumePendingTaskRuns(testutils.Context(t), &head) @@ -3036,12 +3036,12 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { pgtest.MustExec(t, db, `UPDATE pipeline_runs SET state = 'suspended' WHERE id = $1`, run.ID) etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 4, 1, fromAddress) - pgtest.MustExec(t, db, `UPDATE eth_txes SET meta='{"FailOnRevert": true}'`) + pgtest.MustExec(t, db, `UPDATE evm.txes SET meta='{"FailOnRevert": true}'`) // receipt is not passed through as a value since it reverted and caused an error cltest.MustInsertRevertedEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, etx.TxAttempts[0].Hash) - pgtest.MustExec(t, db, `UPDATE eth_txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) + pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) go func() { err2 := ec.ResumePendingTaskRuns(testutils.Context(t), &head) diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index dbd3437aa82..4585d868603 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -81,7 +81,7 @@ type evmTxStore struct { var _ EvmTxStore = (*evmTxStore)(nil) var _ TestEvmTxStore = (*evmTxStore)(nil) -// Directly maps to columns of database table "eth_receipts". +// Directly maps to columns of database table "evm.receipts". // Do not modify type unless you // intend to modify the database schema type dbReceipt struct { @@ -148,7 +148,7 @@ func toOnchainReceipt(rs []*evmtypes.Receipt) []rawOnchainReceipt { return receipts } -// Directly maps to columns of database table "eth_txes". +// Directly maps to columns of database table "evm.txes". // This is exported, as tests and other external code still directly reads DB using this schema. type DbEthTx struct { ID int64 @@ -253,7 +253,7 @@ func dbEthTxsToEvmEthTxPtrs(dbEthTxs []DbEthTx, evmEthTxs []*Tx) { } } -// Directly maps to columns of database table "eth_tx_attempts". +// Directly maps to columns of database table "evm.tx_attempts". // This is exported, as tests and other external code still directly reads DB using this schema. type DbEthTxAttempt struct { ID int64 @@ -344,7 +344,7 @@ func NewTxStore( } const insertIntoEthTxAttemptsQuery = ` -INSERT INTO eth_tx_attempts (eth_tx_id, gas_price, signed_raw_tx, hash, broadcast_before_block_num, state, created_at, chain_specific_gas_limit, tx_type, gas_tip_cap, gas_fee_cap) +INSERT INTO evm.tx_attempts (eth_tx_id, gas_price, signed_raw_tx, hash, broadcast_before_block_num, state, created_at, chain_specific_gas_limit, tx_type, gas_tip_cap, gas_fee_cap) VALUES (:eth_tx_id, :gas_price, :signed_raw_tx, :hash, :broadcast_before_block_num, :state, NOW(), :chain_specific_gas_limit, :tx_type, :gas_tip_cap, :gas_fee_cap) RETURNING *; ` @@ -365,7 +365,7 @@ func (o *evmTxStore) preloadTxAttempts(txs []Tx) error { return nil } var dbAttempts []DbEthTxAttempt - sql := `SELECT * FROM eth_tx_attempts WHERE eth_tx_id IN (?) ORDER BY id desc;` + sql := `SELECT * FROM evm.tx_attempts WHERE eth_tx_id IN (?) ORDER BY id desc;` query, args, err := sqlx.In(sql, ids) if err != nil { return err @@ -400,7 +400,7 @@ func (o *evmTxStore) PreloadTxes(attempts []TxAttempt, qopts ...pg.QOpt) error { } dbEthTxs := make([]DbEthTx, len(ethTxIDs)) qq := o.q.WithOpts(qopts...) - if err := qq.Select(&dbEthTxs, `SELECT * FROM eth_txes WHERE id = ANY($1)`, pq.Array(ethTxIDs)); err != nil { + if err := qq.Select(&dbEthTxs, `SELECT * FROM evm.txes WHERE id = ANY($1)`, pq.Array(ethTxIDs)); err != nil { return pkgerrors.Wrap(err, "loadEthTxes failed") } for _, dbEtx := range dbEthTxs { @@ -417,12 +417,12 @@ func (o *evmTxStore) PreloadTxes(attempts []TxAttempt, qopts ...pg.QOpt) error { // Transactions returns all eth transactions without loaded relations // limited by passed parameters. func (o *evmTxStore) Transactions(offset, limit int) (txs []Tx, count int, err error) { - sql := `SELECT count(*) FROM eth_txes WHERE id IN (SELECT DISTINCT eth_tx_id FROM eth_tx_attempts)` + sql := `SELECT count(*) FROM evm.txes WHERE id IN (SELECT DISTINCT eth_tx_id FROM evm.tx_attempts)` if err = o.q.Get(&count, sql); err != nil { return } - sql = `SELECT * FROM eth_txes WHERE id IN (SELECT DISTINCT eth_tx_id FROM eth_tx_attempts) ORDER BY id desc LIMIT $1 OFFSET $2` + sql = `SELECT * FROM evm.txes WHERE id IN (SELECT DISTINCT eth_tx_id FROM evm.tx_attempts) ORDER BY id desc LIMIT $1 OFFSET $2` var dbEthTxs []DbEthTx if err = o.q.Select(&dbEthTxs, sql, limit, offset); err != nil { return @@ -434,12 +434,12 @@ func (o *evmTxStore) Transactions(offset, limit int) (txs []Tx, count int, err e // TransactionsWithAttempts returns all eth transactions with at least one attempt // limited by passed parameters. Attempts are sorted by id. func (o *evmTxStore) TransactionsWithAttempts(offset, limit int) (txs []Tx, count int, err error) { - sql := `SELECT count(*) FROM eth_txes WHERE id IN (SELECT DISTINCT eth_tx_id FROM eth_tx_attempts)` + sql := `SELECT count(*) FROM evm.txes WHERE id IN (SELECT DISTINCT eth_tx_id FROM evm.tx_attempts)` if err = o.q.Get(&count, sql); err != nil { return } - sql = `SELECT * FROM eth_txes WHERE id IN (SELECT DISTINCT eth_tx_id FROM eth_tx_attempts) ORDER BY id desc LIMIT $1 OFFSET $2` + sql = `SELECT * FROM evm.txes WHERE id IN (SELECT DISTINCT eth_tx_id FROM evm.tx_attempts) ORDER BY id desc LIMIT $1 OFFSET $2` var dbTxs []DbEthTx if err = o.q.Select(&dbTxs, sql, limit, offset); err != nil { return @@ -451,12 +451,12 @@ func (o *evmTxStore) TransactionsWithAttempts(offset, limit int) (txs []Tx, coun // TxAttempts returns the last tx attempts sorted by created_at descending. func (o *evmTxStore) TxAttempts(offset, limit int) (txs []TxAttempt, count int, err error) { - sql := `SELECT count(*) FROM eth_tx_attempts` + sql := `SELECT count(*) FROM evm.tx_attempts` if err = o.q.Get(&count, sql); err != nil { return } - sql = `SELECT * FROM eth_tx_attempts ORDER BY created_at DESC, id DESC LIMIT $1 OFFSET $2` + sql = `SELECT * FROM evm.tx_attempts ORDER BY created_at DESC, id DESC LIMIT $1 OFFSET $2` var dbTxs []DbEthTxAttempt if err = o.q.Select(&dbTxs, sql, limit, offset); err != nil { return @@ -469,7 +469,7 @@ func (o *evmTxStore) TxAttempts(offset, limit int) (txs []TxAttempt, count int, // FindTxAttempt returns an individual TxAttempt func (o *evmTxStore) FindTxAttempt(hash common.Hash) (*TxAttempt, error) { dbTxAttempt := DbEthTxAttempt{} - sql := `SELECT * FROM eth_tx_attempts WHERE hash = $1` + sql := `SELECT * FROM evm.tx_attempts WHERE hash = $1` if err := o.q.Get(&dbTxAttempt, sql, hash); err != nil { return nil, err } @@ -483,7 +483,7 @@ func (o *evmTxStore) FindTxAttempt(hash common.Hash) (*TxAttempt, error) { // FindTxAttemptsByTxIDs returns a list of attempts by ETH Tx IDs func (o *evmTxStore) FindTxAttemptsByTxIDs(ids []int64) ([]TxAttempt, error) { - sql := `SELECT * FROM eth_tx_attempts WHERE eth_tx_id = ANY($1)` + sql := `SELECT * FROM evm.tx_attempts WHERE eth_tx_id = ANY($1)` var dbTxAttempts []DbEthTxAttempt if err := o.q.Select(&dbTxAttempts, sql, ids); err != nil { return nil, err @@ -494,7 +494,7 @@ func (o *evmTxStore) FindTxAttemptsByTxIDs(ids []int64) ([]TxAttempt, error) { func (o *evmTxStore) FindTxByHash(hash common.Hash) (*Tx, error) { var dbEtx DbEthTx err := o.q.Transaction(func(tx pg.Queryer) error { - sql := `SELECT eth_txes.* FROM eth_txes WHERE id IN (SELECT DISTINCT eth_tx_id FROM eth_tx_attempts WHERE hash = $1)` + sql := `SELECT evm.txes.* FROM evm.txes WHERE id IN (SELECT DISTINCT eth_tx_id FROM evm.tx_attempts WHERE hash = $1)` if err := tx.Get(&dbEtx, sql, hash); err != nil { return pkgerrors.Wrapf(err, "failed to find eth_tx with hash %d", hash) } @@ -511,7 +511,7 @@ func (o *evmTxStore) InsertTx(etx *Tx) error { if etx.CreatedAt == (time.Time{}) { etx.CreatedAt = time.Now() } - const insertEthTxSQL = `INSERT INTO eth_txes (nonce, from_address, to_address, encoded_payload, value, gas_limit, error, broadcast_at, initial_broadcast_at, created_at, state, meta, subject, pipeline_task_run_id, min_confirmations, evm_chain_id, transmit_checker) VALUES ( + const insertEthTxSQL = `INSERT INTO evm.txes (nonce, from_address, to_address, encoded_payload, value, gas_limit, error, broadcast_at, initial_broadcast_at, created_at, state, meta, subject, pipeline_task_run_id, min_confirmations, evm_chain_id, transmit_checker) VALUES ( :nonce, :from_address, :to_address, :encoded_payload, :value, :gas_limit, :error, :broadcast_at, :initial_broadcast_at, :created_at, :state, :meta, :subject, :pipeline_task_run_id, :min_confirmations, :evm_chain_id, :transmit_checker ) RETURNING *` dbTx := DbEthTxFromEthTx(etx) @@ -533,7 +533,7 @@ func (o *evmTxStore) InsertReceipt(receipt *evmtypes.Receipt) (int64, error) { // convert to database representation r := DbReceiptFromEvmReceipt(receipt) - const insertEthReceiptSQL = `INSERT INTO eth_receipts (tx_hash, block_hash, block_number, transaction_index, receipt, created_at) VALUES ( + const insertEthReceiptSQL = `INSERT INTO evm.receipts (tx_hash, block_hash, block_number, transaction_index, receipt, created_at) VALUES ( :tx_hash, :block_hash, :block_number, :transaction_index, :receipt, NOW() ) RETURNING *` err := o.q.GetNamed(insertEthReceiptSQL, &r, &r) @@ -545,15 +545,15 @@ func (o *evmTxStore) InsertReceipt(receipt *evmtypes.Receipt) (int64, error) { func (o *evmTxStore) FindTxWithAttempts(etxID int64) (etx Tx, err error) { err = o.q.Transaction(func(tx pg.Queryer) error { var dbEtx DbEthTx - if err = tx.Get(&dbEtx, `SELECT * FROM eth_txes WHERE id = $1 ORDER BY created_at ASC, id ASC`, etxID); err != nil { + if err = tx.Get(&dbEtx, `SELECT * FROM evm.txes WHERE id = $1 ORDER BY created_at ASC, id ASC`, etxID); err != nil { return pkgerrors.Wrapf(err, "failed to find eth_tx with id %d", etxID) } DbEthTxToEthTx(dbEtx, &etx) if err = o.LoadTxAttempts(&etx, pg.WithQueryer(tx)); err != nil { - return pkgerrors.Wrapf(err, "failed to load eth_tx_attempts for eth_tx with id %d", etxID) + return pkgerrors.Wrapf(err, "failed to load evm.tx_attempts for eth_tx with id %d", etxID) } if err = loadEthTxAttemptsReceipts(tx, &etx); err != nil { - return pkgerrors.Wrapf(err, "failed to load eth_receipts for eth_tx with id %d", etxID) + return pkgerrors.Wrapf(err, "failed to load evm.receipts for eth_tx with id %d", etxID) } return nil }, pg.OptReadOnlyTx()) @@ -565,8 +565,8 @@ func (o *evmTxStore) FindTxAttemptConfirmedByTxIDs(ids []int64) ([]TxAttempt, er err := o.q.Transaction(func(tx pg.Queryer) error { var dbAttempts []DbEthTxAttempt if err := tx.Select(&dbAttempts, `SELECT eta.* - FROM eth_tx_attempts eta - join eth_receipts er on eta.hash = er.tx_hash where eta.eth_tx_id = ANY($1) ORDER BY eta.gas_price DESC, eta.gas_tip_cap DESC`, ids); err != nil { + FROM evm.tx_attempts eta + join evm.receipts er on eta.hash = er.tx_hash where eta.eth_tx_id = ANY($1) ORDER BY eta.gas_price DESC, eta.gas_tip_cap DESC`, ids); err != nil { return err } txAttempts = dbEthTxAttemptsToEthTxAttempts(dbAttempts) @@ -585,8 +585,8 @@ func (o *evmTxStore) LoadTxesAttempts(etxs []*Tx, qopts ...pg.QOpt) error { ethTxesM[etx.ID] = etxs[i] } var dbTxAttempts []DbEthTxAttempt - if err := qq.Select(&dbTxAttempts, `SELECT * FROM eth_tx_attempts WHERE eth_tx_id = ANY($1) ORDER BY eth_tx_attempts.gas_price DESC, eth_tx_attempts.gas_tip_cap DESC`, pq.Array(ethTxIDs)); err != nil { - return pkgerrors.Wrap(err, "loadEthTxesAttempts failed to load eth_tx_attempts") + if err := qq.Select(&dbTxAttempts, `SELECT * FROM evm.tx_attempts WHERE eth_tx_id = ANY($1) ORDER BY evm.tx_attempts.gas_price DESC, evm.tx_attempts.gas_tip_cap DESC`, pq.Array(ethTxIDs)); err != nil { + return pkgerrors.Wrap(err, "loadEthTxesAttempts failed to load evm.tx_attempts") } for _, dbAttempt := range dbTxAttempts { etx := ethTxesM[dbAttempt.EthTxID] @@ -618,8 +618,8 @@ func loadEthTxesAttemptsReceipts(q pg.Queryer, etxs []*Tx) (err error) { } } var rs []dbReceipt - if err = q.Select(&rs, `SELECT * FROM eth_receipts WHERE tx_hash = ANY($1)`, pq.Array(attemptHashes)); err != nil { - return pkgerrors.Wrap(err, "loadEthTxesAttemptsReceipts failed to load eth_receipts") + if err = q.Select(&rs, `SELECT * FROM evm.receipts WHERE tx_hash = ANY($1)`, pq.Array(attemptHashes)); err != nil { + return pkgerrors.Wrap(err, "loadEthTxesAttemptsReceipts failed to load evm.receipts") } var receipts []*evmtypes.Receipt = fromDBReceipts(rs) @@ -639,8 +639,8 @@ func loadConfirmedAttemptsReceipts(q pg.Queryer, attempts []TxAttempt) error { hashes = append(hashes, attempt.Hash.Bytes()) } var rs []dbReceipt - if err := q.Select(&rs, `SELECT * FROM eth_receipts WHERE tx_hash = ANY($1)`, pq.Array(hashes)); err != nil { - return pkgerrors.Wrap(err, "loadConfirmedAttemptsReceipts failed to load eth_receipts") + if err := q.Select(&rs, `SELECT * FROM evm.receipts WHERE tx_hash = ANY($1)`, pq.Array(hashes)); err != nil { + return pkgerrors.Wrap(err, "loadConfirmedAttemptsReceipts failed to load evm.receipts") } var receipts []*evmtypes.Receipt = fromDBReceipts(rs) for _, receipt := range receipts { @@ -658,19 +658,19 @@ func (o *evmTxStore) FindTxAttemptsRequiringResend(olderThan time.Time, maxInFli limit = null.Uint32From(maxInFlightTransactions) } var dbAttempts []DbEthTxAttempt - // this select distinct works because of unique index on eth_txes + // this select distinct works because of unique index on evm.txes // (evm_chain_id, from_address, nonce) err = o.q.Select(&dbAttempts, ` -SELECT DISTINCT ON (eth_txes.nonce) eth_tx_attempts.* -FROM eth_tx_attempts -JOIN eth_txes ON eth_txes.id = eth_tx_attempts.eth_tx_id AND eth_txes.state IN ('unconfirmed', 'confirmed_missing_receipt') -WHERE eth_tx_attempts.state <> 'in_progress' AND eth_txes.broadcast_at <= $1 AND evm_chain_id = $2 AND from_address = $3 -ORDER BY eth_txes.nonce ASC, eth_tx_attempts.gas_price DESC, eth_tx_attempts.gas_tip_cap DESC +SELECT DISTINCT ON (evm.txes.nonce) evm.tx_attempts.* +FROM evm.tx_attempts +JOIN evm.txes ON evm.txes.id = evm.tx_attempts.eth_tx_id AND evm.txes.state IN ('unconfirmed', 'confirmed_missing_receipt') +WHERE evm.tx_attempts.state <> 'in_progress' AND evm.txes.broadcast_at <= $1 AND evm_chain_id = $2 AND from_address = $3 +ORDER BY evm.txes.nonce ASC, evm.tx_attempts.gas_price DESC, evm.tx_attempts.gas_tip_cap DESC LIMIT $4 `, olderThan, chainID.String(), address, limit) attempts = dbEthTxAttemptsToEthTxAttempts(dbAttempts) - return attempts, pkgerrors.Wrap(err, "FindEthTxAttemptsRequiringResend failed to load eth_tx_attempts") + return attempts, pkgerrors.Wrap(err, "FindEthTxAttemptsRequiringResend failed to load evm.tx_attempts") } func (o *evmTxStore) UpdateBroadcastAts(now time.Time, etxIDs []int64) error { @@ -681,8 +681,8 @@ func (o *evmTxStore) UpdateBroadcastAts(now time.Time, etxIDs []int64) error { // Since EthConfirmer/EthResender can race (totally OK since highest // priced transaction always wins) we only want to update broadcast_at if // our version is later. - _, err := o.q.Exec(`UPDATE eth_txes SET broadcast_at = $1 WHERE id = ANY($2) AND broadcast_at < $1`, now, pq.Array(etxIDs)) - return pkgerrors.Wrap(err, "updateBroadcastAts failed to update eth_txes") + _, err := o.q.Exec(`UPDATE evm.txes SET broadcast_at = $1 WHERE id = ANY($2) AND broadcast_at < $1`, now, pq.Array(etxIDs)) + return pkgerrors.Wrap(err, "updateBroadcastAts failed to update evm.txes") } // SetBroadcastBeforeBlockNum updates already broadcast attempts with the @@ -690,11 +690,11 @@ func (o *evmTxStore) UpdateBroadcastAts(now time.Time, etxIDs []int64) error { // the attempt is already broadcast it _must_ have been before this head. func (o *evmTxStore) SetBroadcastBeforeBlockNum(blockNum int64, chainID *big.Int) error { _, err := o.q.Exec( - `UPDATE eth_tx_attempts + `UPDATE evm.tx_attempts SET broadcast_before_block_num = $1 -FROM eth_txes -WHERE eth_tx_attempts.broadcast_before_block_num IS NULL AND eth_tx_attempts.state = 'broadcast' -AND eth_txes.id = eth_tx_attempts.eth_tx_id AND eth_txes.evm_chain_id = $2`, +FROM evm.txes +WHERE evm.tx_attempts.broadcast_before_block_num IS NULL AND evm.tx_attempts.state = 'broadcast' +AND evm.txes.id = evm.tx_attempts.eth_tx_id AND evm.txes.evm_chain_id = $2`, blockNum, chainID.String(), ) return pkgerrors.Wrap(err, "SetBroadcastBeforeBlockNum failed") @@ -703,11 +703,11 @@ AND eth_txes.id = eth_tx_attempts.eth_tx_id AND eth_txes.evm_chain_id = $2`, func (o *evmTxStore) FindTxAttemptsConfirmedMissingReceipt(chainID *big.Int) (attempts []TxAttempt, err error) { var dbAttempts []DbEthTxAttempt err = o.q.Select(&dbAttempts, - `SELECT DISTINCT ON (eth_tx_attempts.eth_tx_id) eth_tx_attempts.* - FROM eth_tx_attempts - JOIN eth_txes ON eth_txes.id = eth_tx_attempts.eth_tx_id AND eth_txes.state = 'confirmed_missing_receipt' + `SELECT DISTINCT ON (evm.tx_attempts.eth_tx_id) evm.tx_attempts.* + FROM evm.tx_attempts + JOIN evm.txes ON evm.txes.id = evm.tx_attempts.eth_tx_id AND evm.txes.state = 'confirmed_missing_receipt' WHERE evm_chain_id = $1 - ORDER BY eth_tx_attempts.eth_tx_id ASC, eth_tx_attempts.gas_price DESC, eth_tx_attempts.gas_tip_cap DESC`, + ORDER BY evm.tx_attempts.eth_tx_id ASC, evm.tx_attempts.gas_price DESC, evm.tx_attempts.gas_tip_cap DESC`, chainID.String()) if err != nil { err = pkgerrors.Wrap(err, "FindEtxAttemptsConfirmedMissingReceipt failed to query") @@ -717,7 +717,7 @@ func (o *evmTxStore) FindTxAttemptsConfirmedMissingReceipt(chainID *big.Int) (at } func (o *evmTxStore) UpdateTxsUnconfirmed(ids []int64) error { - _, err := o.q.Exec(`UPDATE eth_txes SET state='unconfirmed' WHERE id = ANY($1)`, pq.Array(ids)) + _, err := o.q.Exec(`UPDATE evm.txes SET state='unconfirmed' WHERE id = ANY($1)`, pq.Array(ids)) if err != nil { return pkgerrors.Wrap(err, "UpdateEthTxsUnconfirmed failed to execute") @@ -729,17 +729,17 @@ func (o *evmTxStore) FindTxAttemptsRequiringReceiptFetch(chainID *big.Int) (atte err = o.q.Transaction(func(tx pg.Queryer) error { var dbAttempts []DbEthTxAttempt err = tx.Select(&dbAttempts, ` -SELECT eth_tx_attempts.* FROM eth_tx_attempts -JOIN eth_txes ON eth_txes.id = eth_tx_attempts.eth_tx_id AND eth_txes.state IN ('unconfirmed', 'confirmed_missing_receipt') AND eth_txes.evm_chain_id = $1 -WHERE eth_tx_attempts.state != 'insufficient_eth' -ORDER BY eth_txes.nonce ASC, eth_tx_attempts.gas_price DESC, eth_tx_attempts.gas_tip_cap DESC +SELECT evm.tx_attempts.* FROM evm.tx_attempts +JOIN evm.txes ON evm.txes.id = evm.tx_attempts.eth_tx_id AND evm.txes.state IN ('unconfirmed', 'confirmed_missing_receipt') AND evm.txes.evm_chain_id = $1 +WHERE evm.tx_attempts.state != 'insufficient_eth' +ORDER BY evm.txes.nonce ASC, evm.tx_attempts.gas_price DESC, evm.tx_attempts.gas_tip_cap DESC `, chainID.String()) if err != nil { - return pkgerrors.Wrap(err, "FindEthTxAttemptsRequiringReceiptFetch failed to load eth_tx_attempts") + return pkgerrors.Wrap(err, "FindEthTxAttemptsRequiringReceiptFetch failed to load evm.tx_attempts") } attempts = dbEthTxAttemptsToEthTxAttempts(dbAttempts) err = o.PreloadTxes(attempts, pg.WithQueryer(tx)) - return pkgerrors.Wrap(err, "FindEthTxAttemptsRequiringReceiptFetch failed to load eth_txes") + return pkgerrors.Wrap(err, "FindEthTxAttemptsRequiringReceiptFetch failed to load evm.txes") }, pg.OptReadOnlyTx()) return } @@ -793,27 +793,27 @@ func (o *evmTxStore) SaveFetchedReceipts(r []*evmtypes.Receipt, chainID *big.Int /* #nosec G201 */ sql := ` WITH inserted_receipts AS ( - INSERT INTO eth_receipts (tx_hash, block_hash, block_number, transaction_index, receipt, created_at) + INSERT INTO evm.receipts (tx_hash, block_hash, block_number, transaction_index, receipt, created_at) VALUES %s ON CONFLICT (tx_hash, block_hash) DO UPDATE SET block_number = EXCLUDED.block_number, transaction_index = EXCLUDED.transaction_index, receipt = EXCLUDED.receipt - RETURNING eth_receipts.tx_hash, eth_receipts.block_number + RETURNING evm.receipts.tx_hash, evm.receipts.block_number ), updated_eth_tx_attempts AS ( - UPDATE eth_tx_attempts + UPDATE evm.tx_attempts SET state = 'broadcast', - broadcast_before_block_num = COALESCE(eth_tx_attempts.broadcast_before_block_num, inserted_receipts.block_number) + broadcast_before_block_num = COALESCE(evm.tx_attempts.broadcast_before_block_num, inserted_receipts.block_number) FROM inserted_receipts - WHERE inserted_receipts.tx_hash = eth_tx_attempts.hash - RETURNING eth_tx_attempts.eth_tx_id + WHERE inserted_receipts.tx_hash = evm.tx_attempts.hash + RETURNING evm.tx_attempts.eth_tx_id ) - UPDATE eth_txes + UPDATE evm.txes SET state = 'confirmed' FROM updated_eth_tx_attempts - WHERE updated_eth_tx_attempts.eth_tx_id = eth_txes.id + WHERE updated_eth_tx_attempts.eth_tx_id = evm.txes.id AND evm_chain_id = ? ` @@ -826,7 +826,7 @@ func (o *evmTxStore) SaveFetchedReceipts(r []*evmtypes.Receipt, chainID *big.Int } // MarkAllConfirmedMissingReceipt -// It is possible that we can fail to get a receipt for all eth_tx_attempts +// It is possible that we can fail to get a receipt for all evm.tx_attempts // even though a transaction with this nonce has long since been confirmed (we // know this because transactions with higher nonces HAVE returned a receipt). // @@ -837,7 +837,7 @@ func (o *evmTxStore) SaveFetchedReceipts(r []*evmtypes.Receipt, chainID *big.Int // In this case we mark these transactions as 'confirmed_missing_receipt' to // prevent gas bumping. // -// NOTE: We continue to attempt to resend eth_txes in this state on +// NOTE: We continue to attempt to resend evm.txes in this state on // every head to guard against the extremely rare scenario of nonce gap due to // reorg that excludes the transaction (from another wallet) that had this // nonce (until finality depth is reached, after which we make the explicit @@ -847,18 +847,18 @@ func (o *evmTxStore) SaveFetchedReceipts(r []*evmtypes.Receipt, chainID *big.Int // attempts are below the finality depth from current head. func (o *evmTxStore) MarkAllConfirmedMissingReceipt(chainID *big.Int) (err error) { res, err := o.q.Exec(` -UPDATE eth_txes +UPDATE evm.txes SET state = 'confirmed_missing_receipt' FROM ( SELECT from_address, MAX(nonce) as max_nonce - FROM eth_txes + FROM evm.txes WHERE state = 'confirmed' AND evm_chain_id = $1 GROUP BY from_address ) AS max_table WHERE state = 'unconfirmed' AND evm_chain_id = $1 AND nonce < max_table.max_nonce - AND eth_txes.from_address = max_table.from_address + AND evm.txes.from_address = max_table.from_address `, chainID.String()) if err != nil { return pkgerrors.Wrap(err, "markAllConfirmedMissingReceipt failed") @@ -878,16 +878,16 @@ func (o *evmTxStore) GetInProgressTxAttempts(ctx context.Context, address common err = qq.Transaction(func(tx pg.Queryer) error { var dbAttempts []DbEthTxAttempt err = tx.Select(&dbAttempts, ` -SELECT eth_tx_attempts.* FROM eth_tx_attempts -INNER JOIN eth_txes ON eth_txes.id = eth_tx_attempts.eth_tx_id AND eth_txes.state in ('confirmed', 'confirmed_missing_receipt', 'unconfirmed') -WHERE eth_tx_attempts.state = 'in_progress' AND eth_txes.from_address = $1 AND eth_txes.evm_chain_id = $2 +SELECT evm.tx_attempts.* FROM evm.tx_attempts +INNER JOIN evm.txes ON evm.txes.id = evm.tx_attempts.eth_tx_id AND evm.txes.state in ('confirmed', 'confirmed_missing_receipt', 'unconfirmed') +WHERE evm.tx_attempts.state = 'in_progress' AND evm.txes.from_address = $1 AND evm.txes.evm_chain_id = $2 `, address, chainID.String()) if err != nil { - return pkgerrors.Wrap(err, "getInProgressEthTxAttempts failed to load eth_tx_attempts") + return pkgerrors.Wrap(err, "getInProgressEthTxAttempts failed to load evm.tx_attempts") } attempts = dbEthTxAttemptsToEthTxAttempts(dbAttempts) err = o.PreloadTxes(attempts, pg.WithQueryer(tx)) - return pkgerrors.Wrap(err, "getInProgressEthTxAttempts failed to load eth_txes") + return pkgerrors.Wrap(err, "getInProgressEthTxAttempts failed to load evm.txes") }, pg.OptReadOnlyTx()) return attempts, pkgerrors.Wrap(err, "getInProgressEthTxAttempts failed") } @@ -896,12 +896,12 @@ func (o *evmTxStore) FindReceiptsPendingConfirmation(ctx context.Context, blockN var rs []dbReceiptPlus err = o.q.SelectContext(ctx, &rs, ` - SELECT pipeline_task_runs.id, eth_receipts.receipt, COALESCE((eth_txes.meta->>'FailOnRevert')::boolean, false) "FailOnRevert" FROM pipeline_task_runs + SELECT pipeline_task_runs.id, evm.receipts.receipt, COALESCE((evm.txes.meta->>'FailOnRevert')::boolean, false) "FailOnRevert" FROM pipeline_task_runs INNER JOIN pipeline_runs ON pipeline_runs.id = pipeline_task_runs.pipeline_run_id - INNER JOIN eth_txes ON eth_txes.pipeline_task_run_id = pipeline_task_runs.id - INNER JOIN eth_tx_attempts ON eth_txes.id = eth_tx_attempts.eth_tx_id - INNER JOIN eth_receipts ON eth_tx_attempts.hash = eth_receipts.tx_hash - WHERE pipeline_runs.state = 'suspended' AND eth_receipts.block_number <= ($1 - eth_txes.min_confirmations) AND eth_txes.evm_chain_id = $2 + INNER JOIN evm.txes ON evm.txes.pipeline_task_run_id = pipeline_task_runs.id + INNER JOIN evm.tx_attempts ON evm.txes.id = evm.tx_attempts.eth_tx_id + INNER JOIN evm.receipts ON evm.tx_attempts.hash = evm.receipts.tx_hash + WHERE pipeline_runs.state = 'suspended' AND evm.receipts.block_number <= ($1 - evm.txes.min_confirmations) AND evm.txes.evm_chain_id = $2 `, blockNum, chainID.String()) receiptsPlus = fromDBReceiptsPlus(rs) @@ -911,12 +911,12 @@ func (o *evmTxStore) FindReceiptsPendingConfirmation(ctx context.Context, blockN // FindTxWithIdempotencyKey returns any broadcast ethtx with the given idempotencyKey and chainID func (o *evmTxStore) FindTxWithIdempotencyKey(idempotencyKey string, chainID *big.Int) (etx *Tx, err error) { var dbEtx DbEthTx - err = o.q.Get(&dbEtx, `SELECT * FROM eth_txes WHERE idempotency_key = $1 and evm_chain_id = $2`, idempotencyKey, chainID.String()) + err = o.q.Get(&dbEtx, `SELECT * FROM evm.txes WHERE idempotency_key = $1 and evm_chain_id = $2`, idempotencyKey, chainID.String()) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, nil } - return nil, pkgerrors.Wrap(err, "FindTxWithIdempotencyKey failed to load eth_txes") + return nil, pkgerrors.Wrap(err, "FindTxWithIdempotencyKey failed to load evm.txes") } etx = new(Tx) DbEthTxToEthTx(dbEtx, etx) @@ -929,14 +929,14 @@ func (o *evmTxStore) FindTxWithSequence(fromAddress common.Address, nonce evmtyp err = o.q.Transaction(func(tx pg.Queryer) error { var dbEtx DbEthTx err = tx.Get(&dbEtx, ` -SELECT * FROM eth_txes WHERE from_address = $1 AND nonce = $2 AND state IN ('confirmed', 'confirmed_missing_receipt', 'unconfirmed') +SELECT * FROM evm.txes WHERE from_address = $1 AND nonce = $2 AND state IN ('confirmed', 'confirmed_missing_receipt', 'unconfirmed') `, fromAddress, nonce.Int64()) if err != nil { - return pkgerrors.Wrap(err, "FindEthTxWithNonce failed to load eth_txes") + return pkgerrors.Wrap(err, "FindEthTxWithNonce failed to load evm.txes") } DbEthTxToEthTx(dbEtx, etx) err = o.LoadTxAttempts(etx, pg.WithQueryer(tx)) - return pkgerrors.Wrap(err, "FindEthTxWithNonce failed to load eth_tx_attempts") + return pkgerrors.Wrap(err, "FindEthTxWithNonce failed to load evm.tx_attempts") }, pg.OptReadOnlyTx()) if errors.Is(err, sql.ErrNoRows) { return nil, nil @@ -948,7 +948,7 @@ func updateEthTxAttemptUnbroadcast(q pg.Queryer, attempt TxAttempt) error { if attempt.State != txmgrtypes.TxAttemptBroadcast { return errors.New("expected eth_tx_attempt to be broadcast") } - _, err := q.Exec(`UPDATE eth_tx_attempts SET broadcast_before_block_num = NULL, state = 'in_progress' WHERE id = $1`, attempt.ID) + _, err := q.Exec(`UPDATE evm.tx_attempts SET broadcast_before_block_num = NULL, state = 'in_progress' WHERE id = $1`, attempt.ID) return pkgerrors.Wrap(err, "updateEthTxAttemptUnbroadcast failed") } @@ -956,16 +956,16 @@ func updateEthTxUnconfirm(q pg.Queryer, etx Tx) error { if etx.State != txmgr.TxConfirmed { return errors.New("expected eth_tx state to be confirmed") } - _, err := q.Exec(`UPDATE eth_txes SET state = 'unconfirmed' WHERE id = $1`, etx.ID) + _, err := q.Exec(`UPDATE evm.txes SET state = 'unconfirmed' WHERE id = $1`, etx.ID) return pkgerrors.Wrap(err, "updateEthTxUnconfirm failed") } func deleteEthReceipts(q pg.Queryer, etxID int64) (err error) { _, err = q.Exec(` -DELETE FROM eth_receipts -USING eth_tx_attempts -WHERE eth_receipts.tx_hash = eth_tx_attempts.hash -AND eth_tx_attempts.eth_tx_id = $1 +DELETE FROM evm.receipts +USING evm.tx_attempts +WHERE evm.receipts.tx_hash = evm.tx_attempts.hash +AND evm.tx_attempts.eth_tx_id = $1 `, etxID) return pkgerrors.Wrap(err, "deleteEthReceipts failed") } @@ -986,22 +986,22 @@ func (o *evmTxStore) FindTransactionsConfirmedInBlockRange(highBlockNumber, lowB err = o.q.Transaction(func(tx pg.Queryer) error { var dbEtxs []DbEthTx err = tx.Select(&dbEtxs, ` -SELECT DISTINCT eth_txes.* FROM eth_txes -INNER JOIN eth_tx_attempts ON eth_txes.id = eth_tx_attempts.eth_tx_id AND eth_tx_attempts.state = 'broadcast' -INNER JOIN eth_receipts ON eth_receipts.tx_hash = eth_tx_attempts.hash -WHERE eth_txes.state IN ('confirmed', 'confirmed_missing_receipt') AND block_number BETWEEN $1 AND $2 AND evm_chain_id = $3 +SELECT DISTINCT evm.txes.* FROM evm.txes +INNER JOIN evm.tx_attempts ON evm.txes.id = evm.tx_attempts.eth_tx_id AND evm.tx_attempts.state = 'broadcast' +INNER JOIN evm.receipts ON evm.receipts.tx_hash = evm.tx_attempts.hash +WHERE evm.txes.state IN ('confirmed', 'confirmed_missing_receipt') AND block_number BETWEEN $1 AND $2 AND evm_chain_id = $3 ORDER BY nonce ASC `, lowBlockNumber, highBlockNumber, chainID.String()) if err != nil { - return pkgerrors.Wrap(err, "FindTransactionsConfirmedInBlockRange failed to load eth_txes") + return pkgerrors.Wrap(err, "FindTransactionsConfirmedInBlockRange failed to load evm.txes") } etxs = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, etxs) if err = o.LoadTxesAttempts(etxs, pg.WithQueryer(tx)); err != nil { - return pkgerrors.Wrap(err, "FindTransactionsConfirmedInBlockRange failed to load eth_tx_attempts") + return pkgerrors.Wrap(err, "FindTransactionsConfirmedInBlockRange failed to load evm.tx_attempts") } err = loadEthTxesAttemptsReceipts(tx, etxs) - return pkgerrors.Wrap(err, "FindTransactionsConfirmedInBlockRange failed to load eth_receipts") + return pkgerrors.Wrap(err, "FindTransactionsConfirmedInBlockRange failed to load evm.receipts") }, pg.OptReadOnlyTx()) return etxs, pkgerrors.Wrap(err, "FindTransactionsConfirmedInBlockRange failed") } @@ -1014,11 +1014,11 @@ func saveAttemptWithNewState(q pg.Queryer, timeout time.Duration, logger logger. // In case of null broadcast_at (shouldn't happen) we don't want to // update anyway because it indicates a state where broadcast_at makes // no sense e.g. fatal_error - if _, err := tx.Exec(`UPDATE eth_txes SET broadcast_at = $1 WHERE id = $2 AND broadcast_at < $1`, broadcastAt, dbAttempt.EthTxID); err != nil { - return pkgerrors.Wrap(err, "saveAttemptWithNewState failed to update eth_txes") + if _, err := tx.Exec(`UPDATE evm.txes SET broadcast_at = $1 WHERE id = $2 AND broadcast_at < $1`, broadcastAt, dbAttempt.EthTxID); err != nil { + return pkgerrors.Wrap(err, "saveAttemptWithNewState failed to update evm.txes") } - _, err := tx.Exec(`UPDATE eth_tx_attempts SET state=$1 WHERE id=$2`, dbAttempt.State, dbAttempt.ID) - return pkgerrors.Wrap(err, "saveAttemptWithNewState failed to update eth_tx_attempts") + _, err := tx.Exec(`UPDATE evm.tx_attempts SET state=$1 WHERE id=$2`, dbAttempt.State, dbAttempt.ID) + return pkgerrors.Wrap(err, "saveAttemptWithNewState failed to update evm.tx_attempts") }) } @@ -1048,8 +1048,8 @@ func (o *evmTxStore) SaveConfirmedMissingReceiptAttempt(ctx context.Context, tim if err := saveSentAttempt(tx, timeout, o.logger, attempt, broadcastAt); err != nil { return err } - if _, err := tx.Exec(`UPDATE eth_txes SET state = 'confirmed_missing_receipt' WHERE id = $1`, attempt.TxID); err != nil { - return pkgerrors.Wrap(err, "failed to update eth_txes") + if _, err := tx.Exec(`UPDATE evm.txes SET state = 'confirmed_missing_receipt' WHERE id = $1`, attempt.TxID); err != nil { + return pkgerrors.Wrap(err, "failed to update evm.txes") } return nil @@ -1066,7 +1066,7 @@ func (o *evmTxStore) DeleteInProgressAttempt(ctx context.Context, attempt TxAtte if attempt.ID == 0 { return errors.New("DeleteInProgressAttempt: expected attempt to have an id") } - _, err := qq.Exec(`DELETE FROM eth_tx_attempts WHERE id = $1`, attempt.ID) + _, err := qq.Exec(`DELETE FROM evm.tx_attempts WHERE id = $1`, attempt.ID) return pkgerrors.Wrap(err, "DeleteInProgressAttempt failed") } @@ -1084,19 +1084,19 @@ func (o *evmTxStore) SaveInProgressAttempt(attempt *TxAttempt) error { } e = o.q.Get(&dbAttempt, query, args...) DbEthTxAttemptToEthTxAttempt(dbAttempt, attempt) - return pkgerrors.Wrap(e, "SaveInProgressAttempt failed to insert into eth_tx_attempts") + return pkgerrors.Wrap(e, "SaveInProgressAttempt failed to insert into evm.tx_attempts") } // Update only applies to case of insufficient eth and simply changes the state to in_progress - res, err := o.q.Exec(`UPDATE eth_tx_attempts SET state=$1, broadcast_before_block_num=$2 WHERE id=$3`, dbAttempt.State, dbAttempt.BroadcastBeforeBlockNum, dbAttempt.ID) + res, err := o.q.Exec(`UPDATE evm.tx_attempts SET state=$1, broadcast_before_block_num=$2 WHERE id=$3`, dbAttempt.State, dbAttempt.BroadcastBeforeBlockNum, dbAttempt.ID) if err != nil { - return pkgerrors.Wrap(err, "SaveInProgressAttempt failed to update eth_tx_attempts") + return pkgerrors.Wrap(err, "SaveInProgressAttempt failed to update evm.tx_attempts") } rowsAffected, err := res.RowsAffected() if err != nil { return pkgerrors.Wrap(err, "SaveInProgressAttempt failed to get RowsAffected") } if rowsAffected == 0 { - return pkgerrors.Wrapf(sql.ErrNoRows, "SaveInProgressAttempt tried to update eth_tx_attempts but no rows matched id %d", attempt.ID) + return pkgerrors.Wrapf(sql.ErrNoRows, "SaveInProgressAttempt tried to update evm.tx_attempts but no rows matched id %d", attempt.ID) } return nil } @@ -1105,7 +1105,7 @@ func (o *evmTxStore) SaveInProgressAttempt(attempt *TxAttempt) error { // attempts which are unconfirmed for at least gasBumpThreshold blocks, // limited by limit pending transactions // -// It also returns eth_txes that are unconfirmed with no eth_tx_attempts +// It also returns evm.txes that are unconfirmed with no evm.tx_attempts func (o *evmTxStore) FindTxsRequiringGasBump(ctx context.Context, address common.Address, blockNum, gasBumpThreshold, depth int64, chainID *big.Int) (etxs []*Tx, err error) { if gasBumpThreshold == 0 { return @@ -1113,20 +1113,20 @@ func (o *evmTxStore) FindTxsRequiringGasBump(ctx context.Context, address common qq := o.q.WithOpts(pg.WithParentCtx(ctx)) err = qq.Transaction(func(tx pg.Queryer) error { stmt := ` -SELECT eth_txes.* FROM eth_txes -LEFT JOIN eth_tx_attempts ON eth_txes.id = eth_tx_attempts.eth_tx_id AND (broadcast_before_block_num > $4 OR broadcast_before_block_num IS NULL OR eth_tx_attempts.state != 'broadcast') -WHERE eth_txes.state = 'unconfirmed' AND eth_tx_attempts.id IS NULL AND eth_txes.from_address = $1 AND eth_txes.evm_chain_id = $2 - AND (($3 = 0) OR (eth_txes.id IN (SELECT id FROM eth_txes WHERE state = 'unconfirmed' AND from_address = $1 ORDER BY nonce ASC LIMIT $3))) +SELECT evm.txes.* FROM evm.txes +LEFT JOIN evm.tx_attempts ON evm.txes.id = evm.tx_attempts.eth_tx_id AND (broadcast_before_block_num > $4 OR broadcast_before_block_num IS NULL OR evm.tx_attempts.state != 'broadcast') +WHERE evm.txes.state = 'unconfirmed' AND evm.tx_attempts.id IS NULL AND evm.txes.from_address = $1 AND evm.txes.evm_chain_id = $2 + AND (($3 = 0) OR (evm.txes.id IN (SELECT id FROM evm.txes WHERE state = 'unconfirmed' AND from_address = $1 ORDER BY nonce ASC LIMIT $3))) ORDER BY nonce ASC ` var dbEtxs []DbEthTx if err = tx.Select(&dbEtxs, stmt, address, chainID.String(), depth, blockNum-gasBumpThreshold); err != nil { - return pkgerrors.Wrap(err, "FindEthTxsRequiringGasBump failed to load eth_txes") + return pkgerrors.Wrap(err, "FindEthTxsRequiringGasBump failed to load evm.txes") } etxs = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, etxs) err = o.LoadTxesAttempts(etxs, pg.WithQueryer(tx)) - return pkgerrors.Wrap(err, "FindEthTxsRequiringGasBump failed to load eth_tx_attempts") + return pkgerrors.Wrap(err, "FindEthTxsRequiringGasBump failed to load evm.tx_attempts") }, pg.OptReadOnlyTx()) return } @@ -1139,18 +1139,18 @@ func (o *evmTxStore) FindTxsRequiringResubmissionDueToInsufficientFunds(address err = qq.Transaction(func(tx pg.Queryer) error { var dbEtxs []DbEthTx err = tx.Select(&dbEtxs, ` -SELECT DISTINCT eth_txes.* FROM eth_txes -INNER JOIN eth_tx_attempts ON eth_txes.id = eth_tx_attempts.eth_tx_id AND eth_tx_attempts.state = 'insufficient_eth' -WHERE eth_txes.from_address = $1 AND eth_txes.state = 'unconfirmed' AND eth_txes.evm_chain_id = $2 +SELECT DISTINCT evm.txes.* FROM evm.txes +INNER JOIN evm.tx_attempts ON evm.txes.id = evm.tx_attempts.eth_tx_id AND evm.tx_attempts.state = 'insufficient_eth' +WHERE evm.txes.from_address = $1 AND evm.txes.state = 'unconfirmed' AND evm.txes.evm_chain_id = $2 ORDER BY nonce ASC `, address, chainID.String()) if err != nil { - return pkgerrors.Wrap(err, "FindEthTxsRequiringResubmissionDueToInsufficientEth failed to load eth_txes") + return pkgerrors.Wrap(err, "FindEthTxsRequiringResubmissionDueToInsufficientEth failed to load evm.txes") } etxs = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, etxs) err = o.LoadTxesAttempts(etxs, pg.WithQueryer(tx)) - return pkgerrors.Wrap(err, "FindEthTxsRequiringResubmissionDueToInsufficientEth failed to load eth_tx_attempts") + return pkgerrors.Wrap(err, "FindEthTxsRequiringResubmissionDueToInsufficientEth failed to load evm.tx_attempts") }, pg.OptReadOnlyTx()) return } @@ -1182,20 +1182,20 @@ func (o *evmTxStore) MarkOldTxesMissingReceiptAsErrored(blockNum int64, finality } var data []etx err := q.Select(&data, ` -UPDATE eth_txes +UPDATE evm.txes SET state='fatal_error', nonce=NULL, error=$1, broadcast_at=NULL, initial_broadcast_at=NULL FROM ( - SELECT e1.id, e1.nonce, e1.from_address FROM eth_txes AS e1 WHERE id IN ( - SELECT e2.id FROM eth_txes AS e2 - INNER JOIN eth_tx_attempts ON e2.id = eth_tx_attempts.eth_tx_id + SELECT e1.id, e1.nonce, e1.from_address FROM evm.txes AS e1 WHERE id IN ( + SELECT e2.id FROM evm.txes AS e2 + INNER JOIN evm.tx_attempts ON e2.id = evm.tx_attempts.eth_tx_id WHERE e2.state = 'confirmed_missing_receipt' AND e2.evm_chain_id = $3 GROUP BY e2.id - HAVING max(eth_tx_attempts.broadcast_before_block_num) < $2 + HAVING max(evm.tx_attempts.broadcast_before_block_num) < $2 ) FOR UPDATE OF e1 ) e0 -WHERE e0.id = eth_txes.id +WHERE e0.id = evm.txes.id RETURNING e0.id, e0.nonce`, ErrCouldNotGetReceipt, cutoff, chainID.String()) if err != nil { @@ -1223,8 +1223,8 @@ RETURNING e0.id, e0.nonce`, ErrCouldNotGetReceipt, cutoff, chainID.String()) var results []result err = q.Select(&results, ` SELECT e.id, e.from_address, max(a.broadcast_before_block_num) AS max_broadcast_before_block_num, array_agg(a.hash) AS tx_hashes -FROM eth_txes e -INNER JOIN eth_tx_attempts a ON e.id = a.eth_tx_id +FROM evm.txes e +INNER JOIN evm.tx_attempts a ON e.id = a.eth_tx_id WHERE e.id = ANY($1) GROUP BY e.id `, etxIDs) @@ -1262,8 +1262,8 @@ func (o *evmTxStore) SaveReplacementInProgressAttempt(oldAttempt TxAttempt, repl return errors.New("expected oldAttempt to have an ID") } return qq.Transaction(func(tx pg.Queryer) error { - if _, err := tx.Exec(`DELETE FROM eth_tx_attempts WHERE id=$1`, oldAttempt.ID); err != nil { - return pkgerrors.Wrap(err, "saveReplacementInProgressAttempt failed to delete from eth_tx_attempts") + if _, err := tx.Exec(`DELETE FROM evm.tx_attempts WHERE id=$1`, oldAttempt.ID); err != nil { + return pkgerrors.Wrap(err, "saveReplacementInProgressAttempt failed to delete from evm.tx_attempts") } dbAttempt := DbEthTxAttemptFromEthTxAttempt(replacementAttempt) query, args, e := tx.BindNamed(insertIntoEthTxAttemptsQuery, &dbAttempt) @@ -1280,7 +1280,7 @@ func (o *evmTxStore) SaveReplacementInProgressAttempt(oldAttempt TxAttempt, repl func (o *evmTxStore) FindNextUnstartedTransactionFromAddress(etx *Tx, fromAddress common.Address, chainID *big.Int, qopts ...pg.QOpt) error { qq := o.q.WithOpts(qopts...) var dbEtx DbEthTx - err := qq.Get(&dbEtx, `SELECT * FROM eth_txes WHERE from_address = $1 AND state = 'unstarted' AND evm_chain_id = $2 ORDER BY value ASC, created_at ASC, id ASC`, fromAddress, chainID.String()) + err := qq.Get(&dbEtx, `SELECT * FROM evm.txes WHERE from_address = $1 AND state = 'unstarted' AND evm_chain_id = $2 ORDER BY value ASC, created_at ASC, id ASC`, fromAddress, chainID.String()) DbEthTxToEthTx(dbEtx, etx) return pkgerrors.Wrap(err, "failed to FindNextUnstartedTransactionFromAddress") } @@ -1299,11 +1299,11 @@ func (o *evmTxStore) UpdateTxFatalError(etx *Tx, qopts ...pg.QOpt) error { etx.State = txmgr.TxFatalError return qq.Transaction(func(tx pg.Queryer) error { - if _, err := tx.Exec(`DELETE FROM eth_tx_attempts WHERE eth_tx_id = $1`, etx.ID); err != nil { + if _, err := tx.Exec(`DELETE FROM evm.tx_attempts WHERE eth_tx_id = $1`, etx.ID); err != nil { return pkgerrors.Wrapf(err, "saveFatallyErroredTransaction failed to delete eth_tx_attempt with eth_tx.ID %v", etx.ID) } dbEtx := DbEthTxFromEthTx(etx) - err := pkgerrors.Wrap(tx.Get(&dbEtx, `UPDATE eth_txes SET state=$1, error=$2, broadcast_at=NULL, initial_broadcast_at=NULL, nonce=NULL WHERE id=$3 RETURNING *`, etx.State, etx.Error, etx.ID), "saveFatallyErroredTransaction failed to save eth_tx") + err := pkgerrors.Wrap(tx.Get(&dbEtx, `UPDATE evm.txes SET state=$1, error=$2, broadcast_at=NULL, initial_broadcast_at=NULL, nonce=NULL WHERE id=$3 RETURNING *`, etx.State, etx.Error, etx.ID), "saveFatallyErroredTransaction failed to save eth_tx") DbEthTxToEthTx(dbEtx, etx) return err }) @@ -1337,12 +1337,12 @@ func (o *evmTxStore) UpdateTxAttemptInProgressToBroadcast(etx *Tx, attempt TxAtt return pkgerrors.Wrap(err, "SaveEthTxAttempt failed on incrNextNonceCallback") } dbEtx := DbEthTxFromEthTx(etx) - if err := tx.Get(&dbEtx, `UPDATE eth_txes SET state=$1, error=$2, broadcast_at=$3, initial_broadcast_at=$4 WHERE id = $5 RETURNING *`, dbEtx.State, dbEtx.Error, dbEtx.BroadcastAt, dbEtx.InitialBroadcastAt, dbEtx.ID); err != nil { + if err := tx.Get(&dbEtx, `UPDATE evm.txes SET state=$1, error=$2, broadcast_at=$3, initial_broadcast_at=$4 WHERE id = $5 RETURNING *`, dbEtx.State, dbEtx.Error, dbEtx.BroadcastAt, dbEtx.InitialBroadcastAt, dbEtx.ID); err != nil { return pkgerrors.Wrap(err, "SaveEthTxAttempt failed to save eth_tx") } DbEthTxToEthTx(dbEtx, etx) dbAttempt := DbEthTxAttemptFromEthTxAttempt(&attempt) - if err := tx.Get(&dbAttempt, `UPDATE eth_tx_attempts SET state = $1 WHERE id = $2 RETURNING *`, dbAttempt.State, dbAttempt.ID); err != nil { + if err := tx.Get(&dbAttempt, `UPDATE evm.tx_attempts SET state = $1 WHERE id = $2 RETURNING *`, dbAttempt.State, dbAttempt.ID); err != nil { return pkgerrors.Wrap(err, "SaveEthTxAttempt failed to save eth_tx_attempt") } return nil @@ -1364,13 +1364,13 @@ func (o *evmTxStore) UpdateTxUnstartedToInProgress(etx *Tx, attempt *TxAttempt, etx.State = txmgr.TxInProgress return qq.Transaction(func(tx pg.Queryer) error { // If a replay was triggered while unconfirmed transactions were pending, they will be marked as fatal_error => abandoned. - // In this case, we must remove the abandoned attempt from eth_tx_attempts before replacing it with a new one. In any other + // In this case, we must remove the abandoned attempt from evm.tx_attempts before replacing it with a new one. In any other // case, we uphold the constraint, leaving the original tx attempt as-is and returning the constraint violation error. // - // Note: the record of the original abandoned transaction will remain in eth_txes, only the attempt is replaced. (Any receipt + // Note: the record of the original abandoned transaction will remain in evm.txes, only the attempt is replaced. (Any receipt // associated with the abandoned attempt would also be lost, although this shouldn't happen since only unconfirmed transactions // can be abandoned.) - _, err := tx.Exec(`DELETE FROM eth_tx_attempts a USING eth_txes t + _, err := tx.Exec(`DELETE FROM evm.tx_attempts a USING evm.txes t WHERE t.id = a.eth_tx_id AND a.hash = $1 AND t.state = $2 AND t.error = 'abandoned'`, attempt.Hash, txmgr.TxFatalError, ) @@ -1388,12 +1388,10 @@ func (o *evmTxStore) UpdateTxUnstartedToInProgress(etx *Tx, attempt *TxAttempt, err = tx.Get(&dbAttempt, query, args...) if err != nil { var pqErr *pgconn.PgError - if isPqErr := errors.As(err, &pqErr); isPqErr { - switch pqErr.ConstraintName { - case "eth_tx_attempts_eth_tx_id_fkey": - return txmgr.ErrTxRemoved - default: - } + if isPqErr := errors.As(err, &pqErr); isPqErr && + pqErr.SchemaName == "evm" && + pqErr.ConstraintName == "eth_tx_attempts_eth_tx_id_fkey" { + return txmgr.ErrTxRemoved } if err != nil { return pkgerrors.Wrap(err, "UpdateTxUnstartedToInProgress failed to create eth_tx_attempt") @@ -1401,7 +1399,7 @@ func (o *evmTxStore) UpdateTxUnstartedToInProgress(etx *Tx, attempt *TxAttempt, } DbEthTxAttemptToEthTxAttempt(dbAttempt, attempt) dbEtx := DbEthTxFromEthTx(etx) - err = tx.Get(&dbEtx, `UPDATE eth_txes SET nonce=$1, state=$2, broadcast_at=$3, initial_broadcast_at=$4 WHERE id=$5 RETURNING *`, etx.Sequence, etx.State, etx.BroadcastAt, etx.InitialBroadcastAt, etx.ID) + err = tx.Get(&dbEtx, `UPDATE evm.txes SET nonce=$1, state=$2, broadcast_at=$3, initial_broadcast_at=$4 WHERE id=$5 RETURNING *`, etx.Sequence, etx.State, etx.BroadcastAt, etx.InitialBroadcastAt, etx.ID) DbEthTxToEthTx(dbEtx, etx) return pkgerrors.Wrap(err, "UpdateTxUnstartedToInProgress failed to update eth_tx") }) @@ -1419,7 +1417,7 @@ func (o *evmTxStore) GetTxInProgress(fromAddress common.Address, qopts ...pg.QOp } err = qq.Transaction(func(tx pg.Queryer) error { var dbEtx DbEthTx - err = tx.Get(&dbEtx, `SELECT * FROM eth_txes WHERE from_address = $1 and state = 'in_progress'`, fromAddress) + err = tx.Get(&dbEtx, `SELECT * FROM evm.txes WHERE from_address = $1 and state = 'in_progress'`, fromAddress) if errors.Is(err, sql.ErrNoRows) { etx = nil return nil @@ -1442,7 +1440,7 @@ func (o *evmTxStore) GetTxInProgress(fromAddress common.Address, qopts ...pg.QOp func (o *evmTxStore) HasInProgressTransaction(account common.Address, chainID *big.Int, qopts ...pg.QOpt) (exists bool, err error) { qq := o.q.WithOpts(qopts...) - err = qq.Get(&exists, `SELECT EXISTS(SELECT 1 FROM eth_txes WHERE state = 'in_progress' AND from_address = $1 AND evm_chain_id = $2)`, account, chainID.String()) + err = qq.Get(&exists, `SELECT EXISTS(SELECT 1 FROM evm.txes WHERE state = 'in_progress' AND from_address = $1 AND evm_chain_id = $2)`, account, chainID.String()) return exists, pkgerrors.Wrap(err, "hasInProgressTransaction failed") } @@ -1451,7 +1449,7 @@ func (o *evmTxStore) UpdateKeyNextSequence(newNextNonce, currentNextNonce evmtyp return qq.Transaction(func(tx pg.Queryer) error { // We filter by next_nonce here as an optimistic lock to make sure it // didn't get changed out from under us. Shouldn't happen but can't hurt. - res, err := tx.Exec(`UPDATE evm_key_states SET next_nonce = $1, updated_at = $2 WHERE address = $3 AND next_nonce = $4 AND evm_chain_id = $5`, newNextNonce.Int64(), time.Now(), address, currentNextNonce.Int64(), chainID.String()) + res, err := tx.Exec(`UPDATE evm.key_states SET next_nonce = $1, updated_at = $2 WHERE address = $3 AND next_nonce = $4 AND evm_chain_id = $5`, newNextNonce.Int64(), time.Now(), address, currentNextNonce.Int64(), chainID.String()) if err != nil { return pkgerrors.Wrap(err, "NonceSyncer#fastForwardNonceIfNecessary failed to update keys.next_nonce") } @@ -1468,7 +1466,7 @@ func (o *evmTxStore) UpdateKeyNextSequence(newNextNonce, currentNextNonce evmtyp func (o *evmTxStore) countTransactionsWithState(fromAddress common.Address, state txmgrtypes.TxState, chainID *big.Int, qopts ...pg.QOpt) (count uint32, err error) { qq := o.q.WithOpts(qopts...) - err = qq.Get(&count, `SELECT count(*) FROM eth_txes WHERE from_address = $1 AND state = $2 AND evm_chain_id = $3`, + err = qq.Get(&count, `SELECT count(*) FROM evm.txes WHERE from_address = $1 AND state = $2 AND evm_chain_id = $3`, fromAddress, state, chainID.String()) return count, pkgerrors.Wrap(err, "failed to countTransactionsWithState") } @@ -1489,7 +1487,7 @@ func (o *evmTxStore) CheckTxQueueCapacity(fromAddress common.Address, maxQueuedT return nil } var count uint64 - err = qq.Get(&count, `SELECT count(*) FROM eth_txes WHERE from_address = $1 AND state = 'unstarted' AND evm_chain_id = $2`, fromAddress, chainID.String()) + err = qq.Get(&count, `SELECT count(*) FROM evm.txes WHERE from_address = $1 AND state = 'unstarted' AND evm_chain_id = $2`, fromAddress, chainID.String()) if err != nil { err = pkgerrors.Wrap(err, "CheckTxQueueCapacity query failed") return @@ -1507,7 +1505,7 @@ func (o *evmTxStore) CreateTransaction(txRequest TxRequest, chainID *big.Int, qo err = qq.Transaction(func(tx pg.Queryer) error { if txRequest.PipelineTaskRunID != nil { - err = tx.Get(&dbEtx, `SELECT * FROM eth_txes WHERE pipeline_task_run_id = $1 AND evm_chain_id = $2`, txRequest.PipelineTaskRunID, chainID.String()) + err = tx.Get(&dbEtx, `SELECT * FROM evm.txes WHERE pipeline_task_run_id = $1 AND evm_chain_id = $2`, txRequest.PipelineTaskRunID, chainID.String()) // If no eth_tx matches (the common case) then continue if !errors.Is(err, sql.ErrNoRows) { if err != nil { @@ -1518,19 +1516,19 @@ func (o *evmTxStore) CreateTransaction(txRequest TxRequest, chainID *big.Int, qo } } err = tx.Get(&dbEtx, ` -INSERT INTO eth_txes (from_address, to_address, encoded_payload, value, gas_limit, state, created_at, meta, subject, evm_chain_id, min_confirmations, pipeline_task_run_id, transmit_checker, idempotency_key) +INSERT INTO evm.txes (from_address, to_address, encoded_payload, value, gas_limit, state, created_at, meta, subject, evm_chain_id, min_confirmations, pipeline_task_run_id, transmit_checker, idempotency_key) VALUES ( $1,$2,$3,$4,$5,'unstarted',NOW(),$6,$7,$8,$9,$10,$11,$12 ) -RETURNING "eth_txes".* +RETURNING "txes".* `, txRequest.FromAddress, txRequest.ToAddress, txRequest.EncodedPayload, assets.Eth(txRequest.Value), txRequest.FeeLimit, txRequest.Meta, txRequest.Strategy.Subject(), chainID.String(), txRequest.MinConfirmations, txRequest.PipelineTaskRunID, txRequest.Checker, txRequest.IdempotencyKey) if err != nil { - return pkgerrors.Wrap(err, "CreateEthTransaction failed to insert eth_tx") + return pkgerrors.Wrap(err, "CreateEthTransaction failed to insert evm tx") } var pruned int64 pruned, err = txRequest.Strategy.PruneQueue(o, pg.WithQueryer(tx)) if err != nil { - return pkgerrors.Wrap(err, "CreateEthTransaction failed to prune eth_txes") + return pkgerrors.Wrap(err, "CreateEthTransaction failed to prune evm.txes") } if pruned > 0 { o.logger.Warnw(fmt.Sprintf("Dropped %d old transactions from transaction queue", pruned), "fromAddress", txRequest.FromAddress, "toAddress", txRequest.ToAddress, "meta", txRequest.Meta, "subject", txRequest.Strategy.Subject(), "replacementID", dbEtx.ID) @@ -1546,12 +1544,12 @@ func (o *evmTxStore) PruneUnstartedTxQueue(queueSize uint32, subject uuid.UUID, qq := o.q.WithOpts(qopts...) err = qq.Transaction(func(tx pg.Queryer) error { res, err := qq.Exec(` -DELETE FROM eth_txes +DELETE FROM evm.txes WHERE state = 'unstarted' AND subject = $1 AND id < ( SELECT min(id) FROM ( SELECT id - FROM eth_txes + FROM evm.txes WHERE state = 'unstarted' AND subject = $2 ORDER BY id DESC LIMIT $3 @@ -1567,26 +1565,26 @@ id < ( } func (o *evmTxStore) ReapTxHistory(minBlockNumberToKeep int64, timeThreshold time.Time, chainID *big.Int) error { - // Delete old confirmed eth_txes + // Delete old confirmed evm.txes // NOTE that this relies on foreign key triggers automatically removing - // the eth_tx_attempts and eth_receipts linked to every eth_tx + // the evm.tx_attempts and evm.receipts linked to every eth_tx err := pg.Batch(func(_, limit uint) (count uint, err error) { res, err := o.q.Exec(` WITH old_enough_receipts AS ( - SELECT tx_hash FROM eth_receipts + SELECT tx_hash FROM evm.receipts WHERE block_number < $1 ORDER BY block_number ASC, id ASC LIMIT $2 ) -DELETE FROM eth_txes -USING old_enough_receipts, eth_tx_attempts -WHERE eth_tx_attempts.eth_tx_id = eth_txes.id -AND eth_tx_attempts.hash = old_enough_receipts.tx_hash -AND eth_txes.created_at < $3 -AND eth_txes.state = 'confirmed' +DELETE FROM evm.txes +USING old_enough_receipts, evm.tx_attempts +WHERE evm.tx_attempts.eth_tx_id = evm.txes.id +AND evm.tx_attempts.hash = old_enough_receipts.tx_hash +AND evm.txes.created_at < $3 +AND evm.txes.state = 'confirmed' AND evm_chain_id = $4`, minBlockNumberToKeep, limit, timeThreshold, chainID.String()) if err != nil { - return count, pkgerrors.Wrap(err, "ReapTxes failed to delete old confirmed eth_txes") + return count, pkgerrors.Wrap(err, "ReapTxes failed to delete old confirmed evm.txes") } rowsAffected, err := res.RowsAffected() if err != nil { @@ -1595,17 +1593,17 @@ AND evm_chain_id = $4`, minBlockNumberToKeep, limit, timeThreshold, chainID.Stri return uint(rowsAffected), err }) if err != nil { - return pkgerrors.Wrap(err, "TxmReaper#reapEthTxes batch delete of confirmed eth_txes failed") + return pkgerrors.Wrap(err, "TxmReaper#reapEthTxes batch delete of confirmed evm.txes failed") } - // Delete old 'fatal_error' eth_txes + // Delete old 'fatal_error' evm.txes err = pg.Batch(func(_, limit uint) (count uint, err error) { res, err := o.q.Exec(` -DELETE FROM eth_txes +DELETE FROM evm.txes WHERE created_at < $1 AND state = 'fatal_error' AND evm_chain_id = $2`, timeThreshold, chainID.String()) if err != nil { - return count, pkgerrors.Wrap(err, "ReapTxes failed to delete old fatally errored eth_txes") + return count, pkgerrors.Wrap(err, "ReapTxes failed to delete old fatally errored evm.txes") } rowsAffected, err := res.RowsAffected() if err != nil { @@ -1614,13 +1612,13 @@ AND evm_chain_id = $2`, timeThreshold, chainID.String()) return uint(rowsAffected), err }) if err != nil { - return pkgerrors.Wrap(err, "TxmReaper#reapEthTxes batch delete of fatally errored eth_txes failed") + return pkgerrors.Wrap(err, "TxmReaper#reapEthTxes batch delete of fatally errored evm.txes failed") } return nil } func (o *evmTxStore) Abandon(chainID *big.Int, addr common.Address) error { - _, err := o.q.Exec(`UPDATE eth_txes SET state='fatal_error', nonce = NULL, error = 'abandoned' WHERE state IN ('unconfirmed', 'in_progress', 'unstarted') AND evm_chain_id = $1 AND from_address = $2`, chainID.String(), addr) + _, err := o.q.Exec(`UPDATE evm.txes SET state='fatal_error', nonce = NULL, error = 'abandoned' WHERE state IN ('unconfirmed', 'in_progress', 'unstarted') AND evm_chain_id = $1 AND from_address = $2`, chainID.String(), addr) return err } diff --git a/core/chains/evm/txmgr/evm_tx_store_test.go b/core/chains/evm/txmgr/evm_tx_store_test.go index 777a179be45..c4837f81e87 100644 --- a/core/chains/evm/txmgr/evm_tx_store_test.go +++ b/core/chains/evm/txmgr/evm_tx_store_test.go @@ -55,7 +55,7 @@ func TestORM_TransactionsWithAttempts(t *testing.T) { cltest.MustCreateUnstartedGeneratedTx(t, txStore, from, &cltest.FixtureChainID) var count int - err := db.Get(&count, `SELECT count(*) FROM eth_txes`) + err := db.Get(&count, `SELECT count(*) FROM evm.txes`) require.NoError(t, err) require.Equal(t, 3, count) @@ -100,7 +100,7 @@ func TestORM_Transactions(t *testing.T) { cltest.MustCreateUnstartedGeneratedTx(t, txStore, from, &cltest.FixtureChainID) var count int - err := db.Get(&count, `SELECT count(*) FROM eth_txes`) + err := db.Get(&count, `SELECT count(*) FROM evm.txes`) require.NoError(t, err) require.Equal(t, 3, count) @@ -130,7 +130,7 @@ func TestORM(t *testing.T) { err = orm.InsertTx(&etx) require.NoError(t, err) assert.Greater(t, int(etx.ID), 0) - cltest.AssertCount(t, db, "eth_txes", 1) + cltest.AssertCount(t, db, "evm.txes", 1) }) var attemptL txmgr.TxAttempt var attemptD txmgr.TxAttempt @@ -139,7 +139,7 @@ func TestORM(t *testing.T) { err = orm.InsertTxAttempt(&attemptD) require.NoError(t, err) assert.Greater(t, int(attemptD.ID), 0) - cltest.AssertCount(t, db, "eth_tx_attempts", 1) + cltest.AssertCount(t, db, "evm.tx_attempts", 1) attemptL = cltest.NewLegacyEthTxAttempt(t, etx.ID) attemptL.State = txmgrtypes.TxAttemptBroadcast @@ -147,7 +147,7 @@ func TestORM(t *testing.T) { err = orm.InsertTxAttempt(&attemptL) require.NoError(t, err) assert.Greater(t, int(attemptL.ID), 0) - cltest.AssertCount(t, db, "eth_tx_attempts", 2) + cltest.AssertCount(t, db, "evm.tx_attempts", 2) }) var r txmgr.Receipt t.Run("InsertReceipt", func(t *testing.T) { @@ -156,7 +156,7 @@ func TestORM(t *testing.T) { r.ID = id require.NoError(t, err) assert.Greater(t, int(r.ID), 0) - cltest.AssertCount(t, db, "eth_receipts", 1) + cltest.AssertCount(t, db, "evm.receipts", 1) }) t.Run("FindTxWithAttempts", func(t *testing.T) { etx, err = orm.FindTxWithAttempts(etx.ID) @@ -217,11 +217,11 @@ func TestORM_FindTxAttemptConfirmedByTxIDs(t *testing.T) { cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, orm, 4, from) // tx5 var count int - err = db.Get(&count, `SELECT count(*) FROM eth_txes`) + err = db.Get(&count, `SELECT count(*) FROM evm.txes`) require.NoError(t, err) require.Equal(t, 5, count) - err = db.Get(&count, `SELECT count(*) FROM eth_tx_attempts`) + err = db.Get(&count, `SELECT count(*) FROM evm.tx_attempts`) require.NoError(t, err) require.Equal(t, 4, count) @@ -385,7 +385,7 @@ func TestORM_SetBroadcastBeforeBlockNum(t *testing.T) { headNum := int64(9000) var err error - t.Run("saves block num to unconfirmed eth_tx_attempts without one", func(t *testing.T) { + t.Run("saves block num to unconfirmed evm.tx_attempts without one", func(t *testing.T) { // Do the thing require.NoError(t, txStore.SetBroadcastBeforeBlockNum(headNum, chainID)) @@ -397,7 +397,7 @@ func TestORM_SetBroadcastBeforeBlockNum(t *testing.T) { assert.Equal(t, int64(9000), *attempt.BroadcastBeforeBlockNum) }) - t.Run("does not change eth_tx_attempts that already have BroadcastBeforeBlockNum set", func(t *testing.T) { + t.Run("does not change evm.tx_attempts that already have BroadcastBeforeBlockNum set", func(t *testing.T) { n := int64(42) attempt := newBroadcastLegacyEthTxAttempt(t, etx.ID, 2) attempt.BroadcastBeforeBlockNum = &n @@ -414,10 +414,10 @@ func TestORM_SetBroadcastBeforeBlockNum(t *testing.T) { assert.Equal(t, int64(42), *attempt.BroadcastBeforeBlockNum) }) - t.Run("only updates eth_tx_attempts for the current chain", func(t *testing.T) { + t.Run("only updates evm.tx_attempts for the current chain", func(t *testing.T) { require.NoError(t, ethKeyStore.Add(fromAddress, testutils.SimulatedChainID)) require.NoError(t, ethKeyStore.Enable(fromAddress, testutils.SimulatedChainID)) - etxThisChain := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, fromAddress, cfg.DefaultChainID()) + etxThisChain := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, fromAddress, cfg.EVM().ChainID()) etxOtherChain := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress, testutils.SimulatedChainID) require.NoError(t, txStore.SetBroadcastBeforeBlockNum(headNum, chainID)) @@ -654,11 +654,11 @@ func TestORM_FindReceiptsPendingConfirmation(t *testing.T) { pgtest.MustExec(t, db, `UPDATE pipeline_runs SET state = 'suspended' WHERE id = $1`, run.ID) etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 3, 1, fromAddress) - pgtest.MustExec(t, db, `UPDATE eth_txes SET meta='{"FailOnRevert": true}'`) + pgtest.MustExec(t, db, `UPDATE evm.txes SET meta='{"FailOnRevert": true}'`) attempt := etx.TxAttempts[0] cltest.MustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, attempt.Hash) - pgtest.MustExec(t, db, `UPDATE eth_txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) + pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) receiptsPlus, err := txStore.FindReceiptsPendingConfirmation(testutils.Context(t), head.Number, ethClient.ConfiguredChainID()) require.NoError(t, err) @@ -1021,8 +1021,8 @@ func TestEthConfirmer_FindTxsRequiringResubmissionDueToInsufficientEth(t *testin }) t.Run("does not return confirmed or fatally errored eth_txes", func(t *testing.T) { - pgtest.MustExec(t, db, `UPDATE eth_txes SET state='confirmed' WHERE id = $1`, etx1.ID) - pgtest.MustExec(t, db, `UPDATE eth_txes SET state='fatal_error', nonce=NULL, error='foo', broadcast_at=NULL, initial_broadcast_at=NULL WHERE id = $1`, etx2.ID) + pgtest.MustExec(t, db, `UPDATE evm.txes SET state='confirmed' WHERE id = $1`, etx1.ID) + pgtest.MustExec(t, db, `UPDATE evm.txes SET state='fatal_error', nonce=NULL, error='foo', broadcast_at=NULL, initial_broadcast_at=NULL WHERE id = $1`, etx2.ID) etxs, err := txStore.FindTxsRequiringResubmissionDueToInsufficientFunds(fromAddress, &cltest.FixtureChainID) require.NoError(t, err) @@ -1102,7 +1102,7 @@ func TestORM_LoadEthTxesAttempts(t *testing.T) { newAttempt := cltest.NewDynamicFeeEthTxAttempt(t, etx.ID) dbAttempt := txmgr.DbEthTxAttemptFromEthTxAttempt(&newAttempt) err := q.Transaction(func(tx pg.Queryer) error { - const insertEthTxAttemptSQL = `INSERT INTO eth_tx_attempts (eth_tx_id, gas_price, signed_raw_tx, hash, broadcast_before_block_num, state, created_at, chain_specific_gas_limit, tx_type, gas_tip_cap, gas_fee_cap) VALUES ( + const insertEthTxAttemptSQL = `INSERT INTO evm.tx_attempts (eth_tx_id, gas_price, signed_raw_tx, hash, broadcast_before_block_num, state, created_at, chain_specific_gas_limit, tx_type, gas_tip_cap, gas_fee_cap) VALUES ( :eth_tx_id, :gas_price, :signed_raw_tx, :hash, :broadcast_before_block_num, :state, NOW(), :chain_specific_gas_limit, :tx_type, :gas_tip_cap, :gas_fee_cap ) RETURNING *` _, err := tx.NamedExec(insertEthTxAttemptSQL, dbAttempt) @@ -1262,7 +1262,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID) - err := q.ExecQ("DELETE FROM eth_txes WHERE id = $1", etx.ID) + err := q.ExecQ("DELETE FROM evm.txes WHERE id = $1", etx.ID) require.NoError(t, err) err = txStore.UpdateTxUnstartedToInProgress(&etx, &attempt) @@ -1574,10 +1574,10 @@ func TestORM_CreateTransaction(t *testing.T) { assert.Equal(t, big.Int(assets.NewEthValue(0)), etx.Value) assert.Equal(t, subject, etx.Subject.UUID) - cltest.AssertCount(t, db, "eth_txes", 1) + cltest.AssertCount(t, db, "evm.txes", 1) var dbEthTx txmgr.DbEthTx - require.NoError(t, db.Get(&dbEthTx, `SELECT * FROM eth_txes ORDER BY id ASC LIMIT 1`)) + require.NoError(t, db.Get(&dbEthTx, `SELECT * FROM evm.txes ORDER BY id ASC LIMIT 1`)) assert.Equal(t, dbEthTx.State, txmgrcommon.TxUnstarted) assert.Equal(t, gasLimit, dbEthTx.GasLimit) diff --git a/core/chains/evm/txmgr/nonce_syncer_test.go b/core/chains/evm/txmgr/nonce_syncer_test.go index 88dc5e22022..05a6d4c8c7b 100644 --- a/core/chains/evm/txmgr/nonce_syncer_test.go +++ b/core/chains/evm/txmgr/nonce_syncer_test.go @@ -42,8 +42,8 @@ func Test_NonceSyncer_Sync(t *testing.T) { require.Error(t, err) assert.Contains(t, err.Error(), "something exploded") - cltest.AssertCount(t, db, "eth_txes", 0) - cltest.AssertCount(t, db, "eth_tx_attempts", 0) + cltest.AssertCount(t, db, "evm.txes", 0) + cltest.AssertCount(t, db, "evm.tx_attempts", 0) assertDatabaseNonce(t, db, from, 0) }) @@ -66,8 +66,8 @@ func Test_NonceSyncer_Sync(t *testing.T) { sendingKeys := cltest.MustSendingKeyStates(t, ethKeyStore, testutils.FixtureChainID) require.NoError(t, ns.Sync(testutils.Context(t), sendingKeys[0].Address.Address())) - cltest.AssertCount(t, db, "eth_txes", 0) - cltest.AssertCount(t, db, "eth_tx_attempts", 0) + cltest.AssertCount(t, db, "evm.txes", 0) + cltest.AssertCount(t, db, "evm.tx_attempts", 0) assertDatabaseNonce(t, db, from, 0) }) @@ -91,8 +91,8 @@ func Test_NonceSyncer_Sync(t *testing.T) { sendingKeys := cltest.MustSendingKeyStates(t, ethKeyStore, testutils.FixtureChainID) require.NoError(t, ns.Sync(testutils.Context(t), sendingKeys[0].Address.Address())) - cltest.AssertCount(t, db, "eth_txes", 0) - cltest.AssertCount(t, db, "eth_tx_attempts", 0) + cltest.AssertCount(t, db, "evm.txes", 0) + cltest.AssertCount(t, db, "evm.tx_attempts", 0) assertDatabaseNonce(t, db, k1.Address, 32) }) @@ -166,7 +166,7 @@ func assertDatabaseNonce(t *testing.T, db *sqlx.DB, address common.Address, nonc t.Helper() var nextNonce int64 - err := db.Get(&nextNonce, `SELECT next_nonce FROM evm_key_states WHERE address = $1`, address) + err := db.Get(&nextNonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1`, address) require.NoError(t, err) assert.Equal(t, nonce, nextNonce) } diff --git a/core/chains/evm/txmgr/reaper_test.go b/core/chains/evm/txmgr/reaper_test.go index 7f32761fa42..11843222999 100644 --- a/core/chains/evm/txmgr/reaper_test.go +++ b/core/chains/evm/txmgr/reaper_test.go @@ -76,7 +76,7 @@ func TestReaper_ReapTxes(t *testing.T) { err := r.ReapTxes(42) assert.NoError(t, err) - cltest.AssertCount(t, db, "eth_txes", 1) + cltest.AssertCount(t, db, "evm.txes", 1) }) t.Run("doesn't touch ethtxes with different chain ID", func(t *testing.T) { @@ -90,10 +90,10 @@ func TestReaper_ReapTxes(t *testing.T) { err := r.ReapTxes(42) assert.NoError(t, err) // Didn't delete because eth_tx has chain ID of 0 - cltest.AssertCount(t, db, "eth_txes", 1) + cltest.AssertCount(t, db, "evm.txes", 1) }) - t.Run("deletes confirmed eth_txes that exceed the age threshold with at least EVM.FinalityDepth blocks above their receipt", func(t *testing.T) { + t.Run("deletes confirmed evm.txes that exceed the age threshold with at least EVM.FinalityDepth blocks above their receipt", func(t *testing.T) { config := txmgrmocks.NewReaperConfig(t) config.On("FinalityDepth").Return(uint32(10)) @@ -104,24 +104,24 @@ func TestReaper_ReapTxes(t *testing.T) { err := r.ReapTxes(42) assert.NoError(t, err) // Didn't delete because eth_tx was not old enough - cltest.AssertCount(t, db, "eth_txes", 1) + cltest.AssertCount(t, db, "evm.txes", 1) - pgtest.MustExec(t, db, `UPDATE eth_txes SET created_at=$1`, oneDayAgo) + pgtest.MustExec(t, db, `UPDATE evm.txes SET created_at=$1`, oneDayAgo) err = r.ReapTxes(12) assert.NoError(t, err) // Didn't delete because eth_tx although old enough, was still within EVM.FinalityDepth of the current head - cltest.AssertCount(t, db, "eth_txes", 1) + cltest.AssertCount(t, db, "evm.txes", 1) err = r.ReapTxes(42) assert.NoError(t, err) // Now it deleted because the eth_tx was past EVM.FinalityDepth - cltest.AssertCount(t, db, "eth_txes", 0) + cltest.AssertCount(t, db, "evm.txes", 0) }) cltest.MustInsertFatalErrorEthTx(t, txStore, from) - t.Run("deletes errored eth_txes that exceed the age threshold", func(t *testing.T) { + t.Run("deletes errored evm.txes that exceed the age threshold", func(t *testing.T) { config := txmgrmocks.NewReaperConfig(t) config.On("FinalityDepth").Return(uint32(10)) @@ -132,13 +132,13 @@ func TestReaper_ReapTxes(t *testing.T) { err := r.ReapTxes(42) assert.NoError(t, err) // Didn't delete because eth_tx was not old enough - cltest.AssertCount(t, db, "eth_txes", 1) + cltest.AssertCount(t, db, "evm.txes", 1) - require.NoError(t, utils.JustError(db.Exec(`UPDATE eth_txes SET created_at=$1`, oneDayAgo))) + require.NoError(t, utils.JustError(db.Exec(`UPDATE evm.txes SET created_at=$1`, oneDayAgo))) err = r.ReapTxes(42) assert.NoError(t, err) // Deleted because it is old enough now - cltest.AssertCount(t, db, "eth_txes", 0) + cltest.AssertCount(t, db, "evm.txes", 0) }) } diff --git a/core/chains/evm/txmgr/resender_test.go b/core/chains/evm/txmgr/resender_test.go index 60b6bcdce20..d17156f4525 100644 --- a/core/chains/evm/txmgr/resender_test.go +++ b/core/chains/evm/txmgr/resender_test.go @@ -187,10 +187,10 @@ func Test_EthResender_Start(t *testing.T) { }() var dbEtx txmgr.DbEthTx - err := db.Get(&dbEtx, `SELECT * FROM eth_txes WHERE id = $1`, etx.ID) + err := db.Get(&dbEtx, `SELECT * FROM evm.txes WHERE id = $1`, etx.ID) require.NoError(t, err) var dbEtx2 txmgr.DbEthTx - err = db.Get(&dbEtx2, `SELECT * FROM eth_txes WHERE id = $1`, etx2.ID) + err = db.Get(&dbEtx2, `SELECT * FROM evm.txes WHERE id = $1`, etx2.ID) require.NoError(t, err) assert.Greater(t, dbEtx.BroadcastAt.Unix(), originalBroadcastAt.Unix()) diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index 854ccd6a4af..79fcf101d5f 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -137,10 +137,10 @@ func TestTxm_CreateTransaction(t *testing.T) { assert.Equal(t, big.Int(assets.NewEthValue(0)), etx.Value) assert.Equal(t, subject, etx.Subject.UUID) - cltest.AssertCount(t, db, "eth_txes", 1) + cltest.AssertCount(t, db, "evm.txes", 1) var dbEtx txmgr.DbEthTx - require.NoError(t, db.Get(&dbEtx, `SELECT * FROM eth_txes ORDER BY id ASC LIMIT 1`)) + require.NoError(t, db.Get(&dbEtx, `SELECT * FROM evm.txes ORDER BY id ASC LIMIT 1`)) assert.Equal(t, etx.State, txmgrcommon.TxUnstarted) assert.Equal(t, gasLimit, etx.FeeLimit) @@ -219,7 +219,7 @@ func TestTxm_CreateTransaction(t *testing.T) { }) t.Run("simulate transmit checker", func(t *testing.T) { - pgtest.MustExec(t, db, `DELETE FROM eth_txes`) + pgtest.MustExec(t, db, `DELETE FROM evm.txes`) checker := txmgr.TransmitCheckerSpec{ CheckerType: txmgr.TransmitCheckerTypeSimulate, @@ -234,9 +234,9 @@ func TestTxm_CreateTransaction(t *testing.T) { Checker: checker, }) assert.NoError(t, err) - cltest.AssertCount(t, db, "eth_txes", 1) + cltest.AssertCount(t, db, "evm.txes", 1) var dbEtx txmgr.DbEthTx - require.NoError(t, db.Get(&dbEtx, `SELECT * FROM eth_txes ORDER BY id ASC LIMIT 1`)) + require.NoError(t, db.Get(&dbEtx, `SELECT * FROM evm.txes ORDER BY id ASC LIMIT 1`)) var c txmgr.TransmitCheckerSpec require.NotNil(t, etx.TransmitChecker) @@ -245,7 +245,7 @@ func TestTxm_CreateTransaction(t *testing.T) { }) t.Run("meta and vrf checker", func(t *testing.T) { - pgtest.MustExec(t, db, `DELETE FROM eth_txes`) + pgtest.MustExec(t, db, `DELETE FROM evm.txes`) testDefaultSubID := uint64(2) testDefaultMaxLink := "1000000000000000000" testDefaultMaxEth := "2000000000000000000" @@ -278,9 +278,9 @@ func TestTxm_CreateTransaction(t *testing.T) { Checker: checker, }) assert.NoError(t, err) - cltest.AssertCount(t, db, "eth_txes", 1) + cltest.AssertCount(t, db, "evm.txes", 1) var dbEtx txmgr.DbEthTx - require.NoError(t, db.Get(&dbEtx, `SELECT * FROM eth_txes ORDER BY id ASC LIMIT 1`)) + require.NoError(t, db.Get(&dbEtx, `SELECT * FROM evm.txes ORDER BY id ASC LIMIT 1`)) m, err := etx.GetMeta() require.NoError(t, err) @@ -293,8 +293,8 @@ func TestTxm_CreateTransaction(t *testing.T) { }) t.Run("forwards tx when a proper forwarder is set up", func(t *testing.T) { - pgtest.MustExec(t, db, `DELETE FROM eth_txes`) - pgtest.MustExec(t, db, `DELETE FROM evm_forwarders`) + pgtest.MustExec(t, db, `DELETE FROM evm.txes`) + pgtest.MustExec(t, db, `DELETE FROM evm.forwarders`) evmConfig.maxQueued = uint64(1) // Create mock forwarder, mock authorizedsenders call. @@ -313,10 +313,10 @@ func TestTxm_CreateTransaction(t *testing.T) { Strategy: txmgrcommon.NewSendEveryStrategy(), }) assert.NoError(t, err) - cltest.AssertCount(t, db, "eth_txes", 1) + cltest.AssertCount(t, db, "evm.txes", 1) var dbEtx txmgr.DbEthTx - require.NoError(t, db.Get(&dbEtx, `SELECT * FROM eth_txes ORDER BY id ASC LIMIT 1`)) + require.NoError(t, db.Get(&dbEtx, `SELECT * FROM evm.txes ORDER BY id ASC LIMIT 1`)) m, err := etx.GetMeta() require.NoError(t, err) @@ -550,7 +550,7 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { require.Equal(t, payload, etx.EncodedPayload) }) - require.NoError(t, utils.JustError(db.Exec(`DELETE FROM eth_txes WHERE from_address = $1`, thisKey.Address))) + require.NoError(t, utils.JustError(db.Exec(`DELETE FROM evm.txes WHERE from_address = $1`, thisKey.Address))) t.Run("if this key has any transactions with insufficient eth errors, inserts it anyway", func(t *testing.T) { payload := cltest.MustRandomBytes(t, 100) @@ -573,7 +573,7 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { require.Equal(t, payload, etx.EncodedPayload) }) - require.NoError(t, utils.JustError(db.Exec(`DELETE FROM eth_txes WHERE from_address = $1`, thisKey.Address))) + require.NoError(t, utils.JustError(db.Exec(`DELETE FROM evm.txes WHERE from_address = $1`, thisKey.Address))) t.Run("if this key has transactions but no insufficient eth errors, transmits as normal", func(t *testing.T) { payload := cltest.MustRandomBytes(t, 100) @@ -626,7 +626,7 @@ func TestTxm_Lifecycle(t *testing.T) { sub := pgmocks.NewSubscription(t) sub.On("Events").Return(make(<-chan pg.Event)) - eventBroadcaster.On("Subscribe", "insert_on_eth_txes", "").Return(sub, nil) + eventBroadcaster.On("Subscribe", "evm.insert_on_txes", "").Return(sub, nil) evmConfig.bumpThreshold = uint64(1) require.NoError(t, txm.Start(testutils.Context(t))) @@ -695,7 +695,7 @@ func TestTxm_Reset(t *testing.T) { sub := pgmocks.NewSubscription(t) sub.On("Events").Return(make(<-chan pg.Event)) sub.On("Close") - eventBroadcaster.On("Subscribe", "insert_on_eth_txes", "").Return(sub, nil) + eventBroadcaster.On("Subscribe", "evm.insert_on_txes", "").Return(sub, nil) estimator := gas.NewEstimator(logger.TestLogger(t), ethClient, cfg.EVM(), cfg.EVM().GasEstimator()) txm, err := makeTestEvmTxm(t, db, ethClient, estimator, cfg.EVM(), cfg.EVM().GasEstimator(), cfg.EVM().Transactions(), cfg.Database(), cfg.Database().Listener(), kst.Eth(), eventBroadcaster) @@ -728,7 +728,7 @@ func TestTxm_Reset(t *testing.T) { f.AssertCalled(t) }) - t.Run("calls function and deletes relevant eth_txes if abandon=true", func(t *testing.T) { + t.Run("calls function and deletes relevant evm.txes if abandon=true", func(t *testing.T) { f := new(fnMock) err := txm.Reset(f.Fn, addr, true) @@ -737,13 +737,13 @@ func TestTxm_Reset(t *testing.T) { f.AssertCalled(t) var s string - err = db.Get(&s, `SELECT error FROM eth_txes WHERE from_address = $1 AND state = 'fatal_error'`, addr) + err = db.Get(&s, `SELECT error FROM evm.txes WHERE from_address = $1 AND state = 'fatal_error'`, addr) require.NoError(t, err) assert.Equal(t, "abandoned", s) // the other address didn't get touched var count int - err = db.Get(&count, `SELECT count(*) FROM eth_txes WHERE from_address = $1 AND state = 'fatal_error'`, addr2) + err = db.Get(&count, `SELECT count(*) FROM evm.txes WHERE from_address = $1 AND state = 'fatal_error'`, addr2) require.NoError(t, err) assert.Equal(t, 0, count) }) diff --git a/core/chains/evm/types/types.go b/core/chains/evm/types/types.go index dea4f9771fd..7d756485d00 100644 --- a/core/chains/evm/types/types.go +++ b/core/chains/evm/types/types.go @@ -12,13 +12,16 @@ import ( "github.com/pkg/errors" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink/v2/core/chains" + "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils" ) type Configs interface { - chains.ChainConfigs - chains.NodeConfigs[utils.Big, Node] + Chains(ids ...relay.ChainID) ([]types.ChainStatus, int, error) + Node(name string) (Node, error) + Nodes(chainID relay.ChainID) (nodes []Node, err error) + NodeStatus(name string) (types.NodeStatus, error) } type Node struct { diff --git a/core/chains/solana/chain.go b/core/chains/solana/chain.go index b39435368ad..682fb23f9f2 100644 --- a/core/chains/solana/chain.go +++ b/core/chains/solana/chain.go @@ -30,6 +30,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/internal" "github.com/smartcontractkit/chainlink/v2/core/chains/solana/monitor" "github.com/smartcontractkit/chainlink/v2/core/services" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -40,7 +41,6 @@ const DefaultRequestTimeout = 30 * time.Second type ChainOpts struct { Logger logger.Logger KeyStore loop.Keystore - Configs Configs } func (o *ChainOpts) Validate() (err error) { @@ -53,21 +53,18 @@ func (o *ChainOpts) Validate() (err error) { if o.KeyStore == nil { err = multierr.Append(err, required("KeyStore")) } - if o.Configs == nil { - err = multierr.Append(err, required("Configs")) - } return } -func (o *ChainOpts) ConfigsAndLogger() (chains.Configs[string, db.Node], logger.Logger) { - return o.Configs, o.Logger +func (o *ChainOpts) GetLogger() logger.Logger { + return o.Logger } func NewChain(cfg *SolanaConfig, opts ChainOpts) (solana.Chain, error) { if !cfg.IsEnabled() { return nil, fmt.Errorf("cannot create new chain with ID %s: %w", *cfg.ChainID, chains.ErrChainDisabled) } - c, err := newChain(*cfg.ChainID, cfg, opts.KeyStore, opts.Configs, opts.Logger) + c, err := newChain(*cfg.ChainID, cfg, opts.KeyStore, opts.Logger) if err != nil { return nil, err } @@ -82,7 +79,6 @@ type chain struct { cfg *SolanaConfig txm *txm.Txm balanceMonitor services.ServiceCtx - nodes func(chainID string) (nodes []db.Node, err error) lggr logger.Logger // tracking node chain id for verification @@ -213,12 +209,11 @@ func (v *verifiedCachedClient) GetAccountInfoWithOpts(ctx context.Context, addr return v.ReaderWriter.GetAccountInfoWithOpts(ctx, addr, opts) } -func newChain(id string, cfg *SolanaConfig, ks loop.Keystore, cfgs Configs, lggr logger.Logger) (*chain, error) { +func newChain(id string, cfg *SolanaConfig, ks loop.Keystore, lggr logger.Logger) (*chain, error) { lggr = logger.With(lggr, "chainID", id, "chain", "solana") var ch = chain{ id: id, cfg: cfg, - nodes: cfgs.Nodes, lggr: logger.Named(lggr, "Chain"), clientCache: map[string]*verifiedCachedClient{}, } @@ -262,7 +257,7 @@ func (c *chain) listNodeStatuses(start, end int) ([]relaytypes.NodeStatus, int, } nodes := c.cfg.Nodes[start:end] for _, node := range nodes { - stat, err := nodeStatus(node, c.id) + stat, err := nodeStatus(node, c.ChainID()) if err != nil { return stats, total, err } @@ -291,11 +286,15 @@ func (c *chain) Reader() (client.Reader, error) { return c.getClient() } +func (c *chain) ChainID() relay.ChainID { + return relay.ChainID(c.id) +} + // getClient returns a client, randomly selecting one from available and valid nodes func (c *chain) getClient() (client.ReaderWriter, error) { var node db.Node var client client.ReaderWriter - nodes, err := c.nodes(c.id) // opt: pass static nodes set to constructor + nodes, err := c.cfg.ListNodes() if err != nil { return nil, errors.Wrap(err, "failed to get nodes") } diff --git a/core/chains/solana/chain_test.go b/core/chains/solana/chain_test.go index 898b70213df..c8dfcf8501e 100644 --- a/core/chains/solana/chain_test.go +++ b/core/chains/solana/chain_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-relay/pkg/utils" "github.com/smartcontractkit/chainlink-solana/pkg/solana/client" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana/db" @@ -44,8 +44,6 @@ func TestSolanaChain_GetClient(t *testing.T) { })) defer mockServer.Close() - solORM := &mockConfigs{} - ch := solcfg.Chain{} ch.SetDefaults() cfg := &SolanaConfig{ @@ -54,68 +52,66 @@ func TestSolanaChain_GetClient(t *testing.T) { } testChain := chain{ id: "devnet", - nodes: solORM.Nodes, cfg: cfg, lggr: logger.TestLogger(t), clientCache: map[string]*verifiedCachedClient{}, } - // random nodes (happy path, all valid) - solORM.nodesForChain = []db.Node{ - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/1", + cfg.Nodes = SolanaNodes([]*solcfg.Node{ + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/1"), }, - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/2", + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/2"), }, - } + }) _, err := testChain.getClient() assert.NoError(t, err) // random nodes (happy path, 1 valid + multiple invalid) - solORM.nodesForChain = []db.Node{ - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/1", + cfg.Nodes = SolanaNodes([]*solcfg.Node{ + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/1"), }, - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/mismatch/1", + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/mismatch/1"), }, - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/mismatch/2", + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/mismatch/2"), }, - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/mismatch/3", + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/mismatch/3"), }, - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/mismatch/4", + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/mismatch/4"), }, - } + }) _, err = testChain.getClient() assert.NoError(t, err) // empty nodes response - solORM.nodesForChain = nil + cfg.Nodes = nil _, err = testChain.getClient() assert.Error(t, err) // no valid nodes to select from - solORM.nodesForChain = []db.Node{ - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/mismatch/1", + cfg.Nodes = SolanaNodes([]*solcfg.Node{ + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/mismatch/1"), }, - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/mismatch/2", + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/mismatch/2"), }, - } + }) _, err = testChain.getClient() assert.NoError(t, err) } @@ -230,28 +226,6 @@ func TestSolanaChain_VerifiedClient_ParallelClients(t *testing.T) { assert.Equal(t, testChain.clientCache[mockServer.URL], client1) } -var _ Configs = &mockConfigs{} - -type mockConfigs struct { - nodesForChain []db.Node -} - -func (m *mockConfigs) Nodes(chainID string) (nodes []db.Node, err error) { - return m.nodesForChain, nil -} - -func (m *mockConfigs) Chains(offset, limit int, ids ...string) ([]types.ChainStatus, int, error) { - panic("unimplemented") -} - -func (m *mockConfigs) Node(s string) (db.Node, error) { panic("unimplemented") } - -func (m *mockConfigs) NodeStatus(s string) (types.NodeStatus, error) { panic("unimplemented") } - -func (m *mockConfigs) NodeStatusesPaged(offset, limit int, chainIDs ...string) (nodes []types.NodeStatus, count int, err error) { - panic("unimplemented") -} - func ptr[T any](t T) *T { return &t } diff --git a/core/chains/solana/config.go b/core/chains/solana/config.go index c9d2f19d61c..b6e4a077f9e 100644 --- a/core/chains/solana/config.go +++ b/core/chains/solana/config.go @@ -15,7 +15,7 @@ import ( solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" soldb "github.com/smartcontractkit/chainlink-solana/pkg/solana/db" - "github.com/smartcontractkit/chainlink/v2/core/chains" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) @@ -75,116 +75,9 @@ func (cs *SolanaConfigs) SetFrom(fs *SolanaConfigs) (err error) { return } -func (cs SolanaConfigs) Chains(ids ...string) (r []relaytypes.ChainStatus, err error) { - for _, ch := range cs { - if ch == nil { - continue - } - if len(ids) > 0 { - var match bool - for _, id := range ids { - if id == *ch.ChainID { - match = true - break - } - } - if !match { - continue - } - } - ch2 := relaytypes.ChainStatus{ - ID: *ch.ChainID, - Enabled: ch.IsEnabled(), - } - ch2.Config, err = ch.TOMLString() - if err != nil { - return - } - r = append(r, ch2) - } - return -} - -func (cs SolanaConfigs) Node(name string) (soldb.Node, error) { - for i := range cs { - for _, n := range cs[i].Nodes { - if n.Name != nil && *n.Name == name { - return legacySolNode(n, *cs[i].ChainID), nil - } - } - } - return soldb.Node{}, fmt.Errorf("node %s: %w", name, chains.ErrNotFound) -} - -func (cs SolanaConfigs) nodes(chainID string) (ns SolanaNodes) { - for _, c := range cs { - if *c.ChainID == chainID { - return c.Nodes - } - } - return nil -} - -func (cs SolanaConfigs) Nodes(chainID string) (ns []soldb.Node, err error) { - nodes := cs.nodes(chainID) - if nodes == nil { - err = fmt.Errorf("no nodes: chain %s: %w", chainID, chains.ErrNotFound) - return - } - for _, n := range nodes { - if n == nil { - continue - } - ns = append(ns, legacySolNode(n, chainID)) - } - return -} - -func (cs SolanaConfigs) NodeStatus(name string) (relaytypes.NodeStatus, error) { - for i := range cs { - for _, n := range cs[i].Nodes { - if n.Name != nil && *n.Name == name { - return nodeStatus(n, *cs[i].ChainID) - } - } - } - return relaytypes.NodeStatus{}, fmt.Errorf("node %s: %w", name, chains.ErrNotFound) -} - -func (cs SolanaConfigs) NodeStatuses(chainIDs ...string) (ns []relaytypes.NodeStatus, err error) { - if len(chainIDs) == 0 { - for i := range cs { - for _, n := range cs[i].Nodes { - if n == nil { - continue - } - n2, err := nodeStatus(n, *cs[i].ChainID) - if err != nil { - return nil, err - } - ns = append(ns, n2) - } - } - return - } - for _, id := range chainIDs { - for _, n := range cs.nodes(id) { - if n == nil { - continue - } - n2, err := nodeStatus(n, id) - if err != nil { - return nil, err - } - ns = append(ns, n2) - } - } - return -} - -func nodeStatus(n *solcfg.Node, chainID string) (relaytypes.NodeStatus, error) { +func nodeStatus(n *solcfg.Node, id relay.ChainID) (relaytypes.NodeStatus, error) { var s relaytypes.NodeStatus - s.ChainID = chainID + s.ChainID = id s.Name = *n.Name b, err := toml.Marshal(n) if err != nil { @@ -219,10 +112,10 @@ func setFromNode(n, f *solcfg.Node) { } } -func legacySolNode(n *solcfg.Node, chainID string) soldb.Node { +func legacySolNode(n *solcfg.Node, id relay.ChainID) soldb.Node { return soldb.Node{ Name: *n.Name, - SolanaChainID: chainID, + SolanaChainID: id, SolanaURL: (*url.URL)(n.URL).String(), } } @@ -370,14 +263,10 @@ func (c *SolanaConfig) FeeBumpPeriod() time.Duration { return c.Chain.FeeBumpPeriod.Duration() } -// Configs manages solana chains and nodes. -type Configs interface { - chains.ChainConfigs - chains.NodeConfigs[string, soldb.Node] -} - -var _ chains.Configs[string, soldb.Node] = (Configs)(nil) - -func NewConfigs(cfgs chains.ConfigsV2[string, soldb.Node]) Configs { - return chains.NewConfigs(cfgs) +func (c *SolanaConfig) ListNodes() ([]soldb.Node, error) { + var allNodes []soldb.Node + for _, n := range c.Nodes { + allNodes = append(allNodes, legacySolNode(n, *c.ChainID)) + } + return allNodes, nil } diff --git a/core/chains/starknet/chain.go b/core/chains/starknet/chain.go index c6718c68065..fead94cda60 100644 --- a/core/chains/starknet/chain.go +++ b/core/chains/starknet/chain.go @@ -23,7 +23,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/internal" - "github.com/smartcontractkit/chainlink/v2/core/chains/starknet/types" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -31,7 +31,6 @@ type ChainOpts struct { Logger logger.Logger // the implementation used here needs to be co-ordinated with the starknet transaction manager keystore adapter KeyStore loop.Keystore - Configs types.Configs } func (o *ChainOpts) Name() string { @@ -48,23 +47,15 @@ func (o *ChainOpts) Validate() (err error) { if o.KeyStore == nil { err = multierr.Append(err, required("KeyStore")) } - if o.Configs == nil { - err = multierr.Append(err, required("Configs")) - } return } -func (o *ChainOpts) ConfigsAndLogger() (chains.Configs[string, db.Node], logger.Logger) { - return o.Configs, o.Logger -} - var _ starkChain.Chain = (*chain)(nil) type chain struct { utils.StartStopOnce id string cfg *StarknetConfig - cfgs types.Configs lggr logger.Logger txm txm.StarkTXM } @@ -73,19 +64,18 @@ func NewChain(cfg *StarknetConfig, opts ChainOpts) (starkchain.Chain, error) { if !cfg.IsEnabled() { return nil, fmt.Errorf("cannot create new chain with ID %s: %w", *cfg.ChainID, chains.ErrChainDisabled) } - c, err := newChain(*cfg.ChainID, cfg, opts.KeyStore, opts.Configs, opts.Logger) + c, err := newChain(*cfg.ChainID, cfg, opts.KeyStore, opts.Logger) if err != nil { return nil, err } return c, nil } -func newChain(id string, cfg *StarknetConfig, loopKs loop.Keystore, cfgs types.Configs, lggr logger.Logger) (*chain, error) { +func newChain(id string, cfg *StarknetConfig, loopKs loop.Keystore, lggr logger.Logger) (*chain, error) { lggr = logger.With(lggr, "starknetChainID", id) ch := &chain{ id: id, cfg: cfg, - cfgs: cfgs, lggr: logger.Named(lggr, "Chain"), } @@ -118,11 +108,15 @@ func (c *chain) Reader() (starknet.Reader, error) { return c.getClient() } +func (c *chain) ChainID() relay.ChainID { + return relay.ChainID(c.id) +} + // getClient returns a client, randomly selecting one from available and valid nodes func (c *chain) getClient() (*starknet.Client, error) { var node db.Node var client *starknet.Client - nodes, err := c.cfgs.Nodes(c.id) + nodes, err := c.cfg.ListNodes() if err != nil { return nil, errors.Wrap(err, "failed to get nodes") } @@ -215,7 +209,7 @@ func (c *chain) listNodeStatuses(start, end int) ([]relaytypes.NodeStatus, int, } nodes := c.cfg.Nodes[start:end] for _, node := range nodes { - stat, err := nodeStatus(node, c.id) + stat, err := nodeStatus(node, c.ChainID()) if err != nil { return stats, total, err } diff --git a/core/chains/starknet/config.go b/core/chains/starknet/config.go index b28d8e6a487..33b2a8d257a 100644 --- a/core/chains/starknet/config.go +++ b/core/chains/starknet/config.go @@ -14,7 +14,7 @@ import ( stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/db" - "github.com/smartcontractkit/chainlink/v2/core/chains" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) @@ -74,118 +74,9 @@ func (cs *StarknetConfigs) SetFrom(fs *StarknetConfigs) (err error) { return } -func (cs StarknetConfigs) Chains(ids ...string) (r []types.ChainStatus, err error) { - for _, ch := range cs { - if ch == nil { - continue - } - if len(ids) > 0 { - var match bool - for _, id := range ids { - if id == *ch.ChainID { - match = true - break - } - } - if !match { - continue - } - } - ch2 := types.ChainStatus{ - ID: *ch.ChainID, - Enabled: ch.IsEnabled(), - } - ch2.Config, err = ch.TOMLString() - if err != nil { - return - } - r = append(r, ch2) - } - return -} - -func (cs StarknetConfigs) Node(name string) (n db.Node, err error) { - for i := range cs { - for _, n := range cs[i].Nodes { - if n.Name != nil && *n.Name == name { - return legacyNode(n, *cs[i].ChainID), nil - } - } - } - err = fmt.Errorf("node %s: %w", name, chains.ErrNotFound) - return -} - -func (cs StarknetConfigs) nodes(chainID string) (ns StarknetNodes) { - for _, c := range cs { - if *c.ChainID == chainID { - return c.Nodes - } - } - return nil -} - -func (cs StarknetConfigs) Nodes(chainID string) (ns []db.Node, err error) { - nodes := cs.nodes(chainID) - if nodes == nil { - err = fmt.Errorf("no nodes: chain %s: %w", chainID, chains.ErrNotFound) - return - } - for _, n := range nodes { - if n == nil { - continue - } - ns = append(ns, legacyNode(n, chainID)) - } - return -} - -func (cs StarknetConfigs) NodeStatus(name string) (n types.NodeStatus, err error) { - for i := range cs { - for _, n := range cs[i].Nodes { - if n.Name != nil && *n.Name == name { - return nodeStatus(n, *cs[i].ChainID) - } - } - } - err = fmt.Errorf("node %s: %w", name, chains.ErrNotFound) - return -} - -func (cs StarknetConfigs) NodeStatuses(chainIDs ...string) (ns []types.NodeStatus, err error) { - if len(chainIDs) == 0 { - for i := range cs { - for _, n := range cs[i].Nodes { - if n == nil { - continue - } - n2, err := nodeStatus(n, *cs[i].ChainID) - if err != nil { - return nil, err - } - ns = append(ns, n2) - } - } - return - } - for _, id := range chainIDs { - for _, n := range cs.nodes(id) { - if n == nil { - continue - } - n2, err := nodeStatus(n, id) - if err != nil { - return nil, err - } - ns = append(ns, n2) - } - } - return -} - -func nodeStatus(n *stkcfg.Node, chainID string) (types.NodeStatus, error) { +func nodeStatus(n *stkcfg.Node, id relay.ChainID) (types.NodeStatus, error) { var s types.NodeStatus - s.ChainID = chainID + s.ChainID = id s.Name = *n.Name b, err := toml.Marshal(n) if err != nil { @@ -283,7 +174,7 @@ func setFromNode(n, f *stkcfg.Node) { } } -func legacyNode(n *stkcfg.Node, id string) db.Node { +func legacyNode(n *stkcfg.Node, id relay.ChainID) db.Node { return db.Node{ Name: *n.Name, ChainID: id, @@ -312,3 +203,11 @@ func (c *StarknetConfig) OCR2CacheTTL() time.Duration { func (c *StarknetConfig) RequestTimeout() time.Duration { return c.Chain.RequestTimeout.Duration() } + +func (c *StarknetConfig) ListNodes() ([]db.Node, error) { + var allNodes []db.Node + for _, n := range c.Nodes { + allNodes = append(allNodes, legacyNode(n, *c.ChainID)) + } + return allNodes, nil +} diff --git a/core/chains/starknet/orm.go b/core/chains/starknet/orm.go deleted file mode 100644 index 9d7109d150e..00000000000 --- a/core/chains/starknet/orm.go +++ /dev/null @@ -1,12 +0,0 @@ -package starknet - -import ( - starknetdb "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/db" - - "github.com/smartcontractkit/chainlink/v2/core/chains" - "github.com/smartcontractkit/chainlink/v2/core/chains/starknet/types" -) - -func NewConfigs(cfgs chains.ConfigsV2[string, starknetdb.Node]) types.Configs { - return chains.NewConfigs(cfgs) -} diff --git a/core/chains/starknet/types/types.go b/core/chains/starknet/types/types.go deleted file mode 100644 index 2158d80fbb9..00000000000 --- a/core/chains/starknet/types/types.go +++ /dev/null @@ -1,12 +0,0 @@ -package types - -import ( - "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/db" - - "github.com/smartcontractkit/chainlink/v2/core/chains" -) - -type Configs interface { - chains.ChainConfigs - chains.NodeConfigs[string, db.Node] -} diff --git a/core/cmd/app_test.go b/core/cmd/app_test.go index d99f941fded..78331bf7063 100644 --- a/core/cmd/app_test.go +++ b/core/cmd/app_test.go @@ -145,7 +145,6 @@ func Test_initServerConfig(t *testing.T) { fileNames: []string{testtomlutils.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, secretsFiles: []string{ "../services/chainlink/testdata/mergingsecretsdata/secrets-database.toml", - "../services/chainlink/testdata/mergingsecretsdata/secrets-explorer.toml", "../services/chainlink/testdata/mergingsecretsdata/secrets-password.toml", "../services/chainlink/testdata/mergingsecretsdata/secrets-pyroscope.toml", "../services/chainlink/testdata/mergingsecretsdata/secrets-prometheus.toml", @@ -168,18 +167,6 @@ func Test_initServerConfig(t *testing.T) { }, wantErr: true, }, - { - name: "reading multiple secrets with overrides: Explorer", - args: args{ - opts: new(chainlink.GeneralConfigOpts), - fileNames: []string{testtomlutils.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, - secretsFiles: []string{ - "../testdata/mergingsecretsdata/secrets-explorer.toml", - "../testdata/mergingsecretsdata/secrets-explorer.toml", - }, - }, - wantErr: true, - }, { name: "reading multiple secrets with overrides: Password", args: args{ diff --git a/core/cmd/cosmos_transaction_commands_test.go b/core/cmd/cosmos_transaction_commands_test.go index 11b89c5232a..04858d2956a 100644 --- a/core/cmd/cosmos_transaction_commands_test.go +++ b/core/cmd/cosmos_transaction_commands_test.go @@ -50,7 +50,7 @@ func TestShell_SendCosmosCoins(t *testing.T) { chainID := cosmostest.RandomChainID() cosmosChain := coscfg.Chain{} cosmosChain.SetDefaults() - accounts, _, url := cosmosclient.SetupLocalCosmosNode(t, chainID, *cosmosChain.FeeToken) + accounts, _, url := cosmosclient.SetupLocalCosmosNode(t, chainID, *cosmosChain.GasToken) require.Greater(t, len(accounts), 1) nodes := cosmos.CosmosNodes{ &coscfg.Node{ @@ -71,7 +71,7 @@ func TestShell_SendCosmosCoins(t *testing.T) { require.NoError(t, err) require.Eventually(t, func() bool { - coin, err := reader.Balance(from.Address, *cosmosChain.FeeToken) + coin, err := reader.Balance(from.Address, *cosmosChain.GasToken) if !assert.NoError(t, err) { return false } @@ -97,7 +97,7 @@ func TestShell_SendCosmosCoins(t *testing.T) { } { tt := tt t.Run(tt.amount, func(t *testing.T) { - startBal, err := reader.Balance(from.Address, *cosmosChain.FeeToken) + startBal, err := reader.Balance(from.Address, *cosmosChain.GasToken) require.NoError(t, err) set := flag.NewFlagSet("sendcosmoscoins", 0) @@ -156,11 +156,11 @@ func TestShell_SendCosmosCoins(t *testing.T) { } // Check balance - endBal, err := reader.Balance(from.Address, *cosmosChain.FeeToken) + endBal, err := reader.Balance(from.Address, *cosmosChain.GasToken) require.NoError(t, err) if assert.NotNil(t, startBal) && assert.NotNil(t, endBal) { diff := startBal.Sub(*endBal).Amount - sent, err := denom.ConvertDecCoinToDenom(sdk.NewDecCoinFromDec(nativeToken, sdk.MustNewDecFromStr(tt.amount)), *cosmosChain.FeeToken) + sent, err := denom.ConvertDecCoinToDenom(sdk.NewDecCoinFromDec(nativeToken, sdk.MustNewDecFromStr(tt.amount)), *cosmosChain.GasToken) require.NoError(t, err) if assert.True(t, diff.IsInt64()) && assert.True(t, sent.Amount.IsInt64()) { require.Greater(t, diff.Int64(), sent.Amount.Int64()) diff --git a/core/cmd/eth_keys_commands_test.go b/core/cmd/eth_keys_commands_test.go index 71dee517b27..30e115e9482 100644 --- a/core/cmd/eth_keys_commands_test.go +++ b/core/cmd/eth_keys_commands_test.go @@ -15,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -177,33 +178,26 @@ func TestShell_CreateETHKey(t *testing.T) { db := app.GetSqlxDB() client, _ := app.NewShellAndRenderer() - cltest.AssertCount(t, db, "evm_key_states", 1) // The initial funding key + cltest.AssertCount(t, db, "evm.key_states", 1) // The initial funding key keys, err := app.KeyStore.Eth().GetAll() require.NoError(t, err) require.Equal(t, 1, len(keys)) - // create a key on the default chain - set := flag.NewFlagSet("test", 0) - cltest.FlagSetApplyFromAction(client.CreateETHKey, set, "") - c := cli.NewContext(nil, set, nil) - assert.NoError(t, client.CreateETHKey(c)) - - // create the key on a specific chainID id := big.NewInt(0) - set = flag.NewFlagSet("test", 0) + set := flag.NewFlagSet("test", 0) cltest.FlagSetApplyFromAction(client.CreateETHKey, set, "") - require.NoError(t, set.Set("evmChainID", "")) + require.NoError(t, set.Set("evm-chain-id", testutils.FixtureChainID.String())) - c = cli.NewContext(nil, set, nil) - require.NoError(t, set.Parse([]string{"-evmChainID", id.String()})) + c := cli.NewContext(nil, set, nil) + require.NoError(t, set.Parse([]string{"-evm-chain-id", id.String()})) assert.NoError(t, client.CreateETHKey(c)) - cltest.AssertCount(t, db, "evm_key_states", 3) + cltest.AssertCount(t, db, "evm.key_states", 2) keys, err = app.KeyStore.Eth().GetAll() require.NoError(t, err) - require.Equal(t, 3, len(keys)) + require.Equal(t, 2, len(keys)) } func TestShell_DeleteETHKey(t *testing.T) { @@ -304,13 +298,16 @@ func TestShell_ImportExportETHKey_NoChains(t *testing.T) { _, err = ethKeyStore.Get(address) require.Error(t, err) - cltest.AssertCount(t, app.GetSqlxDB(), "evm_key_states", 0) + cltest.AssertCount(t, app.GetSqlxDB(), "evm.key_states", 0) // Import the key set = flag.NewFlagSet("test", 0) - set.String("old-password", "../internal/fixtures/incorrect_password.txt", "") - err = set.Parse([]string{keyfilepath}) - require.NoError(t, err) + cltest.FlagSetApplyFromAction(client.ImportETHKey, set, "") + + require.NoError(t, set.Set("evmChainID", testutils.FixtureChainID.String())) + require.NoError(t, set.Set("old-password", "../internal/fixtures/incorrect_password.txt")) + require.NoError(t, set.Parse([]string{keyfilepath})) + c = cli.NewContext(nil, set, nil) err = client.ImportETHKey(c) require.NoError(t, err) @@ -412,6 +409,8 @@ func TestShell_ImportExportETHKey_WithChains(t *testing.T) { set = flag.NewFlagSet("test", 0) cltest.FlagSetApplyFromAction(client.ImportETHKey, set, "") + require.NoError(t, set.Set("evmChainID", testutils.FixtureChainID.String())) + require.NoError(t, set.Set("evmChainID", testutils.FixtureChainID.String())) require.NoError(t, set.Set("old-password", "../internal/fixtures/incorrect_password.txt")) require.NoError(t, set.Parse([]string{keyfilepath})) diff --git a/core/cmd/evm_transaction_commands.go b/core/cmd/evm_transaction_commands.go index 8239ff34569..68fffde303e 100644 --- a/core/cmd/evm_transaction_commands.go +++ b/core/cmd/evm_transaction_commands.go @@ -133,7 +133,7 @@ func (s *Shell) ShowTransaction(c *cli.Context) (err error) { // SendEther transfers ETH from the node's account to a specified address. func (s *Shell) SendEther(c *cli.Context) (err error) { if c.NArg() < 3 { - return s.errorOut(errors.New("three arguments expected: amount, fromAddress and toAddress")) + return s.errorOut(errors.New("the following arguments expected: (chain) id (in multi-chain setup), amount, fromAddress and toAddress")) } var amount assets.Eth diff --git a/core/cmd/evm_transaction_commands_test.go b/core/cmd/evm_transaction_commands_test.go index e1dcb5ec3bb..f213aefb154 100644 --- a/core/cmd/evm_transaction_commands_test.go +++ b/core/cmd/evm_transaction_commands_test.go @@ -17,6 +17,8 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) @@ -160,6 +162,7 @@ func TestShell_SendEther_From_Txm(t *testing.T) { amount := "100.5" to := "0x342156c8d3bA54Abc67920d35ba1d1e67201aC9C" require.NoError(t, set.Parse([]string{amount, fromAddress.Hex(), to})) + require.NoError(t, set.Set("id", evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs()).String())) cliapp := cli.NewApp() c := cli.NewContext(cliapp, set, nil) @@ -167,7 +170,7 @@ func TestShell_SendEther_From_Txm(t *testing.T) { assert.NoError(t, client.SendEther(c)) dbEvmTx := txmgr.DbEthTx{} - require.NoError(t, db.Get(&dbEvmTx, `SELECT * FROM eth_txes`)) + require.NoError(t, db.Get(&dbEvmTx, `SELECT * FROM evm.txes`)) require.Equal(t, "100.500000000000000000", dbEvmTx.Value.String()) require.Equal(t, fromAddress, dbEvmTx.FromAddress) require.Equal(t, to, dbEvmTx.ToAddress.String()) @@ -179,7 +182,7 @@ func TestShell_SendEther_From_Txm(t *testing.T) { assert.Equal(t, fmt.Sprintf("%d", *dbEvmTx.Nonce), output.Nonce) dbEvmTxAttempt := txmgr.DbEthTxAttempt{} - require.NoError(t, db.Get(&dbEvmTxAttempt, `SELECT * FROM eth_tx_attempts`)) + require.NoError(t, db.Get(&dbEvmTxAttempt, `SELECT * FROM evm.tx_attempts`)) assert.Equal(t, dbEvmTxAttempt.Hash, output.Hash) } @@ -215,6 +218,7 @@ func TestShell_SendEther_From_Txm_WEI(t *testing.T) { set := flag.NewFlagSet("sendether", 0) cltest.FlagSetApplyFromAction(client.SendEther, set, "") + require.NoError(t, set.Set("id", testutils.FixtureChainID.String())) require.NoError(t, set.Set("wei", "false")) amount := "1000000000000000000" @@ -231,7 +235,7 @@ func TestShell_SendEther_From_Txm_WEI(t *testing.T) { assert.NoError(t, client.SendEther(c)) dbEvmTx := txmgr.DbEthTx{} - require.NoError(t, db.Get(&dbEvmTx, `SELECT * FROM eth_txes`)) + require.NoError(t, db.Get(&dbEvmTx, `SELECT * FROM evm.txes`)) require.Equal(t, "1.000000000000000000", dbEvmTx.Value.String()) require.Equal(t, fromAddress, dbEvmTx.FromAddress) require.Equal(t, to, dbEvmTx.ToAddress.String()) @@ -243,6 +247,6 @@ func TestShell_SendEther_From_Txm_WEI(t *testing.T) { assert.Equal(t, fmt.Sprintf("%d", *dbEvmTx.Nonce), output.Nonce) dbEvmTxAttempt := txmgr.DbEthTxAttempt{} - require.NoError(t, db.Get(&dbEvmTxAttempt, `SELECT * FROM eth_tx_attempts`)) + require.NoError(t, db.Get(&dbEvmTxAttempt, `SELECT * FROM evm.tx_attempts`)) assert.Equal(t, dbEvmTxAttempt.Hash, output.Hash) } diff --git a/core/cmd/forwarders_commands_test.go b/core/cmd/forwarders_commands_test.go index 7d519917d5a..4381b5ca683 100644 --- a/core/cmd/forwarders_commands_test.go +++ b/core/cmd/forwarders_commands_test.go @@ -77,7 +77,7 @@ func TestShell_TrackEVMForwarder(t *testing.T) { cltest.FlagSetApplyFromAction(client.TrackForwarder, set, "") require.NoError(t, set.Set("address", "0x5431F5F973781809D18643b87B44921b11355d81")) - require.NoError(t, set.Set("evmChainID", id.String())) + require.NoError(t, set.Set("evm-chain-id", id.String())) err := client.TrackForwarder(cli.NewContext(nil, set, nil)) require.NoError(t, err) @@ -122,7 +122,7 @@ func TestShell_TrackEVMForwarder_BadAddress(t *testing.T) { cltest.FlagSetApplyFromAction(client.TrackForwarder, set, "") require.NoError(t, set.Set("address", "0xWrongFormatAddress")) - require.NoError(t, set.Set("evmChainID", id.String())) + require.NoError(t, set.Set("evm-chain-id", id.String())) err := client.TrackForwarder(cli.NewContext(nil, set, nil)) require.Contains(t, err.Error(), "could not decode address: invalid hex string") diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index cd4f170523b..db4d0476fb3 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -375,18 +375,6 @@ func (s *Shell) runNode(c *cli.Context) error { legacyEVMChains := app.GetRelayers().LegacyEVMChains() - // By passing in a function we can be lazy trying to look up a default - // chain - if there are no existing keys, there is no need to check for - // a chain ID - DefaultEVMChainIDFunc := func() (*big.Int, error) { - def, err2 := legacyEVMChains.Default() - if err2 != nil { - return nil, errors.Wrap(err2, "cannot get default EVM chain ID; no default EVM chain available") - } - return def.ID(), nil - } - err = keyStore.Migrate(s.Config.Password().VRF(), DefaultEVMChainIDFunc) - if s.Config.EVMEnabled() { if err != nil { return errors.Wrap(err, "error migrating keystore") diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index 3825a010c66..8d2b5f1fabf 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -323,6 +323,7 @@ func TestShell_RebroadcastTransactions_Txm(t *testing.T) { set := flag.NewFlagSet("test", 0) cltest.FlagSetApplyFromAction(client.RebroadcastTransactions, set, "") + require.NoError(t, set.Set("evmChainID", testutils.FixtureChainID.String())) require.NoError(t, set.Set("beginningNonce", strconv.FormatUint(beginningNonce, 10))) require.NoError(t, set.Set("endingNonce", strconv.FormatUint(endingNonce, 10))) require.NoError(t, set.Set("gasPriceWei", "100000000000")) @@ -402,6 +403,7 @@ func TestShell_RebroadcastTransactions_OutsideRange_Txm(t *testing.T) { set := flag.NewFlagSet("test", 0) cltest.FlagSetApplyFromAction(client.RebroadcastTransactions, set, "") + require.NoError(t, set.Set("evmChainID", testutils.FixtureChainID.String())) require.NoError(t, set.Set("beginningNonce", strconv.FormatUint(uint64(beginningNonce), 10))) require.NoError(t, set.Set("endingNonce", strconv.FormatUint(uint64(endingNonce), 10))) require.NoError(t, set.Set("gasPriceWei", gasPrice.String())) @@ -480,9 +482,9 @@ func TestShell_RebroadcastTransactions_AddressCheck(t *testing.T) { } set := flag.NewFlagSet("test", 0) - set.Set("evmChainID", testutils.SimulatedChainID.String()) cltest.FlagSetApplyFromAction(client.RebroadcastTransactions, set, "") + require.NoError(t, set.Set("evmChainID", testutils.FixtureChainID.String())) require.NoError(t, set.Set("address", fromAddress.Hex())) require.NoError(t, set.Set("password", "../internal/fixtures/correct_password.txt")) c := cli.NewContext(nil, set, nil) diff --git a/core/cmd/shell_remote_test.go b/core/cmd/shell_remote_test.go index 69fa5924828..83686443faa 100644 --- a/core/cmd/shell_remote_test.go +++ b/core/cmd/shell_remote_test.go @@ -125,13 +125,9 @@ func TestShell_ReplayBlocks(t *testing.T) { cltest.FlagSetApplyFromAction(client.ReplayFromBlock, set, "") require.NoError(t, set.Set("block-number", "42")) - - c := cli.NewContext(nil, set, nil) - assert.NoError(t, client.ReplayFromBlock(c)) - require.NoError(t, set.Set("evm-chain-id", "12345678")) - c = cli.NewContext(nil, set, nil) - assert.ErrorContains(t, client.ReplayFromBlock(c), "evmChainID does not match any local chains") + c := cli.NewContext(nil, set, nil) + assert.ErrorContains(t, client.ReplayFromBlock(c), "chain id does not match any local chains") require.NoError(t, set.Set("evm-chain-id", "0")) c = cli.NewContext(nil, set, nil) diff --git a/core/config/app_config.go b/core/config/app_config.go index 82652d3c8ce..20e877e6ec1 100644 --- a/core/config/app_config.go +++ b/core/config/app_config.go @@ -1,7 +1,6 @@ package config import ( - "math/big" "time" "github.com/google/uuid" @@ -21,7 +20,6 @@ type AppConfig interface { RootDir() string ShutdownGracePeriod() time.Duration InsecureFastScrypt() bool - DefaultChainID() *big.Int EVMEnabled() bool EVMRPCEnabled() bool CosmosEnabled() bool @@ -38,7 +36,6 @@ type AppConfig interface { AuditLogger() AuditLogger AutoPprof() AutoPprof Database() Database - Explorer() Explorer Feature() Feature FluxMonitor() FluxMonitor Insecure() Insecure diff --git a/core/config/docs/chains-cosmos.toml b/core/config/docs/chains-cosmos.toml index 3281c6c27a6..bcdb040a680 100644 --- a/core/config/docs/chains-cosmos.toml +++ b/core/config/docs/chains-cosmos.toml @@ -13,8 +13,8 @@ BlocksUntilTxTimeout = 30 # Default ConfirmPollPeriod = '1s' # Default # FallbackGasPrice sets a fallback gas price to use when the estimator is not available. FallbackGasPrice = '0.015' # Default -# FeeToken is the token denomination which is being used to pay gas fees on this chain. -FeeToken = 'ucosm' # Default +# GasToken is the token denomination which is being used to pay gas fees on this chain. +GasToken = 'ucosm' # Default # GasLimitMultiplier scales the estimated gas limit. GasLimitMultiplier = '1.5' # Default # MaxMsgsPerBatch limits the numbers of mesages per transaction batch. diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml index 7253cbd1aad..b9c1063c12a 100644 --- a/core/config/docs/core.toml +++ b/core/config/docs/core.toml @@ -1,5 +1,3 @@ -# ExplorerURL is the websocket URL used by the node to push stats. This variable is required to deliver telemetry. -ExplorerURL = 'ws://explorer.url' # Example # **ADVANCED** # InsecureFastScrypt causes all key stores to encrypt using "fast" scrypt params instead. This is insecure and only useful for local testing. DO NOT ENABLE THIS IN PRODUCTION. InsecureFastScrypt = false # Default diff --git a/core/config/docs/secrets.toml b/core/config/docs/secrets.toml index de097e50a0e..2b491a77497 100644 --- a/core/config/docs/secrets.toml +++ b/core/config/docs/secrets.toml @@ -14,16 +14,6 @@ BackupURL = "postgresql://user:pass@read-replica.example.com:5432/dbname?sslmode # Environment variable: `CL_DATABASE_ALLOW_SIMPLE_PASSWORDS` AllowSimplePasswords = false # Default -[Explorer] -# AccessKey is the access key for authenticating with the Explorer. -# -# Environment variable: `CL_EXPLORER_ACCESS_KEY` -AccessKey = "access_key" # Example -# Secret is the secret for authenticating with the Explorer. -# -# Environment variable: `CL_EXPLORER_SECRET` -Secret = "secret" # Example - [Password] # Keystore is the password for the node's account. # @@ -51,8 +41,10 @@ AuthToken = "prometheus-token" # Example Username = "A-Mercury-Username" # Example # Password is used for basic auth of the Mercury endpoint Password = "A-Mercury-Password" # Example -# URL is the Mercury endpoint URL which is used by OCR2 Automation to access Mercury price feed +# URL is the Mercury endpoint base URL used to access Mercury price feed URL = "https://example.com" # Example +# LegacyURL is the Mercury legacy endpoint base URL used to access Mercury v0.2 price feed +LegacyURL = "https://example.v1.com" # Example [Threshold] # ThresholdKeyShare used by the threshold decryption OCR plugin diff --git a/core/config/env/env.go b/core/config/env/env.go index 160aae65f6d..7813df4a8cc 100644 --- a/core/config/env/env.go +++ b/core/config/env/env.go @@ -31,8 +31,6 @@ var ( DatabaseAllowSimplePasswords = Var("CL_DATABASE_ALLOW_SIMPLE_PASSWORDS") DatabaseURL = Secret("CL_DATABASE_URL") DatabaseBackupURL = Secret("CL_DATABASE_BACKUP_URL") - ExplorerAccessKey = Secret("CL_EXPLORER_ACCESS_KEY") - ExplorerSecret = Secret("CL_EXPLORER_SECRET") PasswordKeystore = Secret("CL_PASSWORD_KEYSTORE") PasswordVRF = Secret("CL_PASSWORD_VRF") PyroscopeAuthToken = Secret("CL_PYROSCOPE_AUTH_TOKEN") diff --git a/core/config/ethereum_config.go b/core/config/ethereum_config.go deleted file mode 100644 index de3ccf28047..00000000000 --- a/core/config/ethereum_config.go +++ /dev/null @@ -1,9 +0,0 @@ -package config - -import ( - "math/big" -) - -type Ethereum interface { - DefaultChainID() *big.Int -} diff --git a/core/config/explorer_config.go b/core/config/explorer_config.go deleted file mode 100644 index dcb201d616d..00000000000 --- a/core/config/explorer_config.go +++ /dev/null @@ -1,9 +0,0 @@ -package config - -import "net/url" - -type Explorer interface { - AccessKey() string - Secret() string - URL() *url.URL -} diff --git a/core/config/toml/types.go b/core/config/toml/types.go index 5aedcf4deb6..5fba0c7ea5e 100644 --- a/core/config/toml/types.go +++ b/core/config/toml/types.go @@ -32,7 +32,6 @@ var ErrUnsupported = errors.New("unsupported with config v2") type Core struct { // General/misc AppID uuid.UUID `toml:"-"` // random or test - ExplorerURL *models.URL InsecureFastScrypt *bool RootDir *string ShutdownGracePeriod *models.Duration @@ -57,9 +56,6 @@ type Core struct { // SetFrom updates c with any non-nil values from f. (currently TOML field only!) func (c *Core) SetFrom(f *Core) { - if v := f.ExplorerURL; v != nil { - c.ExplorerURL = v - } if v := f.InsecureFastScrypt; v != nil { c.InsecureFastScrypt = v } @@ -102,7 +98,6 @@ func (c *Core) ValidateConfig() (err error) { type Secrets struct { Database DatabaseSecrets `toml:",omitempty"` - Explorer ExplorerSecrets `toml:",omitempty"` Password Passwords `toml:",omitempty"` Pyroscope PyroscopeSecrets `toml:",omitempty"` Prometheus PrometheusSecrets `toml:",omitempty"` @@ -197,39 +192,6 @@ func (d *DatabaseSecrets) validateMerge(f *DatabaseSecrets) (err error) { return err } -type ExplorerSecrets struct { - AccessKey *models.Secret - Secret *models.Secret -} - -func (e *ExplorerSecrets) SetFrom(f *ExplorerSecrets) (err error) { - err = e.validateMerge(f) - if err != nil { - return err - } - - if v := f.AccessKey; v != nil { - e.AccessKey = v - } - if v := f.Secret; v != nil { - e.Secret = v - } - - return nil -} - -func (e *ExplorerSecrets) validateMerge(f *ExplorerSecrets) (err error) { - if e.AccessKey != nil && f.AccessKey != nil { - err = multierr.Append(err, configutils.ErrOverride{Name: "AccessKey"}) - } - - if e.Secret != nil && f.Secret != nil { - err = multierr.Append(err, configutils.ErrOverride{Name: "Secret"}) - } - - return err -} - type Passwords struct { Keystore *models.Secret VRF *models.Secret @@ -1215,8 +1177,13 @@ func (ins *Insecure) setFrom(f *Insecure) { } type MercuryCredentials struct { - URL *models.SecretURL + // LegacyURL is the legacy base URL for mercury v0.2 API + LegacyURL *models.SecretURL + // URL is the base URL for mercury v0.3 API + URL *models.SecretURL + // Username is the user id for mercury credential Username *models.Secret + // Password is the user secret key for mercury credential Password *models.Secret } @@ -1263,6 +1230,10 @@ func (m *MercurySecrets) ValidateConfig() (err error) { err = multierr.Append(err, configutils.ErrMissing{Name: "URL", Msg: "must be provided and non-empty"}) continue } + if creds.LegacyURL != nil && creds.LegacyURL.URL() == nil { + err = multierr.Append(err, configutils.ErrMissing{Name: "Legacy URL", Msg: "must be a valid URL"}) + continue + } s := creds.URL.URL().String() if _, exists := urls[s]; exists { err = multierr.Append(err, configutils.NewErrDuplicate("URL", s)) diff --git a/core/config/toml/types_test.go b/core/config/toml/types_test.go index e2eb5eed815..2ab3f0fb86b 100644 --- a/core/config/toml/types_test.go +++ b/core/config/toml/types_test.go @@ -27,6 +27,12 @@ func TestMercurySecrets_valid(t *testing.T) { Username: models.NewSecret("new user1"), Password: models.NewSecret("new password2"), }, + "cred3": { + LegacyURL: models.MustSecretURL("https://abc.com"), + URL: models.MustSecretURL("HTTPS://GOOGLE1.COM"), + Username: models.NewSecret("new user1"), + Password: models.NewSecret("new password2"), + }, }, } diff --git a/core/gethwrappers/functions/generated/functions_client_example/functions_client_example.go b/core/gethwrappers/functions/generated/functions_client_example/functions_client_example.go index 6dc02520146..6ae90b45edb 100644 --- a/core/gethwrappers/functions/generated/functions_client_example/functions_client_example.go +++ b/core/gethwrappers/functions/generated/functions_client_example/functions_client_example.go @@ -32,7 +32,7 @@ var ( var FunctionsClientExampleMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyArgs\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptySecrets\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptySource\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoInlineSecrets\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyRouterCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"UnexpectedRequestID\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RequestFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RequestSent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_CALLBACK_GAS\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"}],\"name\":\"handleOracleFulfillment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastError\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastErrorLength\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastRequestId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastResponse\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastResponseLength\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"source\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"encryptedSecretsReferences\",\"type\":\"bytes\"},{\"internalType\":\"string[]\",\"name\":\"args\",\"type\":\"string[]\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"jobId\",\"type\":\"bytes32\"}],\"name\":\"sendRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162001a7638038062001a76833981016040819052620000349162000180565b6001600160a01b0381166080523380600081620000985760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000cb57620000cb81620000d5565b50505050620001b2565b336001600160a01b038216036200012f5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200008f565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019357600080fd5b81516001600160a01b0381168114620001ab57600080fd5b9392505050565b6080516118a1620001d5600039600081816101c60152610a2a01526118a16000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80636d9809a011610081578063b1e217491161005b578063b1e2174914610182578063f2fde38b1461018b578063f7b4c06f1461019e57600080fd5b80636d9809a01461014857806379ba5097146101525780638da5cb5b1461015a57600080fd5b806342748b2a116100b257806342748b2a146100ff5780634b0795a81461012c5780635fa353e71461013557600080fd5b80630ca76175146100ce5780633944ea3a146100e3575b600080fd5b6100e16100dc3660046112ed565b6101ae565b005b6100ec60035481565b6040519081526020015b60405180910390f35b60055461011790640100000000900463ffffffff1681565b60405163ffffffff90911681526020016100f6565b6100ec60045481565b6100e16101433660046113c0565b61022d565b6101176201117081565b6100e1610347565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f6565b6100ec60025481565b6100e16101993660046114a4565b610449565b6005546101179063ffffffff1681565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461021d576040517fc6829f8300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61022883838361045d565b505050565b61023561052b565b61027e6040805161010081019091528060008152602001600081526020016000815260200160608152602001606081526020016060815260200160608152602001606081525090565b6102c089898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525085939250506105ae9050565b85156103085761030887878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525085939250506105bf9050565b83156103225761032261031b85876114da565b8290610609565b61033961032e8261064c565b846201117085610a25565b600255505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61045161052b565b61045a81610b04565b50565b826002541461049b576040517fd068bf5b000000000000000000000000000000000000000000000000000000008152600481018490526024016103c4565b6104a482610bf9565b6003558151600580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff9092169190911790556104e681610bf9565b600455516005805463ffffffff909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff9092169190911790555050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146105ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103c4565b565b6105bb8260008084610c7b565b5050565b80516000036105fa576040517fe889636f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016020830152608090910152565b8051600003610644576040517ffe936cb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60c090910152565b6060600061065b610100610d12565b90506106a56040518060400160405280600c81526020017f636f64654c6f636174696f6e000000000000000000000000000000000000000081525082610d3390919063ffffffff16565b82516106c39060028111156106bc576106bc611572565b8290610d4c565b60408051808201909152600881527f6c616e67756167650000000000000000000000000000000000000000000000006020820152610702908290610d33565b60408301516107199080156106bc576106bc611572565b60408051808201909152600681527f736f7572636500000000000000000000000000000000000000000000000000006020820152610758908290610d33565b6060830151610768908290610d33565b60a083015151156107c25760408051808201909152601081527f726571756573745369676e61747572650000000000000000000000000000000060208201526107b2908290610d33565b60a08301516107c2908290610d81565b60c0830151511561086f5760408051808201909152600481527f6172677300000000000000000000000000000000000000000000000000000000602082015261080c908290610d33565b61081581610d8e565b60005b8360c0015151811015610865576108558460c00151828151811061083e5761083e6115a1565b602002602001015183610d3390919063ffffffff16565b61085e816115ff565b9050610818565b5061086f81610db2565b608083015151156109705760008360200151600281111561089257610892611572565b036108c9576040517fa80d31f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201909152600f81527f736563726574734c6f636174696f6e00000000000000000000000000000000006020820152610908908290610d33565b610921836020015160028111156106bc576106bc611572565b60408051808201909152600781527f73656372657473000000000000000000000000000000000000000000000000006020820152610960908290610d33565b6080830151610970908290610d81565b60e08301515115610a1d5760408051808201909152600981527f627974657341726773000000000000000000000000000000000000000000000060208201526109ba908290610d33565b6109c381610d8e565b60005b8360e0015151811015610a1357610a038460e0015182815181106109ec576109ec6115a1565b602002602001015183610d8190919063ffffffff16565b610a0c816115ff565b90506109c6565b50610a1d81610db2565b515192915050565b6000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663461d27628688600188886040518663ffffffff1660e01b8152600401610a8a959493929190611637565b6020604051808303816000875af1158015610aa9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610acd91906116d7565b60405190915081907f1131472297a800fee664d1d89cfa8f7676ff07189ecc53f80bbb5f4969099db890600090a295945050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603610b83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103c4565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008060209050602083511015610c0e575081515b60005b81811015610c7457610c248160086116f0565b848281518110610c3657610c366115a1565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016901c9290921791610c6d816115ff565b9050610c11565b5050919050565b8051600003610cb6576040517f22ce3edd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83836002811115610cc957610cc9611572565b90816002811115610cdc57610cdc611572565b90525060408401828015610cf257610cf2611572565b90818015610d0257610d02611572565b9052506060909301929092525050565b610d1a6111a4565b8051610d269083610dd0565b5060006020820152919050565b610d408260038351610e4a565b81516102289082610f71565b8151610d599060c2610f99565b506105bb8282604051602001610d7191815260200190565b6040516020818303038152906040525b610d408260028351610e4a565b610d99816004611002565b600181602001818151610dac9190611707565b90525050565b610dbd816007611002565b600181602001818151610dac919061171a565b604080518082019091526060815260006020820152610df060208361172d565b15610e1857610e0060208361172d565b610e0b90602061171a565b610e159083611707565b91505b602080840183905260405180855260008152908184010181811015610e3c57600080fd5b604052508290505b92915050565b60178167ffffffffffffffff1611610e77578251610e719060e0600585901b168317610f99565b50505050565b60ff8167ffffffffffffffff1611610eb9578251610ea0906018611fe0600586901b1617610f99565b508251610e719067ffffffffffffffff83166001611019565b61ffff8167ffffffffffffffff1611610efc578251610ee3906019611fe0600586901b1617610f99565b508251610e719067ffffffffffffffff83166002611019565b63ffffffff8167ffffffffffffffff1611610f41578251610f2890601a611fe0600586901b1617610f99565b508251610e719067ffffffffffffffff83166004611019565b8251610f5890601b611fe0600586901b1617610f99565b508251610e719067ffffffffffffffff83166008611019565b604080518082019091526060815260006020820152610f928383845161109e565b9392505050565b6040805180820190915260608152600060208201528251516000610fbe826001611707565b905084602001518210610fdf57610fdf85610fda8360026116f0565b61118d565b8451602083820101858153508051821115610ff8578181525b5093949350505050565b815161022890601f611fe0600585901b1617610f99565b604080518082019091526060815260006020820152835151600061103d8285611707565b9050856020015181111561105a5761105a86610fda8360026116f0565b6000600161106a86610100611888565b611074919061171a565b90508651828101878319825116178152508051831115611092578281525b50959695505050505050565b60408051808201909152606081526000602082015282518211156110c157600080fd5b83515160006110d08483611707565b905085602001518111156110ed576110ed86610fda8360026116f0565b855180518382016020019160009180851115611107578482525b505050602086015b602086106111475780518252611126602083611707565b9150611133602082611707565b905061114060208761171a565b955061110f565b5181517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60208890036101000a0190811690199190911617905250849150509392505050565b81516111998383610dd0565b50610e718382610f71565b60405180604001604052806111cc604051806040016040528060608152602001600081525090565b8152602001600081525090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561124f5761124f6111d9565b604052919050565b600067ffffffffffffffff831115611271576112716111d9565b6112a260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011601611208565b90508281528383830111156112b657600080fd5b828260208301376000602084830101529392505050565b600082601f8301126112de57600080fd5b610f9283833560208501611257565b60008060006060848603121561130257600080fd5b83359250602084013567ffffffffffffffff8082111561132157600080fd5b61132d878388016112cd565b9350604086013591508082111561134357600080fd5b50611350868287016112cd565b9150509250925092565b60008083601f84011261136c57600080fd5b50813567ffffffffffffffff81111561138457600080fd5b60208301915083602082850101111561139c57600080fd5b9250929050565b803567ffffffffffffffff811681146113bb57600080fd5b919050565b60008060008060008060008060a0898b0312156113dc57600080fd5b883567ffffffffffffffff808211156113f457600080fd5b6114008c838d0161135a565b909a50985060208b013591508082111561141957600080fd5b6114258c838d0161135a565b909850965060408b013591508082111561143e57600080fd5b818b0191508b601f83011261145257600080fd5b81358181111561146157600080fd5b8c60208260051b850101111561147657600080fd5b60208301965080955050505061148e60608a016113a3565b9150608089013590509295985092959890939650565b6000602082840312156114b657600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610f9257600080fd5b600067ffffffffffffffff808411156114f5576114f56111d9565b8360051b6020611506818301611208565b86815291850191818101903684111561151e57600080fd5b865b84811015611566578035868111156115385760008081fd5b880136601f82011261154a5760008081fd5b611558368235878401611257565b845250918301918301611520565b50979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611630576116306115d0565b5060010190565b67ffffffffffffffff861681526000602060a08184015286518060a085015260005b818110156116755788810183015185820160c001528201611659565b50600060c0828601015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116850101925050506116be604083018661ffff169052565b63ffffffff939093166060820152608001529392505050565b6000602082840312156116e957600080fd5b5051919050565b8082028115828204841417610e4457610e446115d0565b80820180821115610e4457610e446115d0565b81810381811115610e4457610e446115d0565b600082611763577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b600181815b808511156117c157817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156117a7576117a76115d0565b808516156117b457918102915b93841c939080029061176d565b509250929050565b6000826117d857506001610e44565b816117e557506000610e44565b81600181146117fb576002811461180557611821565b6001915050610e44565b60ff841115611816576118166115d0565b50506001821b610e44565b5060208310610133831016604e8410600b8410161715611844575081810a610e44565b61184e8383611768565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115611880576118806115d0565b029392505050565b6000610f9283836117c956fea164736f6c6343000813000a", + Bin: "0x60a06040523480156200001157600080fd5b5060405162001a4838038062001a48833981016040819052620000349162000180565b6001600160a01b0381166080523380600081620000985760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000cb57620000cb81620000d5565b50505050620001b2565b336001600160a01b038216036200012f5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200008f565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019357600080fd5b81516001600160a01b0381168114620001ab57600080fd5b9392505050565b608051611873620001d5600039600081816101c601526109f301526118736000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80636d9809a011610081578063b1e217491161005b578063b1e2174914610182578063f2fde38b1461018b578063f7b4c06f1461019e57600080fd5b80636d9809a01461014857806379ba5097146101525780638da5cb5b1461015a57600080fd5b806342748b2a116100b257806342748b2a146100ff5780634b0795a81461012c5780635fa353e71461013557600080fd5b80630ca76175146100ce5780633944ea3a146100e3575b600080fd5b6100e16100dc3660046112bf565b6101ae565b005b6100ec60035481565b6040519081526020015b60405180910390f35b60055461011790640100000000900463ffffffff1681565b60405163ffffffff90911681526020016100f6565b6100ec60045481565b6100e1610143366004611392565b610258565b6101176201117081565b6100e161036a565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f6565b6100ec60025481565b6100e1610199366004611476565b61046c565b6005546101179063ffffffff1681565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461021d576040517fc6829f8300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610228838383610480565b60405183907f85e1543bf2f84fe80c6badbce3648c8539ad1df4d2b3d822938ca0538be727e690600090a2505050565b61026061054e565b6102a16040805160e0810190915280600081526020016000815260200160008152602001606081526020016060815260200160608152602001606081525090565b6102e389898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525085939250506105d19050565b851561032b5761032b87878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525085939250506105e29050565b83156103455761034561033e85876114ac565b829061062c565b61035c6103518261066f565b8462011170856109ee565b600255505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61047461054e565b61047d81610acd565b50565b82600254146104be576040517fd068bf5b000000000000000000000000000000000000000000000000000000008152600481018490526024016103e7565b6104c782610bc2565b6003558151600580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff90921691909117905561050981610bc2565b600455516005805463ffffffff909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff9092169190911790555050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146105cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103e7565b565b6105de8260008084610c44565b5050565b805160000361061d576040517fe889636f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016020830152608090910152565b8051600003610667576040517ffe936cb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a090910152565b6060600061067e610100610cdb565b90506106c86040518060400160405280600c81526020017f636f64654c6f636174696f6e000000000000000000000000000000000000000081525082610cfc90919063ffffffff16565b82516106e69060028111156106df576106df611544565b8290610d1a565b60408051808201909152600881527f6c616e67756167650000000000000000000000000000000000000000000000006020820152610725908290610cfc565b604083015161073c9080156106df576106df611544565b60408051808201909152600681527f736f757263650000000000000000000000000000000000000000000000000000602082015261077b908290610cfc565b606083015161078b908290610cfc565b60a083015151156108385760408051808201909152600481527f617267730000000000000000000000000000000000000000000000000000000060208201526107d5908290610cfc565b6107de81610d53565b60005b8360a001515181101561082e5761081e8460a00151828151811061080757610807611573565b602002602001015183610cfc90919063ffffffff16565b610827816115d1565b90506107e1565b5061083881610d77565b608083015151156109395760008360200151600281111561085b5761085b611544565b03610892576040517fa80d31f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201909152600f81527f736563726574734c6f636174696f6e000000000000000000000000000000000060208201526108d1908290610cfc565b6108ea836020015160028111156106df576106df611544565b60408051808201909152600781527f73656372657473000000000000000000000000000000000000000000000000006020820152610929908290610cfc565b6080830151610939908290610d95565b60c083015151156109e65760408051808201909152600981527f62797465734172677300000000000000000000000000000000000000000000006020820152610983908290610cfc565b61098c81610d53565b60005b8360c00151518110156109dc576109cc8460c0015182815181106109b5576109b5611573565b602002602001015183610d9590919063ffffffff16565b6109d5816115d1565b905061098f565b506109e681610d77565b515192915050565b6000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663461d27628688600188886040518663ffffffff1660e01b8152600401610a53959493929190611609565b6020604051808303816000875af1158015610a72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9691906116a9565b60405190915081907f1131472297a800fee664d1d89cfa8f7676ff07189ecc53f80bbb5f4969099db890600090a295945050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603610b4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103e7565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008060209050602083511015610bd7575081515b60005b81811015610c3d57610bed8160086116c2565b848281518110610bff57610bff611573565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016901c9290921791610c36816115d1565b9050610bda565b5050919050565b8051600003610c7f576040517f22ce3edd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83836002811115610c9257610c92611544565b90816002811115610ca557610ca5611544565b90525060408401828015610cbb57610cbb611544565b90818015610ccb57610ccb611544565b9052506060909301929092525050565b610ce3611176565b8051610cef9083610da2565b5060006020820152919050565b610d098260038351610e1c565b8151610d159082610f43565b505050565b8151610d279060c2610f6b565b506105de8282604051602001610d3f91815260200190565b604051602081830303815290604052610d95565b610d5e816004610fd4565b600181602001818151610d7191906116d9565b90525050565b610d82816007610fd4565b600181602001818151610d7191906116ec565b610d098260028351610e1c565b604080518082019091526060815260006020820152610dc26020836116ff565b15610dea57610dd26020836116ff565b610ddd9060206116ec565b610de790836116d9565b91505b602080840183905260405180855260008152908184010181811015610e0e57600080fd5b604052508290505b92915050565b60178167ffffffffffffffff1611610e49578251610e439060e0600585901b168317610f6b565b50505050565b60ff8167ffffffffffffffff1611610e8b578251610e72906018611fe0600586901b1617610f6b565b508251610e439067ffffffffffffffff83166001610feb565b61ffff8167ffffffffffffffff1611610ece578251610eb5906019611fe0600586901b1617610f6b565b508251610e439067ffffffffffffffff83166002610feb565b63ffffffff8167ffffffffffffffff1611610f13578251610efa90601a611fe0600586901b1617610f6b565b508251610e439067ffffffffffffffff83166004610feb565b8251610f2a90601b611fe0600586901b1617610f6b565b508251610e439067ffffffffffffffff83166008610feb565b604080518082019091526060815260006020820152610f6483838451611070565b9392505050565b6040805180820190915260608152600060208201528251516000610f908260016116d9565b905084602001518210610fb157610fb185610fac8360026116c2565b61115f565b8451602083820101858153508051821115610fca578181525b5093949350505050565b8151610d1590601f611fe0600585901b1617610f6b565b604080518082019091526060815260006020820152835151600061100f82856116d9565b9050856020015181111561102c5761102c86610fac8360026116c2565b6000600161103c8661010061185a565b61104691906116ec565b90508651828101878319825116178152508051831115611064578281525b50959695505050505050565b604080518082019091526060815260006020820152825182111561109357600080fd5b83515160006110a284836116d9565b905085602001518111156110bf576110bf86610fac8360026116c2565b8551805183820160200191600091808511156110d9578482525b505050602086015b6020861061111957805182526110f86020836116d9565b91506111056020826116d9565b90506111126020876116ec565b95506110e1565b5181517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60208890036101000a0190811690199190911617905250849150509392505050565b815161116b8383610da2565b50610e438382610f43565b604051806040016040528061119e604051806040016040528060608152602001600081525090565b8152602001600081525090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611221576112216111ab565b604052919050565b600067ffffffffffffffff831115611243576112436111ab565b61127460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116016111da565b905082815283838301111561128857600080fd5b828260208301376000602084830101529392505050565b600082601f8301126112b057600080fd5b610f6483833560208501611229565b6000806000606084860312156112d457600080fd5b83359250602084013567ffffffffffffffff808211156112f357600080fd5b6112ff8783880161129f565b9350604086013591508082111561131557600080fd5b506113228682870161129f565b9150509250925092565b60008083601f84011261133e57600080fd5b50813567ffffffffffffffff81111561135657600080fd5b60208301915083602082850101111561136e57600080fd5b9250929050565b803567ffffffffffffffff8116811461138d57600080fd5b919050565b60008060008060008060008060a0898b0312156113ae57600080fd5b883567ffffffffffffffff808211156113c657600080fd5b6113d28c838d0161132c565b909a50985060208b01359150808211156113eb57600080fd5b6113f78c838d0161132c565b909850965060408b013591508082111561141057600080fd5b818b0191508b601f83011261142457600080fd5b81358181111561143357600080fd5b8c60208260051b850101111561144857600080fd5b60208301965080955050505061146060608a01611375565b9150608089013590509295985092959890939650565b60006020828403121561148857600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610f6457600080fd5b600067ffffffffffffffff808411156114c7576114c76111ab565b8360051b60206114d88183016111da565b8681529185019181810190368411156114f057600080fd5b865b848110156115385780358681111561150a5760008081fd5b880136601f82011261151c5760008081fd5b61152a368235878401611229565b8452509183019183016114f2565b50979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611602576116026115a2565b5060010190565b67ffffffffffffffff861681526000602060a08184015286518060a085015260005b818110156116475788810183015185820160c00152820161162b565b50600060c0828601015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010192505050611690604083018661ffff169052565b63ffffffff939093166060820152608001529392505050565b6000602082840312156116bb57600080fd5b5051919050565b8082028115828204841417610e1657610e166115a2565b80820180821115610e1657610e166115a2565b81810381811115610e1657610e166115a2565b600082611735577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b600181815b8085111561179357817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115611779576117796115a2565b8085161561178657918102915b93841c939080029061173f565b509250929050565b6000826117aa57506001610e16565b816117b757506000610e16565b81600181146117cd57600281146117d7576117f3565b6001915050610e16565b60ff8411156117e8576117e86115a2565b50506001821b610e16565b5060208310610133831016604e8410600b8410161715611816575081810a610e16565b611820838361173a565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115611852576118526115a2565b029392505050565b6000610f64838361179b56fea164736f6c6343000813000a", } var FunctionsClientExampleABI = FunctionsClientExampleMetaData.ABI diff --git a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go index e1f6b2f7c15..94f1efd2d6a 100644 --- a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go +++ b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go @@ -31,14 +31,13 @@ var ( ) type FunctionsBillingConfig struct { - MaxCallbackGasLimit uint32 + FulfillmentGasPriceOverEstimationBP uint32 FeedStalenessSeconds uint32 GasOverheadBeforeCallback uint32 GasOverheadAfterCallback uint32 RequestTimeoutSeconds uint32 DonFee *big.Int MaxSupportedRequestDataVersion uint16 - FulfillmentGasPriceOverEstimationBP uint32 FallbackNativePerUnitLink *big.Int } @@ -71,8 +70,8 @@ type FunctionsResponseRequestMeta struct { } var FunctionsCoordinatorMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxCallbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"linkToNativeFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPublicKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InconsistentReportData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoTransmittersSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouterOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReportInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustBeSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedPublicKeyChange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedRequestDataVersion\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CommitmentDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxCallbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"indexed\":false,\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"callbackGasLimit\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"OracleResponse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"deleteCommitment\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"gasPriceGwei\",\"type\":\"uint256\"}],\"name\":\"estimateCost\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxCallbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"getDONFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDONPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getThresholdPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracleWithdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"_f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"_offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"donPublicKey\",\"type\":\"bytes\"}],\"name\":\"setDONPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"thresholdPublicKey\",\"type\":\"bytes\"}],\"name\":\"setThresholdPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"availableBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"}],\"internalType\":\"structFunctionsResponse.RequestMeta\",\"name\":\"request\",\"type\":\"tuple\"}],\"name\":\"startRequest\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"transmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxCallbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60c06040523480156200001157600080fd5b50604051620051b4380380620051b483398101604081905262000034916200044f565b8282828260013380600081620000915760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c457620000c48162000140565b50505015156080526001600160a01b038116620000f457604051632530e88560e11b815260040160405180910390fd5b6001600160a01b0390811660a052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200013482620001eb565b50505050505062000600565b336001600160a01b038216036200019a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000088565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001f56200033a565b80516008805460208401516040808601516060870151608088015160a089015160c08a015163ffffffff998a166001600160401b031990981697909717640100000000968a16870217600160401b600160801b03191668010000000000000000948a169490940263ffffffff60601b1916939093176c010000000000000000000000009289169290920291909117600160801b600160e81b031916600160801b91881691909102600160a01b600160e81b03191617600160a01b6001600160481b03909216919091021761ffff60e81b1916600160e81b61ffff909416939093029290921790925560e084015161010085015193166001600160e01b0390931690910291909117600955517f5b6e2e1a03ea742ce04ca36d0175411a0772f99ef4ee84aeb9868a1ef6ddc82c906200032f90839062000558565b60405180910390a150565b6200034462000346565b565b6000546001600160a01b03163314620003445760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000088565b80516001600160a01b0381168114620003ba57600080fd5b919050565b60405161012081016001600160401b0381118282101715620003f157634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff81168114620003ba57600080fd5b80516001600160481b0381168114620003ba57600080fd5b805161ffff81168114620003ba57600080fd5b80516001600160e01b0381168114620003ba57600080fd5b60008060008385036101608112156200046757600080fd5b6200047285620003a2565b935061012080601f19830112156200048957600080fd5b62000493620003bf565b9150620004a360208701620003f7565b8252620004b360408701620003f7565b6020830152620004c660608701620003f7565b6040830152620004d960808701620003f7565b6060830152620004ec60a08701620003f7565b6080830152620004ff60c087016200040c565b60a08301526200051260e0870162000424565b60c083015261010062000527818801620003f7565b60e08401526200053982880162000437565b908301525091506200054f6101408501620003a2565b90509250925092565b815163ffffffff9081168252602080840151821690830152604080840151821690830152606080840151821690830152608080840151918216908301526101208201905060a0830151620005b760a08401826001600160481b03169052565b5060c0830151620005ce60c084018261ffff169052565b5060e0830151620005e760e084018263ffffffff169052565b50610100928301516001600160e01b0316919092015290565b60805160a051614b6462000650600039600081816108060152818161099401528181610c7d01528181610f130152818161104a01528181611834015261329b015260006112720152614b646000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806381ff7048116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e7121461054e578063e4ddcea614610561578063f2fde38b1461057757600080fd5b8063c3f909d4146103c4578063d227d24514610516578063d328a91e1461054657600080fd5b8063a631571e116100bd578063a631571e14610371578063afcb95d714610391578063b1dc65a4146103b157600080fd5b806381ff7048146102b957806385b214cf146103265780638da5cb5b1461034957600080fd5b806366316d8d116101455780637f15e1661161011f5780637f15e16614610289578063814118341461029c57806381f1b938146102b157600080fd5b806366316d8d1461026657806379ba5097146102795780637d4807871461028157600080fd5b80631bdf7f1b116101765780631bdf7f1b146101f95780632a905ccc1461020c57806359b5b7ac1461022e57600080fd5b8063083a546614610192578063181f5a77146101a7575b600080fd5b6101a56101a036600461358e565b61058a565b005b6101e36040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e302e300000000081525081565b6040516101f09190613634565b60405180910390f35b6101a5610207366004613797565b6105df565b610214610802565b60405168ffffffffffffffffff90911681526020016101f0565b61021461023c3660046138db565b5060085474010000000000000000000000000000000000000000900468ffffffffffffffffff1690565b6101a561027436600461396a565b610898565b6101a5610a51565b6101a5610b53565b6101a561029736600461358e565b610d69565b6102a4610db9565b6040516101f091906139f4565b6101e3610e28565b61030360015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff9485168152939092166020840152908201526060016101f0565b610339610334366004613a07565b610ef9565b60405190151581526020016101f0565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101f0565b61038461037f366004613a20565b610fd9565b6040516101f09190613b75565b6040805160018152600060208201819052918101919091526060016101f0565b6101a56103bf366004613bc9565b611179565b6105096040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250604080516101208101825260085463ffffffff8082168352640100000000808304821660208501526801000000000000000083048216948401949094526c0100000000000000000000000082048116606084015270010000000000000000000000000000000082048116608084015274010000000000000000000000000000000000000000820468ffffffffffffffffff1660a08401527d01000000000000000000000000000000000000000000000000000000000090910461ffff1660c083015260095490811660e0830152919091047bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1661010082015290565b6040516101f09190613c80565b610529610524366004613d63565b611830565b6040516bffffffffffffffffffffffff90911681526020016101f0565b6101e361198f565b6101a561055c366004613e7c565b6119e6565b610569612412565b6040519081526020016101f0565b6101a5610585366004613f49565b612643565b610592612657565b60008190036105cd576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105da828483613fff565b505050565b6105e76126da565b80516008805460208401516040808601516060870151608088015160a089015160c08a015163ffffffff998a167fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090981697909717640100000000968a168702177fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff1668010000000000000000948a16949094027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff16939093176c0100000000000000000000000092891692909202919091177fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff16700100000000000000000000000000000000918816919091027fffffff000000000000000000ffffffffffffffffffffffffffffffffffffffff16177401000000000000000000000000000000000000000068ffffffffffffffffff90921691909102177fff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d01000000000000000000000000000000000000000000000000000000000061ffff909416939093029290921790925560e084015161010085015193167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90931690910291909117600955517f5b6e2e1a03ea742ce04ca36d0175411a0772f99ef4ee84aeb9868a1ef6ddc82c906107f7908390613c80565b60405180910390a150565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561086f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108939190614125565b905090565b6108a06126e2565b806bffffffffffffffffffffffff166000036108da5750336000908152600a60205260409020546bffffffffffffffffffffffff16610934565b336000908152600a60205260409020546bffffffffffffffffffffffff80831691161015610934576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906109619084906bffffffffffffffffffffffff16614171565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506109b67f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b158015610a3557600080fd5b505af1158015610a49573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610ad7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b5b6126da565b610b636126e2565b6000610b6d610db9565b905060005b8151811015610d65576000600a6000848481518110610b9357610b93614196565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a90046bffffffffffffffffffffffff1690506000600a6000858581518110610c0857610c08614196565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610c9f7f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610ccc57610ccc614196565b6020026020010151836040518363ffffffff1660e01b8152600401610d2192919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d3b57600080fd5b505af1158015610d4f573d6000803e3d6000fd5b505050505080610d5e906141c5565b9050610b72565b5050565b610d71612657565b6000819003610dac576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105da828483613fff565b60606006805480602002602001604051908101604052809291908181526020018280548015610e1e57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610df3575b5050505050905090565b6060600d8054610e3790613f66565b9050600003610e72576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610e7f90613f66565b80601f0160208091040260200160405190810160405280929190818152602001828054610eab90613f66565b8015610e1e5780601f10610ecd57610100808354040283529160200191610e1e565b820191906000526020600020905b815481529060010190602001808311610edb57509395945050505050565b60003373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f6a576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260076020526040902054610f8557506000919050565b60008281526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f41690610fc89084815260200190565b60405180910390a15060015b919050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146110a1576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110b26110ad836141fd565b61288d565b90506110c46060830160408401613f49565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff3261111260c0870160a088016142ea565b61112461016088016101408901613f49565b61112e8880614307565b6111406101208b016101008c0161436c565b60208b01356111566101008d0160e08e01614387565b8b60405161116c999897969594939291906143a4565b60405180910390a3919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16040805160608101825260025480825260035460ff80821660208501526101009091041692820192909252908314611260576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f6e666967446967657374206d69736d6174636800000000000000000000006044820152606401610ace565b61126e8b8b8b8b8b8b612c9d565b60007f0000000000000000000000000000000000000000000000000000000000000000156112cb576002826020015183604001516112ac919061444c565b6112b69190614494565b6112c190600161444c565b60ff1690506112e1565b60208201516112db90600161444c565b60ff1690505b88811461134a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610ace565b8887146113b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f7369676e617475726573206f7574206f6620726567697374726174696f6e00006044820152606401610ace565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113f6576113f66144b6565b6002811115611407576114076144b6565b9052509050600281602001516002811115611424576114246144b6565b14801561146b57506006816000015160ff168154811061144657611446614196565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b6114d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610ace565b50505050506114de613526565b6000808a8a6040516114f19291906144e5565b604051908190038120611508918e906020016144f5565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b8981101561181257600060018489846020811061157157611571614196565b61157e91901a601b61444c565b8e8e8681811061159057611590614196565b905060200201358d8d878181106115a9576115a9614196565b90506020020135604051600081526020016040526040516115e6949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611608573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff80821685529296509294508401916101009004166002811115611688576116886144b6565b6002811115611699576116996144b6565b90525092506001836020015160028111156116b6576116b66144b6565b1461171d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610ace565b8251600090879060ff16601f811061173757611737614196565b602002015173ffffffffffffffffffffffffffffffffffffffff16146117b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610ace565b8086846000015160ff16601f81106117d3576117d3614196565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117fe60018661444c565b9450508061180b906141c5565b9050611552565b505050611823833383858e8e612d54565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b1580156118d057600080fd5b505afa1580156118e4573d6000803e3d6000fd5b505050620f42408311159050611926576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611930610802565b9050600061197387878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061023c92505050565b905061198185858385612f22565b925050505b95945050505050565b6060600c805461199e90613f66565b90506000036119d9576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610e7f90613f66565b855185518560ff16601f831115611a59576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610ace565b80600003611ac3576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610ace565b818314611b51576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610ace565b611b5c816003614509565b8311611bc4576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610ace565b611bcc612657565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611c13908861300c565b60055415611dc857600554600090611c2d90600190614520565b9050600060058281548110611c4457611c44614196565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611c7e57611c7e614196565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611cfe57611cfe614533565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611d6757611d67614533565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611c13915050565b60005b81515181101561222f5760006004600084600001518481518110611df157611df1614196565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611e3b57611e3b6144b6565b14611ea2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610ace565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611ed357611ed3614196565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115611f7457611f746144b6565b021790555060009150611f849050565b6004600084602001518481518110611f9e57611f9e614196565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611fe857611fe86144b6565b1461204f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610ace565b6040805180820190915260ff82168152602081016002815250600460008460200151848151811061208257612082614196565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115612123576121236144b6565b02179055505082518051600592508390811061214157612141614196565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90931692909217909155820151805160069190839081106121bd576121bd614196565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905580612227816141c5565b915050611dcb565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff43811682029290921780855592048116929182916014916122e791849174010000000000000000000000000000000000000000900416614562565b92506101000a81548163ffffffff021916908363ffffffff1602179055506123464630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a00151613025565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986123fd988b9891977401000000000000000000000000000000000000000090920463ffffffff1696909591949193919261457f565b60405180910390a15050505050505050505050565b604080516101208101825260085463ffffffff8082168352640100000000808304821660208501526801000000000000000083048216848601526c010000000000000000000000008084048316606086015270010000000000000000000000000000000084048316608086015274010000000000000000000000000000000000000000840468ffffffffffffffffff1660a0808701919091527d01000000000000000000000000000000000000000000000000000000000090940461ffff1660c086015260095492831660e086015291047bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16610100840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa158015612577573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061259b919061462f565b5093505092505080426125ae9190614520565b836020015163ffffffff161080156125d057506000836020015163ffffffff16115b156125ff57505061010001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b6000821361263c576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610ace565b5092915050565b61264b612657565b612654816130d0565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146126d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610ace565b565b6126d8612657565b600b546bffffffffffffffffffffffff166000036126fc57565b6000612706610db9565b90508051600003612743576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600b54600091612762916bffffffffffffffffffffffff1661467f565b905060005b825181101561282e5781600a600085848151811061278757612787614196565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff166127ef91906146aa565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080612827906141c5565b9050612767565b50815161283b90826146cf565b600b805460009061285b9084906bffffffffffffffffffffffff16614171565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152604080516101208101825260085463ffffffff8082168352640100000000808304821660208501526801000000000000000083048216948401949094526c0100000000000000000000000082048116606084015270010000000000000000000000000000000082048116608084015274010000000000000000000000000000000000000000820468ffffffffffffffffff1660a08401527d01000000000000000000000000000000000000000000000000000000000090910461ffff90811660c0840181905260095492831660e0850152939091047bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1661010080840191909152850151919291161115612a22576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60085460009074010000000000000000000000000000000000000000900468ffffffffffffffffff1690506000612a638560e001513a848860800151612f22565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612abf576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612b423087604001518860a001518960c001516001612ae091906146f7565b6040805173ffffffffffffffffffffffffffffffffffffffff958616602080830191909152949095168582015267ffffffffffffffff928316606086015291166080808501919091528151808503909101815260a09093019052815191012090565b90506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001836bffffffffffffffffffffffff168152602001876040015173ffffffffffffffffffffffffffffffffffffffff1681526020018760a0015167ffffffffffffffff1681526020018760e0015163ffffffff168152602001876080015168ffffffffffffffffff1681526020018468ffffffffffffffffff168152602001856040015163ffffffff1664ffffffffff168152602001856060015163ffffffff1664ffffffffff168152602001856080015163ffffffff1642612c349190614718565b63ffffffff16815250945084604051602001612c509190613b75565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181528151602092830120600093845260079092529091205550919392505050565b6000612caa826020614509565b612cb5856020614509565b612cc188610144614718565b612ccb9190614718565b612cd59190614718565b612ce0906000614718565b9050368114612d4b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610ace565b50505050505050565b606080808080612d6686880188614806565b8451949950929750909550935091501580612d8357508351855114155b80612d9057508251855114155b80612d9d57508151855114155b80612daa57508051855114155b15612de1576040517f0be3632800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8551811015612f14576000612e79878381518110612e0457612e04614196565b6020026020010151878481518110612e1e57612e1e614196565b6020026020010151878581518110612e3857612e38614196565b6020026020010151878681518110612e5257612e52614196565b6020026020010151878781518110612e6c57612e6c614196565b60200260200101516131c5565b90506000816006811115612e8f57612e8f6144b6565b1480612eac57506001816006811115612eaa57612eaa6144b6565b145b15612f0357868281518110612ec357612ec3614196565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b50612f0d816141c5565b9050612de4565b505050505050505050505050565b60085460009081908690612f5a9063ffffffff6c01000000000000000000000000820481169168010000000000000000900416614562565b612f649190614562565b60095463ffffffff918216925060009161271091612f83911688614509565b612f8d91906148d8565b612f979087614718565b90506000612fa482613455565b90506000612fc0846bffffffffffffffffffffffff8416614509565b90506000612fdc68ffffffffffffffffff808916908a166146aa565b9050612ffe612ff96bffffffffffffffffffffffff831684614718565b613484565b9a9950505050505050505050565b6000613016610db9565b511115610d6557610d656126e2565b6000808a8a8a8a8a8a8a8a8a604051602001613049999897969594939291906148ec565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff82160361314f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610ace565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080838060200190518101906131dc91906149c2565b9050806040516020016131ef9190613b75565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060008a8152600790935291205414613241576006915050611986565b60008781526007602052604090205461325e576002915050611986565b60006132693a613455565b905060008261012001518361010001516132839190614a8a565b6132949064ffffffffff16836146cf565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298b8b878960e0015168ffffffffffffffffff16886132f391906146aa565b338b6040518763ffffffff1660e01b815260040161331696959493929190614aa8565b60408051808303816000875af1158015613334573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133589190614b24565b90925090506000826006811115613371576133716144b6565b148061338e5750600182600681111561338c5761338c6144b6565b145b156134475760008b8152600760205260408120556133ac81846146aa565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0870151600b805468ffffffffffffffffff90921693909291613418918591166146aa565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b509998505050505050505050565b600061347e613462612412565b61347484670de0b6b3a7640000614509565b612ff991906148d8565b92915050565b60006bffffffffffffffffffffffff821115613522576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610ace565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f84011261355757600080fd5b50813567ffffffffffffffff81111561356f57600080fd5b60208301915083602082850101111561358757600080fd5b9250929050565b600080602083850312156135a157600080fd5b823567ffffffffffffffff8111156135b857600080fd5b6135c485828601613545565b90969095509350505050565b6000815180845260005b818110156135f6576020818501810151868301820152016135da565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061364760208301846135d0565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156136a1576136a161364e565b60405290565b604051610160810167ffffffffffffffff811182821017156136a1576136a161364e565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156137125761371261364e565b604052919050565b63ffffffff8116811461265457600080fd5b8035610fd48161371a565b68ffffffffffffffffff8116811461265457600080fd5b8035610fd481613737565b803561ffff81168114610fd457600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168114610fd457600080fd5b600061012082840312156137aa57600080fd5b6137b261367d565b6137bb8361372c565b81526137c96020840161372c565b60208201526137da6040840161372c565b60408201526137eb6060840161372c565b60608201526137fc6080840161372c565b608082015261380d60a0840161374e565b60a082015261381e60c08401613759565b60c082015261382f60e0840161372c565b60e082015261010061384281850161376b565b908201529392505050565b600082601f83011261385e57600080fd5b813567ffffffffffffffff8111156138785761387861364e565b6138a960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016136cb565b8181528460208386010111156138be57600080fd5b816020850160208301376000918101602001919091529392505050565b6000602082840312156138ed57600080fd5b813567ffffffffffffffff81111561390457600080fd5b6139108482850161384d565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461265457600080fd5b8035610fd481613918565b6bffffffffffffffffffffffff8116811461265457600080fd5b8035610fd481613945565b6000806040838503121561397d57600080fd5b823561398881613918565b9150602083013561399881613945565b809150509250929050565b600081518084526020808501945080840160005b838110156139e957815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016139b7565b509495945050505050565b60208152600061364760208301846139a3565b600060208284031215613a1957600080fd5b5035919050565b600060208284031215613a3257600080fd5b813567ffffffffffffffff811115613a4957600080fd5b8201610160818503121561364757600080fd5b805182526020810151613a87602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613aa760408401826bffffffffffffffffffffffff169052565b506060810151613acf606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613aeb608084018267ffffffffffffffff169052565b5060a0810151613b0360a084018263ffffffff169052565b5060c0810151613b2060c084018268ffffffffffffffffff169052565b5060e0810151613b3d60e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b610160810161347e8284613a5c565b60008083601f840112613b9657600080fd5b50813567ffffffffffffffff811115613bae57600080fd5b6020830191508360208260051b850101111561358757600080fd5b60008060008060008060008060e0898b031215613be557600080fd5b606089018a811115613bf657600080fd5b8998503567ffffffffffffffff80821115613c1057600080fd5b613c1c8c838d01613545565b909950975060808b0135915080821115613c3557600080fd5b613c418c838d01613b84565b909750955060a08b0135915080821115613c5a57600080fd5b50613c678b828c01613b84565b999c989b50969995989497949560c00135949350505050565b815163ffffffff9081168252602080840151821690830152604080840151821690830152606080840151821690830152608080840151918216908301526101208201905060a0830151613ce060a084018268ffffffffffffffffff169052565b5060c0830151613cf660c084018261ffff169052565b5060e0830151613d0e60e084018263ffffffff169052565b50610100838101517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116848301525b505092915050565b67ffffffffffffffff8116811461265457600080fd5b8035610fd481613d42565b600080600080600060808688031215613d7b57600080fd5b8535613d8681613d42565b9450602086013567ffffffffffffffff811115613da257600080fd5b613dae88828901613545565b9095509350506040860135613dc28161371a565b949793965091946060013592915050565b600067ffffffffffffffff821115613ded57613ded61364e565b5060051b60200190565b600082601f830112613e0857600080fd5b81356020613e1d613e1883613dd3565b6136cb565b82815260059290921b84018101918181019086841115613e3c57600080fd5b8286015b84811015613e60578035613e5381613918565b8352918301918301613e40565b509695505050505050565b803560ff81168114610fd457600080fd5b60008060008060008060c08789031215613e9557600080fd5b863567ffffffffffffffff80821115613ead57600080fd5b613eb98a838b01613df7565b97506020890135915080821115613ecf57600080fd5b613edb8a838b01613df7565b9650613ee960408a01613e6b565b95506060890135915080821115613eff57600080fd5b613f0b8a838b0161384d565b9450613f1960808a01613d58565b935060a0890135915080821115613f2f57600080fd5b50613f3c89828a0161384d565b9150509295509295509295565b600060208284031215613f5b57600080fd5b813561364781613918565b600181811c90821680613f7a57607f821691505b602082108103613fb3577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105da57600081815260208120601f850160051c81016020861015613fe05750805b601f850160051c820191505b81811015610a4957828155600101613fec565b67ffffffffffffffff8311156140175761401761364e565b61402b836140258354613f66565b83613fb9565b6000601f84116001811461407d57600085156140475750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614113565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156140cc57868501358255602094850194600190920191016140ac565b5086821015614107577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b8051610fd481613737565b60006020828403121561413757600080fd5b815161364781613737565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff82811682821603908082111561263c5761263c614142565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036141f6576141f6614142565b5060010190565b6000610160823603121561421057600080fd5b6142186136a7565b823567ffffffffffffffff81111561422f57600080fd5b61423b3682860161384d565b825250602083013560208201526142546040840161393a565b60408201526142656060840161395f565b60608201526142766080840161374e565b608082015261428760a08401613d58565b60a082015261429860c08401613d58565b60c08201526142a960e0840161372c565b60e08201526101006142bc818501613759565b908201526101206142ce848201613d58565b908201526101406142e084820161393a565b9082015292915050565b6000602082840312156142fc57600080fd5b813561364781613d42565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261433c57600080fd5b83018035915067ffffffffffffffff82111561435757600080fd5b60200191503681900382131561358757600080fd5b60006020828403121561437e57600080fd5b61364782613759565b60006020828403121561439957600080fd5b81356136478161371a565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168301019050612ffe60e0830184613a5c565b60ff818116838216019081111561347e5761347e614142565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff8316806144a7576144a7614465565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b808202811582820484141761347e5761347e614142565b8181038181111561347e5761347e614142565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff81811683821601908082111561263c5761263c614142565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526145af8184018a6139a3565b905082810360808401526145c381896139a3565b905060ff871660a084015282810360c08401526145e081876135d0565b905067ffffffffffffffff851660e084015282810361010084015261460581856135d0565b9c9b505050505050505050505050565b805169ffffffffffffffffffff81168114610fd457600080fd5b600080600080600060a0868803121561464757600080fd5b61465086614615565b945060208601519350604086015192506060860151915061467360808701614615565b90509295509295909350565b60006bffffffffffffffffffffffff8084168061469e5761469e614465565b92169190910492915050565b6bffffffffffffffffffffffff81811683821601908082111561263c5761263c614142565b6bffffffffffffffffffffffff818116838216028082169190828114613d3a57613d3a614142565b67ffffffffffffffff81811683821601908082111561263c5761263c614142565b8082018082111561347e5761347e614142565b600082601f83011261473c57600080fd5b8135602061474c613e1883613dd3565b82815260059290921b8401810191818101908684111561476b57600080fd5b8286015b84811015613e60578035835291830191830161476f565b600082601f83011261479757600080fd5b813560206147a7613e1883613dd3565b82815260059290921b840181019181810190868411156147c657600080fd5b8286015b84811015613e6057803567ffffffffffffffff8111156147ea5760008081fd5b6147f88986838b010161384d565b8452509183019183016147ca565b600080600080600060a0868803121561481e57600080fd5b853567ffffffffffffffff8082111561483657600080fd5b61484289838a0161472b565b9650602088013591508082111561485857600080fd5b61486489838a01614786565b9550604088013591508082111561487a57600080fd5b61488689838a01614786565b9450606088013591508082111561489c57600080fd5b6148a889838a01614786565b935060808801359150808211156148be57600080fd5b506148cb88828901614786565b9150509295509295909350565b6000826148e7576148e7614465565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526149338285018b6139a3565b91508382036080850152614947828a6139a3565b915060ff881660a085015283820360c085015261496482886135d0565b90861660e0850152838103610100850152905061460581856135d0565b8051610fd481613918565b8051610fd481613945565b8051610fd481613d42565b8051610fd48161371a565b805164ffffffffff81168114610fd457600080fd5b600061016082840312156149d557600080fd5b6149dd6136a7565b825181526149ed60208401614981565b60208201526149fe6040840161498c565b6040820152614a0f60608401614981565b6060820152614a2060808401614997565b6080820152614a3160a084016149a2565b60a0820152614a4260c0840161411a565b60c0820152614a5360e0840161411a565b60e0820152610100614a668185016149ad565b90820152610120614a788482016149ad565b908201526101406138428482016149a2565b64ffffffffff81811683821601908082111561263c5761263c614142565b6000610200808352614abc8184018a6135d0565b90508281036020840152614ad081896135d0565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614b19905060a0830184613a5c565b979650505050505050565b60008060408385031215614b3757600080fd5b825160078110614b4657600080fd5b60208401519092506139988161394556fea164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"linkToNativeFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPublicKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InconsistentReportData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoTransmittersSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouterOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReportInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustBeSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedPublicKeyChange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedRequestDataVersion\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CommitmentDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"indexed\":false,\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"callbackGasLimit\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"OracleResponse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"deleteCommitment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"gasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateCost\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"getDONFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDONPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getThresholdPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracleWithdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"_f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"_offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"donPublicKey\",\"type\":\"bytes\"}],\"name\":\"setDONPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"thresholdPublicKey\",\"type\":\"bytes\"}],\"name\":\"setThresholdPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"availableBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"}],\"internalType\":\"structFunctionsResponse.RequestMeta\",\"name\":\"request\",\"type\":\"tuple\"}],\"name\":\"startRequest\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"transmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60c06040523480156200001157600080fd5b50604051620050f4380380620050f4833981016040819052620000349162000418565b8282828260013380600081620000915760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c457620000c48162000140565b50505015156080526001600160a01b038116620000f457604051632530e88560e11b815260040160405180910390fd5b6001600160a01b0390811660a052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200013482620001eb565b505050505050620005c6565b336001600160a01b038216036200019a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000088565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001f56200033b565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff16600160e81b0261ffff60e81b196001600160481b03909216600160a01b02600160a01b600160e81b031963ffffffff948516600160801b0216600160801b600160e81b03199585166c010000000000000000000000000263ffffffff60601b19978616680100000000000000000297909716600160401b600160801b0319998616640100000000026001600160401b0319909b1695909c1694909417989098179690961698909817929092171617929092179390931692909217905560e0820151600980546001600160e01b039092166001600160e01b0319909216919091179055517f8efd15b0efe82b55a8dc915f88e835007cc65ad0b442997d3c10604961e3907a906200033090839062000536565b60405180910390a150565b6200034562000347565b565b6000546001600160a01b03163314620003455760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000088565b80516001600160a01b0381168114620003bb57600080fd5b919050565b805163ffffffff81168114620003bb57600080fd5b80516001600160481b0381168114620003bb57600080fd5b805161ffff81168114620003bb57600080fd5b80516001600160e01b0381168114620003bb57600080fd5b60008060008385036101408112156200043057600080fd5b6200043b85620003a3565b935061010080601f19830112156200045257600080fd5b60405191508082016001600160401b03811183821017156200048457634e487b7160e01b600052604160045260246000fd5b6040526200049560208701620003c0565b8252620004a560408701620003c0565b6020830152620004b860608701620003c0565b6040830152620004cb60808701620003c0565b6060830152620004de60a08701620003c0565b6080830152620004f160c08701620003d5565b60a08301526200050460e08701620003ed565b60c08301526200051681870162000400565b60e08301525091506200052d6101208501620003a3565b90509250925092565b60006101008201905063ffffffff8084511683528060208501511660208401528060408501511660408401528060608501511660608401528060808501511660808401525060018060481b0360a08401511660a083015260c0830151620005a360c084018261ffff169052565b5060e0830151620005bf60e08401826001600160e01b03169052565b5092915050565b60805160a051614ade62000616600039600081816105be0152818161074c01528181610a1f01528181610cb301528181610ffa015281816117e50152613235015260006112230152614ade6000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806385b214cf116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e71214610529578063e4ddcea61461053c578063f2fde38b1461055257600080fd5b8063c3f909d4146103b4578063d227d245146104f1578063d328a91e1461052157600080fd5b8063a631571e116100bd578063a631571e14610361578063afcb95d714610381578063b1dc65a4146103a157600080fd5b806385b214cf146103135780638da5cb5b146103265780639314176d1461034e57600080fd5b806379ba509711610145578063814118341161011f578063814118341461028957806381f1b9381461029e57806381ff7048146102a657600080fd5b806379ba5097146102665780637d4807871461026e5780637f15e1661461027657600080fd5b80632a905ccc116101765780632a905ccc146101f957806359b5b7ac1461021b57806366316d8d1461025357600080fd5b8063083a546614610192578063181f5a77146101a7575b600080fd5b6101a56101a0366004613528565b610565565b005b6101e36040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e302e300000000081525081565b6040516101f091906135ce565b60405180910390f35b6102016105ba565b60405168ffffffffffffffffff90911681526020016101f0565b61020161022936600461371e565b5060085474010000000000000000000000000000000000000000900468ffffffffffffffffff1690565b6101a56102613660046137ad565b610650565b6101a5610809565b6101a561090b565b6101a5610284366004613528565b610b0b565b610291610b5b565b6040516101f09190613837565b6101e3610bca565b6102f060015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff9485168152939092166020840152908201526060016101f0565b6101a561032136600461384a565b610c9b565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101f0565b6101a561035c3660046138e0565b610d58565b61037461036f3660046139aa565b610f89565b6040516101f09190613aff565b6040805160018152600060208201819052918101919091526060016101f0565b6101a56103af366004613b53565b61112a565b6104e46040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915250604080516101008101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c010000000000000000000000008104831660608301527001000000000000000000000000000000008104909216608082015274010000000000000000000000000000000000000000820468ffffffffffffffffff1660a08201527d01000000000000000000000000000000000000000000000000000000000090910461ffff1660c08201526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e082015290565b6040516101f09190613c0a565b6105046104ff366004613cca565b6117e1565b6040516bffffffffffffffffffffffff90911681526020016101f0565b6101e3611943565b6101a5610537366004613de3565b61199a565b6105446123c6565b6040519081526020016101f0565b6101a5610560366004613eb0565b6125eb565b61056d6125ff565b60008190036105a8576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105b5828483613f66565b505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610627573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064b919061408c565b905090565b610658612682565b806bffffffffffffffffffffffff166000036106925750336000908152600a60205260409020546bffffffffffffffffffffffff166106ec565b336000908152600a60205260409020546bffffffffffffffffffffffff808316911610156106ec576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906107199084906bffffffffffffffffffffffff166140d8565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061076e7f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b1580156107ed57600080fd5b505af1158015610801573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61091361282d565b61091b612682565b6000610925610b5b565b905060005b8151811015610b07576000600a600084848151811061094b5761094b6140fd565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610af6576000600a60008585815181106109aa576109aa6140fd565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610a417f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610a6e57610a6e6140fd565b6020026020010151836040518363ffffffff1660e01b8152600401610ac392919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610add57600080fd5b505af1158015610af1573d6000803e3d6000fd5b505050505b50610b008161412c565b905061092a565b5050565b610b136125ff565b6000819003610b4e576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105b5828483613f66565b60606006805480602002602001604051908101604052809291908181526020018280548015610bc057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610b95575b5050505050905090565b6060600d8054610bd990613ecd565b9050600003610c14576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610c2190613ecd565b80601f0160208091040260200160405190810160405280929190818152602001828054610c4d90613ecd565b8015610bc05780601f10610c6f57610100808354040283529160200191610bc0565b820191906000526020600020905b815481529060010190602001808311610c7d57509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610d0a576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f41690610d4d9083815260200190565b60405180910390a150565b610d6061282d565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff167d010000000000000000000000000000000000000000000000000000000000027fff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff68ffffffffffffffffff90921674010000000000000000000000000000000000000000027fffffff000000000000000000ffffffffffffffffffffffffffffffffffffffff63ffffffff94851670010000000000000000000000000000000002167fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff9585166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9786166801000000000000000002979097167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998616640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b1695909c1694909417989098179690961698909817929092171617929092179390931692909217905560e0820151600980547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092167fffffffff00000000000000000000000000000000000000000000000000000000909216919091179055517f8efd15b0efe82b55a8dc915f88e835007cc65ad0b442997d3c10604961e3907a90610d4d908390613c0a565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611051576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61106261105d83614164565b612835565b90506110746060830160408401613eb0565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff326110c260c0870160a08801614251565b6110d461016088016101408901613eb0565b6110de888061426e565b6110f06101208b016101008c016142d3565b60208b01356111066101008d0160e08e016142ee565b8b60405161111c9998979695949392919061430b565b60405180910390a35b919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16040805160608101825260025480825260035460ff80821660208501526101009091041692820192909252908314611211576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f6e666967446967657374206d69736d6174636800000000000000000000006044820152606401610886565b61121f8b8b8b8b8b8b612c36565b60007f00000000000000000000000000000000000000000000000000000000000000001561127c5760028260200151836040015161125d91906143b3565b61126791906143fb565b6112729060016143b3565b60ff169050611292565b602082015161128c9060016143b3565b60ff1690505b8881146112fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610886565b888714611364576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f7369676e617475726573206f7574206f6620726567697374726174696f6e00006044820152606401610886565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113a7576113a761441d565b60028111156113b8576113b861441d565b90525090506002816020015160028111156113d5576113d561441d565b14801561141c57506006816000015160ff16815481106113f7576113f76140fd565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b611482576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610886565b505050505061148f6134c0565b6000808a8a6040516114a292919061444c565b6040519081900381206114b9918e9060200161445c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b898110156117c3576000600184898460208110611522576115226140fd565b61152f91901a601b6143b3565b8e8e86818110611541576115416140fd565b905060200201358d8d8781811061155a5761155a6140fd565b9050602002013560405160008152602001604052604051611597949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa1580156115b9573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff808216855292965092945084019161010090041660028111156116395761163961441d565b600281111561164a5761164a61441d565b90525092506001836020015160028111156116675761166761441d565b146116ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610886565b8251600090879060ff16601f81106116e8576116e86140fd565b602002015173ffffffffffffffffffffffffffffffffffffffff161461176a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610886565b8086846000015160ff16601f8110611784576117846140fd565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117af6001866143b3565b945050806117bc9061412c565b9050611503565b5050506117d4833383858e8e612ced565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b15801561188157600080fd5b505afa158015611895573d6000803e3d6000fd5b5050505066038d7ea4c680008211156118da576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006118e46105ba565b9050600061192787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061022992505050565b905061193585858385612ebb565b925050505b95945050505050565b6060600c805461195290613ecd565b905060000361198d576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610c2190613ecd565b855185518560ff16601f831115611a0d576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610886565b80600003611a77576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610886565b818314611b05576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610886565b611b10816003614470565b8311611b78576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610886565b611b806125ff565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611bc79088612fa5565b60055415611d7c57600554600090611be190600190614487565b9050600060058281548110611bf857611bf86140fd565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611c3257611c326140fd565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611cb257611cb261449a565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611d1b57611d1b61449a565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611bc7915050565b60005b8151518110156121e35760006004600084600001518481518110611da557611da56140fd565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611def57611def61441d565b14611e56576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610886565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611e8757611e876140fd565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115611f2857611f2861441d565b021790555060009150611f389050565b6004600084602001518481518110611f5257611f526140fd565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611f9c57611f9c61441d565b14612003576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610886565b6040805180820190915260ff821681526020810160028152506004600084602001518481518110612036576120366140fd565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016176101008360028111156120d7576120d761441d565b0217905550508251805160059250839081106120f5576120f56140fd565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9093169290921790915582015180516006919083908110612171576121716140fd565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055806121db8161412c565b915050611d7f565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff438116820292909217808555920481169291829160149161229b918491740100000000000000000000000000000000000000009004166144c9565b92506101000a81548163ffffffff021916908363ffffffff1602179055506122fa4630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a00151612fbe565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986123b1988b9891977401000000000000000000000000000000000000000090920463ffffffff169690959194919391926144e6565b60405180910390a15050505050505050505050565b604080516101008101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116838501526c01000000000000000000000000808304821660608501527001000000000000000000000000000000008304909116608084015274010000000000000000000000000000000000000000820468ffffffffffffffffff1660a0808501919091527d01000000000000000000000000000000000000000000000000000000000090920461ffff1660c08401526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e0840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa158015612520573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125449190614596565b5093505092505080426125579190614487565b836020015163ffffffff1610801561257957506000836020015163ffffffff16115b156125a757505060e001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b600082136125e4576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610886565b5092915050565b6125f36125ff565b6125fc81613069565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314612680576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610886565b565b600b546bffffffffffffffffffffffff1660000361269c57565b60006126a6610b5b565b905080516000036126e3576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600b54600091612702916bffffffffffffffffffffffff166145e6565b905060005b82518110156127ce5781600a6000858481518110612727576127276140fd565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff1661278f9190614611565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550806127c79061412c565b9050612707565b5081516127db9082614636565b600b80546000906127fb9084906bffffffffffffffffffffffff166140d8565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505050565b6126806125ff565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915260408051610100808201835260085463ffffffff80821684526401000000008204811660208501526801000000000000000082048116948401949094526c010000000000000000000000008104841660608401527001000000000000000000000000000000008104909316608083015274010000000000000000000000000000000000000000830468ffffffffffffffffff1660a08301527d01000000000000000000000000000000000000000000000000000000000090920461ffff90811660c083018190526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e0840152928501519192911611156129bb576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60085460009074010000000000000000000000000000000000000000900468ffffffffffffffffff16905060006129fc8560e001513a848860800151612ebb565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612a58576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612adb3087604001518860a001518960c001516001612a799190614666565b6040805173ffffffffffffffffffffffffffffffffffffffff958616602080830191909152949095168582015267ffffffffffffffff928316606086015291166080808501919091528151808503909101815260a09093019052815191012090565b90506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001836bffffffffffffffffffffffff168152602001876040015173ffffffffffffffffffffffffffffffffffffffff1681526020018760a0015167ffffffffffffffff1681526020018760e0015163ffffffff168152602001876080015168ffffffffffffffffff1681526020018468ffffffffffffffffff168152602001856040015163ffffffff1664ffffffffff168152602001856060015163ffffffff1664ffffffffff168152602001856080015163ffffffff1642612bcd9190614687565b63ffffffff16815250945084604051602001612be99190613aff565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181528151602092830120600093845260079092529091205550919392505050565b6000612c43826020614470565b612c4e856020614470565b612c5a88610144614687565b612c649190614687565b612c6e9190614687565b612c79906000614687565b9050368114612ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610886565b50505050505050565b606080808080612cff86880188614775565b8451949950929750909550935091501580612d1c57508351855114155b80612d2957508251855114155b80612d3657508151855114155b80612d4357508051855114155b15612d7a576040517f0be3632800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8551811015612ead576000612e12878381518110612d9d57612d9d6140fd565b6020026020010151878481518110612db757612db76140fd565b6020026020010151878581518110612dd157612dd16140fd565b6020026020010151878681518110612deb57612deb6140fd565b6020026020010151878781518110612e0557612e056140fd565b602002602001015161315e565b90506000816006811115612e2857612e2861441d565b1480612e4557506001816006811115612e4357612e4361441d565b145b15612e9c57868281518110612e5c57612e5c6140fd565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b50612ea68161412c565b9050612d7d565b505050505050505050505050565b60085460009081908690612ef39063ffffffff6c010000000000000000000000008204811691680100000000000000009004166144c9565b612efd91906144c9565b60085463ffffffff918216925060009161271091612f1c911688614470565b612f269190614847565b612f309087614687565b90506000612f3d826133ef565b90506000612f59846bffffffffffffffffffffffff8416614470565b90506000612f7568ffffffffffffffffff808916908a16614611565b9050612f97612f926bffffffffffffffffffffffff831684614687565b61341e565b9a9950505050505050505050565b6000612faf610b5b565b511115610b0757610b07612682565b6000808a8a8a8a8a8a8a8a8a604051602001612fe29998979695949392919061485b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036130e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610886565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080838060200190518101906131759190614931565b60008881526007602052604090205490915061319557600291505061193a565b806040516020016131a69190613aff565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060008a81526007909352912054146131f857600691505061193a565b60006132033a6133ef565b9050600082610120015183610100015161321d9190614a04565b61322e9064ffffffffff1683614636565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298b8b878960e0015168ffffffffffffffffff168861328d9190614611565b338b6040518763ffffffff1660e01b81526004016132b096959493929190614a22565b60408051808303816000875af11580156132ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f29190614a9e565b9092509050600082600681111561330b5761330b61441d565b1480613328575060018260068111156133265761332661441d565b145b156133e15760008b8152600760205260408120556133468184614611565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0870151600b805468ffffffffffffffffff909216939092916133b291859116614611565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b509998505050505050505050565b60006134186133fc6123c6565b61340e84670de0b6b3a7640000614470565b612f929190614847565b92915050565b60006bffffffffffffffffffffffff8211156134bc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610886565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f8401126134f157600080fd5b50813567ffffffffffffffff81111561350957600080fd5b60208301915083602082850101111561352157600080fd5b9250929050565b6000806020838503121561353b57600080fd5b823567ffffffffffffffff81111561355257600080fd5b61355e858286016134df565b90969095509350505050565b6000815180845260005b8181101561359057602081850181015186830182015201613574565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006135e1602083018461356a565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610160810167ffffffffffffffff8111828210171561363b5761363b6135e8565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613688576136886135e8565b604052919050565b600082601f8301126136a157600080fd5b813567ffffffffffffffff8111156136bb576136bb6135e8565b6136ec60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613641565b81815284602083860101111561370157600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561373057600080fd5b813567ffffffffffffffff81111561374757600080fd5b61375384828501613690565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff811681146125fc57600080fd5b80356111258161375b565b6bffffffffffffffffffffffff811681146125fc57600080fd5b803561112581613788565b600080604083850312156137c057600080fd5b82356137cb8161375b565b915060208301356137db81613788565b809150509250929050565b600081518084526020808501945080840160005b8381101561382c57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016137fa565b509495945050505050565b6020815260006135e160208301846137e6565b60006020828403121561385c57600080fd5b5035919050565b63ffffffff811681146125fc57600080fd5b803561112581613863565b68ffffffffffffffffff811681146125fc57600080fd5b803561112581613880565b803561ffff8116811461112557600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461112557600080fd5b60006101008083850312156138f457600080fd5b6040519081019067ffffffffffffffff82118183101715613917576139176135e8565b816040528335915061392882613863565b81815261393760208501613875565b602082015261394860408501613875565b604082015261395960608501613875565b606082015261396a60808501613875565b608082015261397b60a08501613897565b60a082015261398c60c085016138a2565b60c082015261399d60e085016138b4565b60e0820152949350505050565b6000602082840312156139bc57600080fd5b813567ffffffffffffffff8111156139d357600080fd5b820161016081850312156135e157600080fd5b805182526020810151613a11602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613a3160408401826bffffffffffffffffffffffff169052565b506060810151613a59606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613a75608084018267ffffffffffffffff169052565b5060a0810151613a8d60a084018263ffffffff169052565b5060c0810151613aaa60c084018268ffffffffffffffffff169052565b5060e0810151613ac760e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b610160810161341882846139e6565b60008083601f840112613b2057600080fd5b50813567ffffffffffffffff811115613b3857600080fd5b6020830191508360208260051b850101111561352157600080fd5b60008060008060008060008060e0898b031215613b6f57600080fd5b606089018a811115613b8057600080fd5b8998503567ffffffffffffffff80821115613b9a57600080fd5b613ba68c838d016134df565b909950975060808b0135915080821115613bbf57600080fd5b613bcb8c838d01613b0e565b909750955060a08b0135915080821115613be457600080fd5b50613bf18b828c01613b0e565b999c989b50969995989497949560c00135949350505050565b60006101008201905063ffffffff8084511683528060208501511660208401528060408501511660408401528060608501511660608401528060808501511660808401525068ffffffffffffffffff60a08401511660a083015260c0830151613c7960c084018261ffff169052565b5060e08301516125e460e08401827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169052565b67ffffffffffffffff811681146125fc57600080fd5b803561112581613ca9565b600080600080600060808688031215613ce257600080fd5b8535613ced81613ca9565b9450602086013567ffffffffffffffff811115613d0957600080fd5b613d15888289016134df565b9095509350506040860135613d2981613863565b949793965091946060013592915050565b600067ffffffffffffffff821115613d5457613d546135e8565b5060051b60200190565b600082601f830112613d6f57600080fd5b81356020613d84613d7f83613d3a565b613641565b82815260059290921b84018101918181019086841115613da357600080fd5b8286015b84811015613dc7578035613dba8161375b565b8352918301918301613da7565b509695505050505050565b803560ff8116811461112557600080fd5b60008060008060008060c08789031215613dfc57600080fd5b863567ffffffffffffffff80821115613e1457600080fd5b613e208a838b01613d5e565b97506020890135915080821115613e3657600080fd5b613e428a838b01613d5e565b9650613e5060408a01613dd2565b95506060890135915080821115613e6657600080fd5b613e728a838b01613690565b9450613e8060808a01613cbf565b935060a0890135915080821115613e9657600080fd5b50613ea389828a01613690565b9150509295509295509295565b600060208284031215613ec257600080fd5b81356135e18161375b565b600181811c90821680613ee157607f821691505b602082108103613f1a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105b557600081815260208120601f850160051c81016020861015613f475750805b601f850160051c820191505b8181101561080157828155600101613f53565b67ffffffffffffffff831115613f7e57613f7e6135e8565b613f9283613f8c8354613ecd565b83613f20565b6000601f841160018114613fe45760008515613fae5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b17835561407a565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156140335786850135825560209485019460019092019101614013565b508682101561406e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b805161112581613880565b60006020828403121561409e57600080fd5b81516135e181613880565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff8281168282160390808211156125e4576125e46140a9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361415d5761415d6140a9565b5060010190565b6000610160823603121561417757600080fd5b61417f613617565b823567ffffffffffffffff81111561419657600080fd5b6141a236828601613690565b825250602083013560208201526141bb6040840161377d565b60408201526141cc606084016137a2565b60608201526141dd60808401613897565b60808201526141ee60a08401613cbf565b60a08201526141ff60c08401613cbf565b60c082015261421060e08401613875565b60e08201526101006142238185016138a2565b90820152610120614235848201613cbf565b9082015261014061424784820161377d565b9082015292915050565b60006020828403121561426357600080fd5b81356135e181613ca9565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126142a357600080fd5b83018035915067ffffffffffffffff8211156142be57600080fd5b60200191503681900382131561352157600080fd5b6000602082840312156142e557600080fd5b6135e1826138a2565b60006020828403121561430057600080fd5b81356135e181613863565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168301019050612f9760e08301846139e6565b60ff8181168382160190811115613418576134186140a9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061440e5761440e6143cc565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b8082028115828204841417613418576134186140a9565b81810381811115613418576134186140a9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff8181168382160190808211156125e4576125e46140a9565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526145168184018a6137e6565b9050828103608084015261452a81896137e6565b905060ff871660a084015282810360c0840152614547818761356a565b905067ffffffffffffffff851660e084015282810361010084015261456c818561356a565b9c9b505050505050505050505050565b805169ffffffffffffffffffff8116811461112557600080fd5b600080600080600060a086880312156145ae57600080fd5b6145b78661457c565b94506020860151935060408601519250606086015191506145da6080870161457c565b90509295509295909350565b60006bffffffffffffffffffffffff80841680614605576146056143cc565b92169190910492915050565b6bffffffffffffffffffffffff8181168382160190808211156125e4576125e46140a9565b6bffffffffffffffffffffffff81811683821602808216919082811461465e5761465e6140a9565b505092915050565b67ffffffffffffffff8181168382160190808211156125e4576125e46140a9565b80820180821115613418576134186140a9565b600082601f8301126146ab57600080fd5b813560206146bb613d7f83613d3a565b82815260059290921b840181019181810190868411156146da57600080fd5b8286015b84811015613dc757803583529183019183016146de565b600082601f83011261470657600080fd5b81356020614716613d7f83613d3a565b82815260059290921b8401810191818101908684111561473557600080fd5b8286015b84811015613dc757803567ffffffffffffffff8111156147595760008081fd5b6147678986838b0101613690565b845250918301918301614739565b600080600080600060a0868803121561478d57600080fd5b853567ffffffffffffffff808211156147a557600080fd5b6147b189838a0161469a565b965060208801359150808211156147c757600080fd5b6147d389838a016146f5565b955060408801359150808211156147e957600080fd5b6147f589838a016146f5565b9450606088013591508082111561480b57600080fd5b61481789838a016146f5565b9350608088013591508082111561482d57600080fd5b5061483a888289016146f5565b9150509295509295909350565b600082614856576148566143cc565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526148a28285018b6137e6565b915083820360808501526148b6828a6137e6565b915060ff881660a085015283820360c08501526148d3828861356a565b90861660e0850152838103610100850152905061456c818561356a565b80516111258161375b565b805161112581613788565b805161112581613ca9565b805161112581613863565b805164ffffffffff8116811461112557600080fd5b6000610160828403121561494457600080fd5b61494c613617565b8251815261495c602084016148f0565b602082015261496d604084016148fb565b604082015261497e606084016148f0565b606082015261498f60808401614906565b60808201526149a060a08401614911565b60a08201526149b160c08401614081565b60c08201526149c260e08401614081565b60e08201526101006149d581850161491c565b908201526101206149e784820161491c565b908201526101406149f9848201614911565b908201529392505050565b64ffffffffff8181168382160190808211156125e4576125e46140a9565b6000610200808352614a368184018a61356a565b90508281036020840152614a4a818961356a565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614a93905060a08301846139e6565b979650505050505050565b60008060408385031215614ab157600080fd5b825160078110614ac057600080fd5b60208401519092506137db8161378856fea164736f6c6343000813000a", } var FunctionsCoordinatorABI = FunctionsCoordinatorMetaData.ABI @@ -211,9 +210,9 @@ func (_FunctionsCoordinator *FunctionsCoordinatorTransactorRaw) Transact(opts *b return _FunctionsCoordinator.Contract.contract.Transact(opts, method, params...) } -func (_FunctionsCoordinator *FunctionsCoordinatorCaller) EstimateCost(opts *bind.CallOpts, subscriptionId uint64, data []byte, callbackGasLimit uint32, gasPriceGwei *big.Int) (*big.Int, error) { +func (_FunctionsCoordinator *FunctionsCoordinatorCaller) EstimateCost(opts *bind.CallOpts, subscriptionId uint64, data []byte, callbackGasLimit uint32, gasPriceWei *big.Int) (*big.Int, error) { var out []interface{} - err := _FunctionsCoordinator.contract.Call(opts, &out, "estimateCost", subscriptionId, data, callbackGasLimit, gasPriceGwei) + err := _FunctionsCoordinator.contract.Call(opts, &out, "estimateCost", subscriptionId, data, callbackGasLimit, gasPriceWei) if err != nil { return *new(*big.Int), err @@ -225,12 +224,12 @@ func (_FunctionsCoordinator *FunctionsCoordinatorCaller) EstimateCost(opts *bind } -func (_FunctionsCoordinator *FunctionsCoordinatorSession) EstimateCost(subscriptionId uint64, data []byte, callbackGasLimit uint32, gasPriceGwei *big.Int) (*big.Int, error) { - return _FunctionsCoordinator.Contract.EstimateCost(&_FunctionsCoordinator.CallOpts, subscriptionId, data, callbackGasLimit, gasPriceGwei) +func (_FunctionsCoordinator *FunctionsCoordinatorSession) EstimateCost(subscriptionId uint64, data []byte, callbackGasLimit uint32, gasPriceWei *big.Int) (*big.Int, error) { + return _FunctionsCoordinator.Contract.EstimateCost(&_FunctionsCoordinator.CallOpts, subscriptionId, data, callbackGasLimit, gasPriceWei) } -func (_FunctionsCoordinator *FunctionsCoordinatorCallerSession) EstimateCost(subscriptionId uint64, data []byte, callbackGasLimit uint32, gasPriceGwei *big.Int) (*big.Int, error) { - return _FunctionsCoordinator.Contract.EstimateCost(&_FunctionsCoordinator.CallOpts, subscriptionId, data, callbackGasLimit, gasPriceGwei) +func (_FunctionsCoordinator *FunctionsCoordinatorCallerSession) EstimateCost(subscriptionId uint64, data []byte, callbackGasLimit uint32, gasPriceWei *big.Int) (*big.Int, error) { + return _FunctionsCoordinator.Contract.EstimateCost(&_FunctionsCoordinator.CallOpts, subscriptionId, data, callbackGasLimit, gasPriceWei) } func (_FunctionsCoordinator *FunctionsCoordinatorCaller) GetAdminFee(opts *bind.CallOpts) (*big.Int, error) { @@ -1690,7 +1689,7 @@ func (FunctionsCoordinatorConfigSet) Topic() common.Hash { } func (FunctionsCoordinatorConfigUpdated) Topic() common.Hash { - return common.HexToHash("0x5b6e2e1a03ea742ce04ca36d0175411a0772f99ef4ee84aeb9868a1ef6ddc82c") + return common.HexToHash("0x8efd15b0efe82b55a8dc915f88e835007cc65ad0b442997d3c10604961e3907a") } func (FunctionsCoordinatorOracleRequest) Topic() common.Hash { @@ -1718,7 +1717,7 @@ func (_FunctionsCoordinator *FunctionsCoordinator) Address() common.Address { } type FunctionsCoordinatorInterface interface { - EstimateCost(opts *bind.CallOpts, subscriptionId uint64, data []byte, callbackGasLimit uint32, gasPriceGwei *big.Int) (*big.Int, error) + EstimateCost(opts *bind.CallOpts, subscriptionId uint64, data []byte, callbackGasLimit uint32, gasPriceWei *big.Int) (*big.Int, error) GetAdminFee(opts *bind.CallOpts) (*big.Int, error) diff --git a/core/gethwrappers/functions/generated/functions_load_test_client/functions_load_test_client.go b/core/gethwrappers/functions/generated/functions_load_test_client/functions_load_test_client.go index 1f399700b1c..37a895fe8cd 100644 --- a/core/gethwrappers/functions/generated/functions_load_test_client/functions_load_test_client.go +++ b/core/gethwrappers/functions/generated/functions_load_test_client/functions_load_test_client.go @@ -32,7 +32,7 @@ var ( var FunctionsLoadTestClientMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyArgs\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptySecrets\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptySource\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoInlineSecrets\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyRouterCanFulfill\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RequestFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RequestSent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_CALLBACK_GAS\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStats\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"}],\"name\":\"handleOracleFulfillment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastError\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRequestID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastResponse\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"resetStats\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"times\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"cborEncodedRequest\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendEncodedRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"times\",\"type\":\"uint32\"},{\"internalType\":\"string\",\"name\":\"source\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"encryptedSecretsReferences\",\"type\":\"bytes\"},{\"internalType\":\"string[]\",\"name\":\"args\",\"type\":\"string[]\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"times\",\"type\":\"uint32\"},{\"internalType\":\"string\",\"name\":\"source\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"slotId\",\"type\":\"uint8\"},{\"internalType\":\"uint64\",\"name\":\"slotVersion\",\"type\":\"uint64\"},{\"internalType\":\"string[]\",\"name\":\"args\",\"type\":\"string[]\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequestWithDONHostedSecrets\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalEmptyResponses\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalFailedResponses\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalRequests\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSucceededResponses\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b506040516200243938038062002439833981016040819052620000349162000180565b6001600160a01b0381166080523380600081620000985760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000cb57620000cb81620000d5565b50505050620001b2565b336001600160a01b038216036200012f5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200008f565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019357600080fd5b81516001600160a01b0381168114620001ab57600080fd5b9392505050565b608051612264620001d5600039600081816102ac0152610fde01526122646000f3fe608060405234801561001057600080fd5b506004361061011b5760003560e01c806379ba5097116100b2578063954491c111610081578063c59d484711610066578063c59d484714610246578063c9429e2a14610261578063f2fde38b1461028157600080fd5b8063954491c114610220578063b2518e0e1461023357600080fd5b806379ba5097146101cd578063887efe94146101d55780638aea61dc146101e85780638da5cb5b146101f857600080fd5b80635c1d92e9116100ee5780635c1d92e91461019b57806362747e42146101b35780636d9809a0146101bb578063724ec8a2146101c557600080fd5b80630ca761751461012057806329f0de3f146101355780632ab424da1461015357806347c0318614610184575b600080fd5b61013361012e3660046118ee565b610294565b005b61013d610313565b60405161014a91906119bf565b60405180910390f35b60055461016f9068010000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161014a565b61018d60025481565b60405190815260200161014a565b60055461016f90640100000000900463ffffffff1681565b61013d6103a1565b61016f6203d09081565b6101336103ae565b610133610420565b6101336101e3366004611a91565b610522565b60055461016f9063ffffffff1681565b60005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161014a565b61013361022e366004611b55565b61069c565b610133610241366004611c1b565b6107ba565b61024e610839565b60405161014a9796959493929190611c81565b60055461016f906c01000000000000000000000000900463ffffffff1681565b61013361028f366004611cde565b6109c1565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610303576040517fc6829f8300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61030e8383836109d5565b505050565b6004805461032090611d14565b80601f016020809104026020016040519081016040528092919081815260200182805461034c90611d14565b80156103995780601f1061036e57610100808354040283529160200191610399565b820191906000526020600020905b81548152906001019060200180831161037c57829003601f168201915b505050505081565b6003805461032090611d14565b6103b6610adf565b6000600281905560408051602081019091529081526003906103d89082611db5565b506040805160208101909152600081526004906103f59082611db5565b50600580547fffffffffffffffffffffffffffffffff00000000000000000000000000000000169055565b60015473ffffffffffffffffffffffffffffffffffffffff1633146104a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61052a610adf565b6105736040805161010081019091528060008152602001600081526020016000815260200160608152602001606081526020016060815260200160608152602001606081525090565b6105b589898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508593925050610b629050565b85156105fd576105fd87878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508593925050610b739050565b8315610617576106176106108587611ecf565b8290610bbd565b60005b8a63ffffffff1681101561068f5761063f61063483610c00565b856203d09086610fd9565b600255600580546001919060009061065e90849063ffffffff16611f96565b92506101000a81548163ffffffff021916908363ffffffff160217905550808061068790611fba565b91505061061a565b5050505050505050505050565b6106a4610adf565b6106ed6040805161010081019091528060008152602001600081526020016000815260200160608152602001606081526020016060815260200160608152602001606081525090565b61072f89898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508593925050610b629050565b61073a8188886110b8565b831561074d5761074d6106108587611ecf565b60005b8a63ffffffff1681101561068f5761076a61063483610c00565b600255600580546001919060009061078990849063ffffffff16611f96565b92506101000a81548163ffffffff021916908363ffffffff16021790555080806107b290611fba565b915050610750565b6107c2610adf565b60005b8463ffffffff16811015610832576107e284846203d09085610fd9565b600255600580546001919060009061080190849063ffffffff16611f96565b92506101000a81548163ffffffff021916908363ffffffff160217905550808061082a90611fba565b9150506107c5565b5050505050565b600060608060008060008061084c610adf565b60025460055460038054909160049163ffffffff808316926801000000000000000081048216926c01000000000000000000000000820483169264010000000090920490911690869061089e90611d14565b80601f01602080910402602001604051908101604052809291908181526020018280546108ca90611d14565b80156109175780601f106108ec57610100808354040283529160200191610917565b820191906000526020600020905b8154815290600101906020018083116108fa57829003601f168201915b5050505050955084805461092a90611d14565b80601f016020809104026020016040519081016040528092919081815260200182805461095690611d14565b80156109a35780601f10610978576101008083540402835291602001916109a3565b820191906000526020600020905b81548152906001019060200180831161098657829003601f168201915b50505050509450965096509650965096509650965090919293949596565b6109c9610adf565b6109d28161117b565b50565b600283905560036109e68382611db5565b5060046109f38282611db5565b508151600003610a3e576001600560048282829054906101000a900463ffffffff16610a1f9190611f96565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b805115610a865760016005600c8282829054906101000a900463ffffffff16610a679190611f96565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b815115801590610a9557508051155b1561030e576001600560088282829054906101000a900463ffffffff16610abc9190611f96565b92506101000a81548163ffffffff021916908363ffffffff160217905550505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610b60576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161049d565b565b610b6f8260008084611270565b5050565b8051600003610bae576040517fe889636f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016020830152608090910152565b8051600003610bf8576040517ffe936cb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60c090910152565b60606000610c0f610100611307565b9050610c596040518060400160405280600c81526020017f636f64654c6f636174696f6e00000000000000000000000000000000000000008152508261132890919063ffffffff16565b8251610c77906002811115610c7057610c70611ff2565b8290611341565b60408051808201909152600881527f6c616e67756167650000000000000000000000000000000000000000000000006020820152610cb6908290611328565b6040830151610ccd908015610c7057610c70611ff2565b60408051808201909152600681527f736f7572636500000000000000000000000000000000000000000000000000006020820152610d0c908290611328565b6060830151610d1c908290611328565b60a08301515115610d765760408051808201909152601081527f726571756573745369676e6174757265000000000000000000000000000000006020820152610d66908290611328565b60a0830151610d76908290611376565b60c08301515115610e235760408051808201909152600481527f61726773000000000000000000000000000000000000000000000000000000006020820152610dc0908290611328565b610dc981611383565b60005b8360c0015151811015610e1957610e098460c001518281518110610df257610df2612021565b60200260200101518361132890919063ffffffff16565b610e1281611fba565b9050610dcc565b50610e23816113a7565b60808301515115610f2457600083602001516002811115610e4657610e46611ff2565b03610e7d576040517fa80d31f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201909152600f81527f736563726574734c6f636174696f6e00000000000000000000000000000000006020820152610ebc908290611328565b610ed583602001516002811115610c7057610c70611ff2565b60408051808201909152600781527f73656372657473000000000000000000000000000000000000000000000000006020820152610f14908290611328565b6080830151610f24908290611376565b60e08301515115610fd15760408051808201909152600981527f62797465734172677300000000000000000000000000000000000000000000006020820152610f6e908290611328565b610f7781611383565b60005b8360e0015151811015610fc757610fb78460e001518281518110610fa057610fa0612021565b60200260200101518361137690919063ffffffff16565b610fc081611fba565b9050610f7a565b50610fd1816113a7565b515192915050565b6000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663461d27628688600188886040518663ffffffff1660e01b815260040161103e959493929190612050565b6020604051808303816000875af115801561105d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611081919061209a565b60405190915081907f1131472297a800fee664d1d89cfa8f7676ff07189ecc53f80bbb5f4969099db890600090a295945050505050565b60006110c5610100611307565b905061110f6040518060400160405280600681526020017f736c6f74494400000000000000000000000000000000000000000000000000008152508261132890919063ffffffff16565b61111c8160ff85166113c5565b60408051808201909152600781527f76657273696f6e00000000000000000000000000000000000000000000000000602082015261115b908290611328565b61116581836113c5565b6002602085015251516080909301929092525050565b3373ffffffffffffffffffffffffffffffffffffffff8216036111fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161049d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516000036112ab576040517f22ce3edd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b838360028111156112be576112be611ff2565b908160028111156112d1576112d1611ff2565b905250604084018280156112e7576112e7611ff2565b908180156112f7576112f7611ff2565b9052506060909301929092525050565b61130f6117a5565b805161131b90836113d1565b5060006020820152919050565b611335826003835161144b565b815161030e9082611572565b815161134e9060c261159a565b50610b6f828260405160200161136691815260200190565b6040516020818303038152906040525b611335826002835161144b565b61138e816004611603565b6001816020018181516113a191906120b3565b90525050565b6113b2816007611603565b6001816020018181516113a191906120c6565b610b6f8260008361144b565b6040805180820190915260608152600060208201526113f16020836120d9565b15611419576114016020836120d9565b61140c9060206120c6565b61141690836120b3565b91505b60208084018390526040518085526000815290818401018181101561143d57600080fd5b604052508290505b92915050565b60178167ffffffffffffffff16116114785782516114729060e0600585901b16831761159a565b50505050565b60ff8167ffffffffffffffff16116114ba5782516114a1906018611fe0600586901b161761159a565b5082516114729067ffffffffffffffff8316600161161a565b61ffff8167ffffffffffffffff16116114fd5782516114e4906019611fe0600586901b161761159a565b5082516114729067ffffffffffffffff8316600261161a565b63ffffffff8167ffffffffffffffff161161154257825161152990601a611fe0600586901b161761159a565b5082516114729067ffffffffffffffff8316600461161a565b825161155990601b611fe0600586901b161761159a565b5082516114729067ffffffffffffffff8316600861161a565b6040805180820190915260608152600060208201526115938383845161169f565b9392505050565b60408051808201909152606081526000602082015282515160006115bf8260016120b3565b9050846020015182106115e0576115e0856115db836002612114565b61178e565b84516020838201018581535080518211156115f9578181525b5093949350505050565b815161030e90601f611fe0600585901b161761159a565b604080518082019091526060815260006020820152835151600061163e82856120b3565b9050856020015181111561165b5761165b866115db836002612114565b6000600161166b8661010061224b565b61167591906120c6565b90508651828101878319825116178152508051831115611693578281525b50959695505050505050565b60408051808201909152606081526000602082015282518211156116c257600080fd5b83515160006116d184836120b3565b905085602001518111156116ee576116ee866115db836002612114565b855180518382016020019160009180851115611708578482525b505050602086015b6020861061174857805182526117276020836120b3565b91506117346020826120b3565b90506117416020876120c6565b9550611710565b5181517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60208890036101000a0190811690199190911617905250849150509392505050565b815161179a83836113d1565b506114728382611572565b60405180604001604052806117cd604051806040016040528060608152602001600081525090565b8152602001600081525090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611850576118506117da565b604052919050565b600067ffffffffffffffff831115611872576118726117da565b6118a360207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011601611809565b90508281528383830111156118b757600080fd5b828260208301376000602084830101529392505050565b600082601f8301126118df57600080fd5b61159383833560208501611858565b60008060006060848603121561190357600080fd5b83359250602084013567ffffffffffffffff8082111561192257600080fd5b61192e878388016118ce565b9350604086013591508082111561194457600080fd5b50611951868287016118ce565b9150509250925092565b6000815180845260005b8181101561198157602081850181015186830182015201611965565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000611593602083018461195b565b803563ffffffff811681146119e657600080fd5b919050565b60008083601f8401126119fd57600080fd5b50813567ffffffffffffffff811115611a1557600080fd5b602083019150836020828501011115611a2d57600080fd5b9250929050565b60008083601f840112611a4657600080fd5b50813567ffffffffffffffff811115611a5e57600080fd5b6020830191508360208260051b8501011115611a2d57600080fd5b803567ffffffffffffffff811681146119e657600080fd5b600080600080600080600080600060c08a8c031215611aaf57600080fd5b611ab88a6119d2565b985060208a013567ffffffffffffffff80821115611ad557600080fd5b611ae18d838e016119eb565b909a50985060408c0135915080821115611afa57600080fd5b611b068d838e016119eb565b909850965060608c0135915080821115611b1f57600080fd5b50611b2c8c828d01611a34565b9095509350611b3f905060808b01611a79565b915060a08a013590509295985092959850929598565b600080600080600080600080600060e08a8c031215611b7357600080fd5b611b7c8a6119d2565b985060208a013567ffffffffffffffff80821115611b9957600080fd5b611ba58d838e016119eb565b909a50985060408c0135915060ff82168214611bc057600080fd5b819750611bcf60608d01611a79565b965060808c0135915080821115611be557600080fd5b50611bf28c828d01611a34565b9095509350611c05905060a08b01611a79565b915060c08a013590509295985092959850929598565b60008060008060808587031215611c3157600080fd5b611c3a856119d2565b9350602085013567ffffffffffffffff811115611c5657600080fd5b611c62878288016118ce565b935050611c7160408601611a79565b9396929550929360600135925050565b87815260e060208201526000611c9a60e083018961195b565b8281036040840152611cac818961195b565b63ffffffff97881660608501529587166080840152505091841660a083015290921660c0909201919091529392505050565b600060208284031215611cf057600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461159357600080fd5b600181811c90821680611d2857607f821691505b602082108103611d61577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f82111561030e57600081815260208120601f850160051c81016020861015611d8e5750805b601f850160051c820191505b81811015611dad57828155600101611d9a565b505050505050565b815167ffffffffffffffff811115611dcf57611dcf6117da565b611de381611ddd8454611d14565b84611d67565b602080601f831160018114611e365760008415611e005750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555611dad565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015611e8357888601518255948401946001909101908401611e64565b5085821015611ebf57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600067ffffffffffffffff80841115611eea57611eea6117da565b8360051b6020611efb818301611809565b868152918501918181019036841115611f1357600080fd5b865b84811015611f5b57803586811115611f2d5760008081fd5b880136601f820112611f3f5760008081fd5b611f4d368235878401611858565b845250918301918301611f15565b50979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b63ffffffff818116838216019080821115611fb357611fb3611f67565b5092915050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611feb57611feb611f67565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b67ffffffffffffffff8616815260a06020820152600061207360a083018761195b565b61ffff9590951660408301525063ffffffff92909216606083015260809091015292915050565b6000602082840312156120ac57600080fd5b5051919050565b8082018082111561144557611445611f67565b8181038181111561144557611445611f67565b60008261210f577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b808202811582820484141761144557611445611f67565b600181815b8085111561218457817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561216a5761216a611f67565b8085161561217757918102915b93841c9390800290612130565b509250929050565b60008261219b57506001611445565b816121a857506000611445565b81600181146121be57600281146121c8576121e4565b6001915050611445565b60ff8411156121d9576121d9611f67565b50506001821b611445565b5060208310610133831016604e8410600b8410161715612207575081810a611445565b612211838361212b565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561224357612243611f67565b029392505050565b6000611593838361218c56fea164736f6c6343000813000a", + Bin: "0x60a06040523480156200001157600080fd5b50604051620023ff380380620023ff833981016040819052620000349162000180565b6001600160a01b0381166080523380600081620000985760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000cb57620000cb81620000d5565b50505050620001b2565b336001600160a01b038216036200012f5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200008f565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019357600080fd5b81516001600160a01b0381168114620001ab57600080fd5b9392505050565b60805161222a620001d5600039600081816102ac0152610fa0015261222a6000f3fe608060405234801561001057600080fd5b506004361061011b5760003560e01c806379ba5097116100b2578063954491c111610081578063c59d484711610066578063c59d484714610246578063c9429e2a14610261578063f2fde38b1461028157600080fd5b8063954491c114610220578063b2518e0e1461023357600080fd5b806379ba5097146101cd578063887efe94146101d55780638aea61dc146101e85780638da5cb5b146101f857600080fd5b80635c1d92e9116100ee5780635c1d92e91461019b57806362747e42146101b35780636d9809a0146101bb578063724ec8a2146101c557600080fd5b80630ca761751461012057806329f0de3f146101355780632ab424da1461015357806347c0318614610184575b600080fd5b61013361012e3660046118b4565b610294565b005b61013d61033e565b60405161014a9190611985565b60405180910390f35b60055461016f9068010000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161014a565b61018d60025481565b60405190815260200161014a565b60055461016f90640100000000900463ffffffff1681565b61013d6103cc565b61016f6203d09081565b6101336103d9565b61013361044b565b6101336101e3366004611a57565b61054d565b60055461016f9063ffffffff1681565b60005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161014a565b61013361022e366004611b1b565b6106bf565b610133610241366004611be1565b6107d5565b61024e610854565b60405161014a9796959493929190611c47565b60055461016f906c01000000000000000000000000900463ffffffff1681565b61013361028f366004611ca4565b6109dc565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610303576040517fc6829f8300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61030e8383836109f0565b60405183907f85e1543bf2f84fe80c6badbce3648c8539ad1df4d2b3d822938ca0538be727e690600090a2505050565b6004805461034b90611cda565b80601f016020809104026020016040519081016040528092919081815260200182805461037790611cda565b80156103c45780601f10610399576101008083540402835291602001916103c4565b820191906000526020600020905b8154815290600101906020018083116103a757829003601f168201915b505050505081565b6003805461034b90611cda565b6103e1610afb565b6000600281905560408051602081019091529081526003906104039082611d7b565b506040805160208101909152600081526004906104209082611d7b565b50600580547fffffffffffffffffffffffffffffffff00000000000000000000000000000000169055565b60015473ffffffffffffffffffffffffffffffffffffffff1633146104d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610555610afb565b6105966040805160e0810190915280600081526020016000815260200160008152602001606081526020016060815260200160608152602001606081525090565b6105d889898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508593925050610b7e9050565b85156106205761062087878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508593925050610b8f9050565b831561063a5761063a6106338587611e95565b8290610bd9565b60005b8a63ffffffff168110156106b25761066261065783610c1c565b856203d09086610f9b565b600255600580546001919060009061068190849063ffffffff16611f5c565b92506101000a81548163ffffffff021916908363ffffffff16021790555080806106aa90611f80565b91505061063d565b5050505050505050505050565b6106c7610afb565b6107086040805160e0810190915280600081526020016000815260200160008152602001606081526020016060815260200160608152602001606081525090565b61074a89898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508593925050610b7e9050565b61075581888861107a565b8315610768576107686106338587611e95565b60005b8a63ffffffff168110156106b25761078561065783610c1c565b60025560058054600191906000906107a490849063ffffffff16611f5c565b92506101000a81548163ffffffff021916908363ffffffff16021790555080806107cd90611f80565b91505061076b565b6107dd610afb565b60005b8463ffffffff1681101561084d576107fd84846203d09085610f9b565b600255600580546001919060009061081c90849063ffffffff16611f5c565b92506101000a81548163ffffffff021916908363ffffffff160217905550808061084590611f80565b9150506107e0565b5050505050565b6000606080600080600080610867610afb565b60025460055460038054909160049163ffffffff808316926801000000000000000081048216926c0100000000000000000000000082048316926401000000009092049091169086906108b990611cda565b80601f01602080910402602001604051908101604052809291908181526020018280546108e590611cda565b80156109325780601f1061090757610100808354040283529160200191610932565b820191906000526020600020905b81548152906001019060200180831161091557829003601f168201915b5050505050955084805461094590611cda565b80601f016020809104026020016040519081016040528092919081815260200182805461097190611cda565b80156109be5780601f10610993576101008083540402835291602001916109be565b820191906000526020600020905b8154815290600101906020018083116109a157829003601f168201915b50505050509450965096509650965096509650965090919293949596565b6109e4610afb565b6109ed8161113d565b50565b60028390556003610a018382611d7b565b506004610a0e8282611d7b565b508151600003610a59576001600560048282829054906101000a900463ffffffff16610a3a9190611f5c565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b805115610aa15760016005600c8282829054906101000a900463ffffffff16610a829190611f5c565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b815115801590610ab057508051155b15610af6576001600560088282829054906101000a900463ffffffff16610ad79190611f5c565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610b7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016104c8565b565b610b8b8260008084611232565b5050565b8051600003610bca576040517fe889636f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016020830152608090910152565b8051600003610c14576040517ffe936cb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a090910152565b60606000610c2b6101006112c9565b9050610c756040518060400160405280600c81526020017f636f64654c6f636174696f6e0000000000000000000000000000000000000000815250826112ea90919063ffffffff16565b8251610c93906002811115610c8c57610c8c611fb8565b8290611303565b60408051808201909152600881527f6c616e67756167650000000000000000000000000000000000000000000000006020820152610cd29082906112ea565b6040830151610ce9908015610c8c57610c8c611fb8565b60408051808201909152600681527f736f7572636500000000000000000000000000000000000000000000000000006020820152610d289082906112ea565b6060830151610d389082906112ea565b60a08301515115610de55760408051808201909152600481527f61726773000000000000000000000000000000000000000000000000000000006020820152610d829082906112ea565b610d8b8161133c565b60005b8360a0015151811015610ddb57610dcb8460a001518281518110610db457610db4611fe7565b6020026020010151836112ea90919063ffffffff16565b610dd481611f80565b9050610d8e565b50610de581611360565b60808301515115610ee657600083602001516002811115610e0857610e08611fb8565b03610e3f576040517fa80d31f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201909152600f81527f736563726574734c6f636174696f6e00000000000000000000000000000000006020820152610e7e9082906112ea565b610e9783602001516002811115610c8c57610c8c611fb8565b60408051808201909152600781527f73656372657473000000000000000000000000000000000000000000000000006020820152610ed69082906112ea565b6080830151610ee690829061137e565b60c08301515115610f935760408051808201909152600981527f62797465734172677300000000000000000000000000000000000000000000006020820152610f309082906112ea565b610f398161133c565b60005b8360c0015151811015610f8957610f798460c001518281518110610f6257610f62611fe7565b60200260200101518361137e90919063ffffffff16565b610f8281611f80565b9050610f3c565b50610f9381611360565b515192915050565b6000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663461d27628688600188886040518663ffffffff1660e01b8152600401611000959493929190612016565b6020604051808303816000875af115801561101f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110439190612060565b60405190915081907f1131472297a800fee664d1d89cfa8f7676ff07189ecc53f80bbb5f4969099db890600090a295945050505050565b60006110876101006112c9565b90506110d16040518060400160405280600681526020017f736c6f7449440000000000000000000000000000000000000000000000000000815250826112ea90919063ffffffff16565b6110de8160ff851661138b565b60408051808201909152600781527f76657273696f6e00000000000000000000000000000000000000000000000000602082015261111d9082906112ea565b611127818361138b565b6002602085015251516080909301929092525050565b3373ffffffffffffffffffffffffffffffffffffffff8216036111bc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016104c8565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b805160000361126d576040517f22ce3edd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8383600281111561128057611280611fb8565b9081600281111561129357611293611fb8565b905250604084018280156112a9576112a9611fb8565b908180156112b9576112b9611fb8565b9052506060909301929092525050565b6112d161176b565b80516112dd9083611397565b5060006020820152919050565b6112f78260038351611411565b8151610af69082611538565b81516113109060c2611560565b50610b8b828260405160200161132891815260200190565b60405160208183030381529060405261137e565b6113478160046115c9565b60018160200181815161135a9190612079565b90525050565b61136b8160076115c9565b60018160200181815161135a919061208c565b6112f78260028351611411565b610b8b82600083611411565b6040805180820190915260608152600060208201526113b760208361209f565b156113df576113c760208361209f565b6113d290602061208c565b6113dc9083612079565b91505b60208084018390526040518085526000815290818401018181101561140357600080fd5b604052508290505b92915050565b60178167ffffffffffffffff161161143e5782516114389060e0600585901b168317611560565b50505050565b60ff8167ffffffffffffffff1611611480578251611467906018611fe0600586901b1617611560565b5082516114389067ffffffffffffffff831660016115e0565b61ffff8167ffffffffffffffff16116114c35782516114aa906019611fe0600586901b1617611560565b5082516114389067ffffffffffffffff831660026115e0565b63ffffffff8167ffffffffffffffff16116115085782516114ef90601a611fe0600586901b1617611560565b5082516114389067ffffffffffffffff831660046115e0565b825161151f90601b611fe0600586901b1617611560565b5082516114389067ffffffffffffffff831660086115e0565b60408051808201909152606081526000602082015261155983838451611665565b9392505050565b6040805180820190915260608152600060208201528251516000611585826001612079565b9050846020015182106115a6576115a6856115a18360026120da565b611754565b84516020838201018581535080518211156115bf578181525b5093949350505050565b8151610af690601f611fe0600585901b1617611560565b60408051808201909152606081526000602082015283515160006116048285612079565b9050856020015181111561162157611621866115a18360026120da565b6000600161163186610100612211565b61163b919061208c565b90508651828101878319825116178152508051831115611659578281525b50959695505050505050565b604080518082019091526060815260006020820152825182111561168857600080fd5b83515160006116978483612079565b905085602001518111156116b4576116b4866115a18360026120da565b8551805183820160200191600091808511156116ce578482525b505050602086015b6020861061170e57805182526116ed602083612079565b91506116fa602082612079565b905061170760208761208c565b95506116d6565b5181517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60208890036101000a0190811690199190911617905250849150509392505050565b81516117608383611397565b506114388382611538565b6040518060400160405280611793604051806040016040528060608152602001600081525090565b8152602001600081525090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611816576118166117a0565b604052919050565b600067ffffffffffffffff831115611838576118386117a0565b61186960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116016117cf565b905082815283838301111561187d57600080fd5b828260208301376000602084830101529392505050565b600082601f8301126118a557600080fd5b6115598383356020850161181e565b6000806000606084860312156118c957600080fd5b83359250602084013567ffffffffffffffff808211156118e857600080fd5b6118f487838801611894565b9350604086013591508082111561190a57600080fd5b5061191786828701611894565b9150509250925092565b6000815180845260005b818110156119475760208185018101518683018201520161192b565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006115596020830184611921565b803563ffffffff811681146119ac57600080fd5b919050565b60008083601f8401126119c357600080fd5b50813567ffffffffffffffff8111156119db57600080fd5b6020830191508360208285010111156119f357600080fd5b9250929050565b60008083601f840112611a0c57600080fd5b50813567ffffffffffffffff811115611a2457600080fd5b6020830191508360208260051b85010111156119f357600080fd5b803567ffffffffffffffff811681146119ac57600080fd5b600080600080600080600080600060c08a8c031215611a7557600080fd5b611a7e8a611998565b985060208a013567ffffffffffffffff80821115611a9b57600080fd5b611aa78d838e016119b1565b909a50985060408c0135915080821115611ac057600080fd5b611acc8d838e016119b1565b909850965060608c0135915080821115611ae557600080fd5b50611af28c828d016119fa565b9095509350611b05905060808b01611a3f565b915060a08a013590509295985092959850929598565b600080600080600080600080600060e08a8c031215611b3957600080fd5b611b428a611998565b985060208a013567ffffffffffffffff80821115611b5f57600080fd5b611b6b8d838e016119b1565b909a50985060408c0135915060ff82168214611b8657600080fd5b819750611b9560608d01611a3f565b965060808c0135915080821115611bab57600080fd5b50611bb88c828d016119fa565b9095509350611bcb905060a08b01611a3f565b915060c08a013590509295985092959850929598565b60008060008060808587031215611bf757600080fd5b611c0085611998565b9350602085013567ffffffffffffffff811115611c1c57600080fd5b611c2887828801611894565b935050611c3760408601611a3f565b9396929550929360600135925050565b87815260e060208201526000611c6060e0830189611921565b8281036040840152611c728189611921565b63ffffffff97881660608501529587166080840152505091841660a083015290921660c0909201919091529392505050565b600060208284031215611cb657600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461155957600080fd5b600181811c90821680611cee57607f821691505b602082108103611d27577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115610af657600081815260208120601f850160051c81016020861015611d545750805b601f850160051c820191505b81811015611d7357828155600101611d60565b505050505050565b815167ffffffffffffffff811115611d9557611d956117a0565b611da981611da38454611cda565b84611d2d565b602080601f831160018114611dfc5760008415611dc65750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555611d73565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015611e4957888601518255948401946001909101908401611e2a565b5085821015611e8557878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600067ffffffffffffffff80841115611eb057611eb06117a0565b8360051b6020611ec18183016117cf565b868152918501918181019036841115611ed957600080fd5b865b84811015611f2157803586811115611ef35760008081fd5b880136601f820112611f055760008081fd5b611f1336823587840161181e565b845250918301918301611edb565b50979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b63ffffffff818116838216019080821115611f7957611f79611f2d565b5092915050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611fb157611fb1611f2d565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b67ffffffffffffffff8616815260a06020820152600061203960a0830187611921565b61ffff9590951660408301525063ffffffff92909216606083015260809091015292915050565b60006020828403121561207257600080fd5b5051919050565b8082018082111561140b5761140b611f2d565b8181038181111561140b5761140b611f2d565b6000826120d5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b808202811582820484141761140b5761140b611f2d565b600181815b8085111561214a57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561213057612130611f2d565b8085161561213d57918102915b93841c93908002906120f6565b509250929050565b6000826121615750600161140b565b8161216e5750600061140b565b8160018114612184576002811461218e576121aa565b600191505061140b565b60ff84111561219f5761219f611f2d565b50506001821b61140b565b5060208310610133831016604e8410600b84101617156121cd575081810a61140b565b6121d783836120f1565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561220957612209611f2d565b029392505050565b6000611559838361215256fea164736f6c6343000813000a", } var FunctionsLoadTestClientABI = FunctionsLoadTestClientMetaData.ABI diff --git a/core/gethwrappers/functions/generated/functions_router/functions_router.go b/core/gethwrappers/functions/generated/functions_router/functions_router.go index 83c3f9b6132..2c482048c49 100644 --- a/core/gethwrappers/functions/generated/functions_router/functions_router.go +++ b/core/gethwrappers/functions/generated/functions_router/functions_router.go @@ -45,11 +45,13 @@ type FunctionsResponseCommitment struct { } type FunctionsRouterConfig struct { - MaxConsumersPerSubscription uint16 - AdminFee *big.Int - HandleOracleFulfillmentSelector [4]byte - GasForCallExactCheck uint16 - MaxCallbackGasLimits []uint32 + MaxConsumersPerSubscription uint16 + AdminFee *big.Int + HandleOracleFulfillmentSelector [4]byte + GasForCallExactCheck uint16 + MaxCallbackGasLimits []uint32 + SubscriptionDepositMinimumRequests uint16 + SubscriptionDepositJuels *big.Int } type IFunctionsSubscriptionsConsumer struct { @@ -68,8 +70,8 @@ type IFunctionsSubscriptionsSubscription struct { } var FunctionsRouterMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CannotRemoveWithPendingRequests\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyRequestData\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"limit\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"IdentifierIsReserved\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"currentBalanceJuels\",\"type\":\"uint96\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"value\",\"type\":\"uint8\"}],\"name\":\"InvalidGasFlagValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidProposal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeProposedOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeSubscriptionOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RouteNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderMustAcceptTermsOfService\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TimeoutNotExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"maximumConsumers\",\"type\":\"uint16\"}],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"totalBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deductionAttempt\",\"type\":\"uint256\"}],\"name\":\"TotalBalanceInvariantViolated\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"}],\"indexed\":false,\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"proposedContractSetId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proposedContractSetFromAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proposedContractSetToAddress\",\"type\":\"address\"}],\"name\":\"ContractProposed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"ContractUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"}],\"name\":\"RequestNotProcessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalCostJuels\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"callbackReturnData\",\"type\":\"bytes\"}],\"name\":\"RequestProcessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"}],\"name\":\"RequestStart\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"RequestTimedOut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"fundsRecipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fundsAmount\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_CALLBACK_RETURN_BYTES\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"createSubscriptionWithConsumer\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"juelsPerGas\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"costWithoutCallback\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"fulfill\",\"outputs\":[{\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"},{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getConsumer\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"}],\"internalType\":\"structIFunctionsSubscriptions.Consumer\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"getContractById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getFlags\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"getProposedContractById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getProposedContractSet\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getSubscription\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"blockedBalance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"internalType\":\"structIFunctionsSubscriptions.Subscription\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSubscriptionCount\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTotalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"}],\"name\":\"isValidCallbackGasLimit\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"ownerWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"proposedContractSetIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"proposedContractSetAddresses\",\"type\":\"address[]\"}],\"name\":\"proposeContractsUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"proposeSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequest\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequestToProposed\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"allowListId\",\"type\":\"bytes32\"}],\"name\":\"setAllowListId\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"name\":\"setFlags\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment[]\",\"name\":\"requestsToTimeoutByCommitment\",\"type\":\"tuple[]\"}],\"name\":\"timeoutRequests\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"updateContracts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162006254380380620062548339810160408190526200003491620004df565b6001600160a01b0382166080526006805460ff191690553380600081620000a25760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600680546001600160a01b0380851661010002610100600160a81b031990921691909117909155811615620000dc57620000dc81620000f8565b505050620000f081620001aa60201b60201c565b50506200067b565b336001600160a01b03821603620001525760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000099565b600780546001600160a01b0319166001600160a01b03838116918217909255600654604051919261010090910416907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b620001b462000287565b8051600a80546020808501516040860151606087015161ffff908116600160781b0261ffff60781b1960e09390931c6b010000000000000000000000029290921665ffffffffffff60581b196001600160481b0390941662010000026001600160581b031990961691909716179390931716939093171781556080830151805184936200024792600b92910190620002ea565b509050507f049ce2e6e1420eb4b07b425e90129186833eb346bda40b37d5d921aad482f71c816040516200027c9190620005dd565b60405180910390a150565b60065461010090046001600160a01b03163314620002e85760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000099565b565b828054828255906000526020600020906007016008900481019282156200038e5791602002820160005b838211156200035a57835183826101000a81548163ffffffff021916908363ffffffff160217905550926020019260040160208160030104928301926001030262000314565b80156200038c5782816101000a81549063ffffffff02191690556004016020816003010492830192600103026200035a565b505b506200039c929150620003a0565b5090565b5b808211156200039c5760008155600101620003a1565b634e487b7160e01b600052604160045260246000fd5b60405160a081016001600160401b0381118282101715620003f257620003f2620003b7565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620004235762000423620003b7565b604052919050565b805161ffff811681146200043e57600080fd5b919050565b600082601f8301126200045557600080fd5b815160206001600160401b03821115620004735762000473620003b7565b8160051b62000484828201620003f8565b92835284810182019282810190878511156200049f57600080fd5b83870192505b84831015620004d457825163ffffffff81168114620004c45760008081fd5b82529183019190830190620004a5565b979650505050505050565b60008060408385031215620004f357600080fd5b82516001600160a01b03811681146200050b57600080fd5b60208401519092506001600160401b03808211156200052957600080fd5b9084019060a082870312156200053e57600080fd5b62000548620003cd565b62000553836200042b565b815260208301516001600160481b03811681146200057057600080fd5b602082015260408301516001600160e01b0319811681146200059157600080fd5b6040820152620005a4606084016200042b565b6060820152608083015182811115620005bc57600080fd5b620005ca8882860162000443565b6080830152508093505050509250929050565b6020808252825161ffff90811683830152838201516001600160481b03166040808501919091528401516001600160e01b0319166060808501919091528401511660808084019190915283015160a080840152805160c0840181905260009291820190839060e08601905b808310156200067057835163ffffffff16825292840192600192909201919084019062000648565b509695505050505050565b608051615ba1620006b3600039600081816113b40152818161218701528181612a7f01528181612b4301526132be0152615ba16000f3fe608060405234801561001057600080fd5b50600436106102de5760003560e01c80637341c10c11610186578063aab396bd116100e3578063d7ae1d3011610097578063e82ad7d411610071578063e82ad7d4146106bf578063ea320e0b146106d2578063f2fde38b146106e557600080fd5b8063d7ae1d3014610686578063e72f6e3014610699578063e82622aa146106ac57600080fd5b8063badc3eb6116100c8578063badc3eb614610648578063c3f909d41461065e578063cc77470a1461067357600080fd5b8063aab396bd14610638578063b734c0f41461064057600080fd5b80639f87fad71161013a578063a47c76961161011f578063a47c7696146105f2578063a4c0ed3614610612578063a9c9a9181461062557600080fd5b80639f87fad7146105d7578063a21a23e4146105ea57600080fd5b8063823597401161016b57806382359740146105995780638456cb59146105ac5780638da5cb5b146105b457600080fd5b80637341c10c1461057e57806379ba50971461059157600080fd5b80633f4ba83a1161023f5780635c975abb116101f357806366419970116101cd57806366419970146104d6578063674603d0146104fd5780636a2215de1461054657600080fd5b80635c975abb146104995780635ed6dfba146104b057806366316d8d146104c357600080fd5b8063461d276211610224578063461d2762146104455780634b8832d31461045857806355fedefa1461046b57600080fd5b80633f4ba83a1461041c57806341db4ca31461042457600080fd5b80631ded3b36116102965780632a905ccc1161027b5780632a905ccc146103ba57806333060529146103e85780633e871e4d1461040957600080fd5b80631ded3b361461039457806321b60e7f146103a757600080fd5b806310fc49c1116102c757806310fc49c11461031857806312b583491461032b578063181f5a771461034b57600080fd5b806302bcc5b6146102e35780630c5d49cb146102f8575b600080fd5b6102f66102f136600461487a565b6106f8565b005b610300608481565b60405161ffff90911681526020015b60405180910390f35b6102f66103263660046148bb565b610757565b6000546040516bffffffffffffffffffffffff909116815260200161030f565b6103876040518060400160405280601781526020017f46756e6374696f6e7320526f757465722076312e302e3000000000000000000081525081565b60405161030f9190614962565b6102f66103a2366004614975565b610853565b6102f66103b5366004614b38565b610885565b600a5462010000900468ffffffffffffffffff1660405168ffffffffffffffffff909116815260200161030f565b6103fb6103f6366004614de4565b6109b2565b60405161030f929190614ecc565b6102f6610417366004614f59565b610d8a565b6102f661100f565b61043761043236600461505b565b611021565b60405190815260200161030f565b61043761045336600461505b565b611081565b6102f66104663660046150df565b61108d565b61043761047936600461487a565b67ffffffffffffffff166000908152600360208190526040909120015490565b60065460ff165b604051901515815260200161030f565b6102f66104be36600461510d565b6111db565b6102f66104d136600461510d565b6113fd565b60025467ffffffffffffffff165b60405167ffffffffffffffff909116815260200161030f565b61051061050b36600461513b565b61154f565b6040805182511515815260208084015167ffffffffffffffff90811691830191909152928201519092169082015260600161030f565b610559610554366004615169565b6115df565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161030f565b6102f661058c3660046150df565b61169e565b6102f6611852565b6102f66105a736600461487a565b611979565b6102f6611ac0565b600654610100900473ffffffffffffffffffffffffffffffffffffffff16610559565b6102f66105e53660046150df565b611ad0565b6104e4611ea5565b61060561060036600461487a565b612032565b60405161030f91906151d3565b6102f661062036600461525b565b612167565b610559610633366004615169565b6123b3565b600954610437565b6102f6612412565b61065061255e565b60405161030f9291906152b7565b61066661262e565b60405161030f919061530e565b6104e46106813660046153b8565b612763565b6102f66106943660046150df565b6129e3565b6102f66106a73660046153b8565b612a46565b6102f66106ba3660046153d5565b612bbf565b6104a06106cd36600461487a565b612e90565b6102f66106e0366004615169565b612fdf565b6102f66106f33660046153b8565b612fec565b610700612ffd565b61070981613005565b67ffffffffffffffff81166000908152600360205260409020546107549082906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1661307b565b50565b67ffffffffffffffff8216600090815260036020819052604082200154600b54911a9081106107bc576040517f45c108ce00000000000000000000000000000000000000000000000000000000815260ff821660048201526024015b60405180910390fd5b6000600a6001018260ff16815481106107d7576107d761544b565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1690508063ffffffff168363ffffffff16111561084d576040517f1d70f87a00000000000000000000000000000000000000000000000000000000815263ffffffff821660048201526024016107b3565b50505050565b61085b612ffd565b61086482613005565b67ffffffffffffffff90911660009081526003602081905260409091200155565b61088d613367565b8051600a80546020808501516040860151606087015161ffff9081166f01000000000000000000000000000000027fffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffff60e09390931c6b01000000000000000000000002929092167fffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffff68ffffffffffffffffff90941662010000027fffffffffffffffffffffffffffffffffffffffffff0000000000000000000000909616919097161793909317169390931717815560808301518051849361097492600b929101906146c5565b509050507f049ce2e6e1420eb4b07b425e90129186833eb346bda40b37d5d921aad482f71c816040516109a7919061530e565b60405180910390a150565b6000806109bd6133ed565b826020015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a26576040517f8bec23e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8251600090815260056020526040902054610a885782516020840151604051600294507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610a78918890879061547a565b60405180910390a2506000610d7f565b8251600090815260056020908152604091829020549151610aab918691016154ac565b6040516020818303038152906040528051906020012014610b035782516020840151604051600694507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610a78918890879061547a565b8261012001518360a0015163ffffffff16610b1e9190615608565b64ffffffffff165a1015610b695782516020840151604051600494507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610a78918890879061547a565b6000610b7e8460a0015163ffffffff166133f5565b610b88908861562d565b9050600081878660c0015168ffffffffffffffffff16610ba89190615655565b610bb29190615655565b9050610bc18560800151612032565b600001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610c395784516020860151604051600596507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610c25918a90899061547a565b60405180910390a25060009150610d7f9050565b84604001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610c9e5784516020860151604051600396507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610c25918a90899061547a565b505082516000908152600560205260408120819055835160a08501516060860151610cce92918c918c9190613497565b8051909150610cde576001610ce1565b60005b92506000610d1b8560800151866040015187606001518860c0015168ffffffffffffffffff168c610d1588602001516133f5565b8d613626565b9050846080015167ffffffffffffffff1685600001517f64778f26c70b60a8d7e29e2451b3844302d959448401c0535b768ed88c6b505e836020015189888f8f8960400151604051610d729695949392919061567a565b60405180910390a3519150505b965096945050505050565b610d92613367565b8151815181141580610da45750600881115b15610ddb576040517fee03280800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610ecd576000848281518110610dfa57610dfa61544b565b602002602001015190506000848381518110610e1857610e1861544b565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161480610e83575060008281526008602052604090205473ffffffffffffffffffffffffffffffffffffffff8281169116145b15610eba576040517fee03280800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505080610ec6906156fd565b9050610dde565b506040805180820190915283815260208082018490528451600c91610ef6918391880190614770565b506020828101518051610f0f92600185019201906147ab565b5090505060005b835181101561084d577f8b052f0f4bf82fede7daffea71592b29d5ef86af1f3c7daaa0345dbb2f52f481848281518110610f5257610f5261544b565b602002602001015160086000878581518110610f7057610f7061544b565b6020026020010151815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16858481518110610fb957610fb961544b565b6020026020010151604051610ff79392919092835273ffffffffffffffffffffffffffffffffffffffff918216602084015216604082015260600190565b60405180910390a1611008816156fd565b9050610f16565b611017613367565b61101f6139a8565b565b60008061102d836115df565b905061107583828a8a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508c92508b9150613a259050565b98975050505050505050565b60008061102d836123b3565b6110956133ed565b61109e82613dce565b6110a6613e94565b73ffffffffffffffffffffffffffffffffffffffff8116158061110d575067ffffffffffffffff821660009081526003602052604090206001015473ffffffffffffffffffffffffffffffffffffffff8281166c0100000000000000000000000090920416145b15611144576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff821660008181526003602090815260409182902060010180546bffffffffffffffffffffffff166c0100000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8716908102919091179091558251338152918201527f69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be910160405180910390a25050565b6111e3612ffd565b806bffffffffffffffffffffffff166000036112195750306000908152600160205260409020546bffffffffffffffffffffffff165b306000908152600160205260409020546bffffffffffffffffffffffff908116908216811015611285576040517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff821660048201526024016107b3565b6000546bffffffffffffffffffffffff808416911610156112ee576000546040517fdda2b2160000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff918216600482015290831660248201526044016107b3565b306000908152600160205260408120805484929061131b9084906bffffffffffffffffffffffff16615735565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550816000808282829054906101000a90046bffffffffffffffffffffffff166113719190615735565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506113f883836bffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16613f9e9092919063ffffffff16565b505050565b6114056133ed565b806bffffffffffffffffffffffff1660000361144d576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600160205260409020546bffffffffffffffffffffffff9081169082168110156114b9576040517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff821660048201526024016107b3565b6000546bffffffffffffffffffffffff80841691161015611522576000546040517fdda2b2160000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff918216600482015290831660248201526044016107b3565b336000908152600160205260408120805484929061131b9084906bffffffffffffffffffffffff16615735565b60408051606080820183526000808352602080840182905292840181905273ffffffffffffffffffffffffffffffffffffffff861681526004835283812067ffffffffffffffff868116835290845290849020845192830185525460ff81161515835261010081048216938301939093526901000000000000000000909204909116918101919091525b92915050565b6000805b600c5460ff8216101561166857600c805460ff83169081106116075761160761544b565b9060005260206000200154830361165857600d805460ff831690811061162f5761162f61544b565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff169392505050565b6116618161575a565b90506115e3565b506040517f80833e33000000000000000000000000000000000000000000000000000000008152600481018390526024016107b3565b6116a66133ed565b6116af82613dce565b6116b7613e94565b60006116c6600a5461ffff1690565b67ffffffffffffffff841660009081526003602052604090206002015490915061ffff82169003611729576040517fb72bc70300000000000000000000000000000000000000000000000000000000815261ffff821660048201526024016107b3565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020908152604080832067ffffffffffffffff8716845290915290205460ff161561177157505050565b73ffffffffffffffffffffffffffffffffffffffff8216600081815260046020908152604080832067ffffffffffffffff881680855290835281842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155600384528285206002018054918201815585529383902090930180547fffffffffffffffffffffffff000000000000000000000000000000000000000016851790555192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e091015b60405180910390a2505050565b60075473ffffffffffffffffffffffffffffffffffffffff1633146118d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016107b3565b600680547fffffffffffffffffffffff0000000000000000000000000000000000000000ff81166101003381810292909217909355600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556040519290910473ffffffffffffffffffffffffffffffffffffffff169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6119816133ed565b611989613e94565b67ffffffffffffffff81166000908152600360205260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481169290910416338114611a29576040517f4e1d9f1800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016107b3565b67ffffffffffffffff831660008181526003602090815260409182902080546c01000000000000000000000000339081026bffffffffffffffffffffffff928316178355600190920180549091169055825173ffffffffffffffffffffffffffffffffffffffff87168152918201527f6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f09101611845565b611ac8613367565b61101f61402b565b611ad86133ed565b611ae182613dce565b611ae9613e94565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260046020908152604080832067ffffffffffffffff8087168552908352928190208151606081018352905460ff8116151580835261010082048616948301949094526901000000000000000000900490931690830152611b91576040517f71e8313700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806040015167ffffffffffffffff16816020015167ffffffffffffffff1614611be6576040517f06eb10c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8316600090815260036020908152604080832060020180548251818502810185019093528083529192909190830182828015611c6157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611c36575b5050505050905060005b8151811015611e09578373ffffffffffffffffffffffffffffffffffffffff16828281518110611c9d57611c9d61544b565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611df9578160018351611ccf9190615779565b81518110611cdf57611cdf61544b565b6020026020010151600360008767ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000206002018281548110611d2257611d2261544b565b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff949094169390931790925567ffffffffffffffff87168152600390915260409020600201805480611d9c57611d9c61578c565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055611e09565b611e02816156fd565b9050611c6b565b5073ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832067ffffffffffffffff89168085529083529281902080547fffffffffffffffffffffffffffffff00000000000000000000000000000000001690555192835290917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b91015b60405180910390a250505050565b6000611eaf6133ed565b611eb7613e94565b60028054600090611ed19067ffffffffffffffff166157bb565b825467ffffffffffffffff8083166101009490940a93840293021916919091179091556040805160c0810182526000808252336020830152918101829052606081018290529192506080820190604051908082528060200260200182016040528015611f47578160200160208202803683370190505b5081526000602091820181905267ffffffffffffffff841681526003825260409081902083518484015173ffffffffffffffffffffffffffffffffffffffff9081166c010000000000000000000000009081026bffffffffffffffffffffffff9384161784559386015160608701519091169093029216919091176001820155608083015180519192611fe2926002850192909101906147ab565b5060a0919091015160039091015560405133815267ffffffffffffffff8216907f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf9060200160405180910390a290565b6040805160c0810182526000808252602082018190529181018290526060808201839052608082015260a081019190915261206c82613005565b67ffffffffffffffff8216600090815260036020908152604091829020825160c08101845281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811684870152600185015491821684880152919004166060820152600282018054855181860281018601909652808652919492936080860193929083018282801561214d57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612122575b505050505081526020016003820154815250509050919050565b61216f6133ed565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146121de576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208114612218576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006122268284018461487a565b67ffffffffffffffff81166000908152600360205260409020549091506c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1661229f576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8116600090815260036020526040812080546bffffffffffffffffffffffff16918691906122d68385615655565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550846000808282829054906101000a90046bffffffffffffffffffffffff1661232c9190615655565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508167ffffffffffffffff167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f882878461239391906157e2565b6040805192835260208301919091520160405180910390a2505050505050565b60008181526008602052604081205473ffffffffffffffffffffffffffffffffffffffff16806115d9576040517f80833e33000000000000000000000000000000000000000000000000000000008152600481018490526024016107b3565b61241a613367565b60005b600c5481101561253d576000600c600001828154811061243f5761243f61544b565b906000526020600020015490506000600c60010183815481106124645761246461544b565b6000918252602080832091909101548483526008825260409283902054835186815273ffffffffffffffffffffffffffffffffffffffff91821693810193909352169181018290529091507ff8a6175bca1ba37d682089187edc5e20a859989727f10ca6bd9a5bc0de8caf949060600160405180910390a160009182526008602052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055612536816156fd565b905061241d565b50600c600061254c8282614825565b61255a600183016000614825565b5050565b606080600c600001600c600101818054806020026020016040519081016040528092919081815260200182805480156125b657602002820191906000526020600020905b8154815260200190600101908083116125a2575b505050505091508080548060200260200160405190810160405280929190818152602001828054801561261f57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116125f4575b50505050509050915091509091565b6040805160a08101825260008082526020820181905291810182905260608082019290925260808101919091526040805160a081018252600a805461ffff808216845268ffffffffffffffffff620100008304166020808601919091527fffffffff000000000000000000000000000000000000000000000000000000006b010000000000000000000000840460e01b16858701526f01000000000000000000000000000000909204166060840152600b80548551818402810184019096528086529394929360808601939283018282801561275557602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116127185790505b505050505081525050905090565b600061276d6133ed565b612775613e94565b6002805460009061278f9067ffffffffffffffff166157bb565b825467ffffffffffffffff8083166101009490940a93840293021916919091179091556040805160c0810182526000808252336020830152918101829052606081018290529192506080820190604051908082528060200260200182016040528015612805578160200160208202803683370190505b5081526000602091820181905267ffffffffffffffff841681526003825260409081902083518484015173ffffffffffffffffffffffffffffffffffffffff9081166c010000000000000000000000009081026bffffffffffffffffffffffff93841617845593860151606087015190911690930292169190911760018201556080830151805191926128a0926002850192909101906147ab565b5060a0919091015160039182015567ffffffffffffffff82166000818152602092835260408082206002018054600180820183559184528584200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff891690811790915583526004855281832084845285529181902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169092179091555133815290917f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf910160405180910390a260405173ffffffffffffffffffffffffffffffffffffffff8316815267ffffffffffffffff8216907f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e09060200160405180910390a2919050565b6129eb6133ed565b6129f482613dce565b6129fc613e94565b612a0582612e90565b15612a3c576040517f06eb10c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61255a828261307b565b612a4e612ffd565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612adb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aff91906157f5565b6000549091506bffffffffffffffffffffffff16818110156113f8576000612b278284615779565b9050612b6a73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168583613f9e565b6040805173ffffffffffffffffffffffffffffffffffffffff86168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a150505050565b612bc76133ed565b60005b818110156113f8576000838383818110612be657612be661544b565b90506101600201803603810190612bfd919061580e565b80516080820151600082815260056020908152604091829020549151949550929391929091612c2e918691016154ac565b6040516020818303038152906040528051906020012014612c7b576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015163ffffffff16421015612cc0576040517fa2376fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516040517f85b214cf0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff909116906385b214cf906024016020604051808303816000875af1158015612d33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d57919061582b565b5060408084015167ffffffffffffffff831660009081526003602052918220600101805491929091612d989084906bffffffffffffffffffffffff16615735565b82546bffffffffffffffffffffffff9182166101009390930a928302919092021990911617905550606083015173ffffffffffffffffffffffffffffffffffffffff16600090815260046020908152604080832067ffffffffffffffff808616855292529091208054600192600991612e20918591690100000000000000000090041661584d565b825467ffffffffffffffff9182166101009390930a9283029190920219909116179055506000828152600560205260408082208290555183917ff1ca1e9147be737b04a2b018a79405f687a97de8dd8a2559bbe62357343af41491a250505080612e89906156fd565b9050612bca565b67ffffffffffffffff8116600090815260036020908152604080832060020180548251818502810185019093528083528493830182828015612f0857602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612edd575b5050505050905060005b8151811015612fd557600060046000848481518110612f3357612f3361544b565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040908101600090812067ffffffffffffffff808a168352908452908290208251606081018452905460ff8116151582526101008104831694820185905269010000000000000000009004909116918101829052925014612fc457506001949350505050565b50612fce816156fd565b9050612f12565b5060009392505050565b612fe7613367565b600955565b612ff4613367565b61075481614086565b61101f613367565b67ffffffffffffffff81166000908152600360205260409020546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16610754576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff82166000908152600360209081526040808320815160c08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481168488015260018501549182168487015291900416606082015260028201805484518187028101870190955280855291949293608086019390929083018282801561315c57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311613131575b505050918352505060039190910154602090910152805190915060005b82608001515181101561321d5760046000846080015183815181106131a0576131a061544b565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040908101600090812067ffffffffffffffff89168252909252902080547fffffffffffffffffffffffffffffff0000000000000000000000000000000000169055613216816156fd565b9050613179565b5067ffffffffffffffff84166000908152600360205260408120818155600181018290559061324f6002830182614825565b5060006003919091018190558054829190819061327b9084906bffffffffffffffffffffffff16615735565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061330283826bffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16613f9e9092919063ffffffff16565b6040805173ffffffffffffffffffffffffffffffffffffffff851681526bffffffffffffffffffffffff8316602082015267ffffffffffffffff8616917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd498159101611e97565b600654610100900473ffffffffffffffffffffffffffffffffffffffff16331461101f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016107b3565b61101f614182565b60006bffffffffffffffffffffffff821115613493576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f362062697473000000000000000000000000000000000000000000000000000060648201526084016107b3565b5090565b60408051606080820183526000808352602083015291810191909152600a546040516000916b010000000000000000000000900460e01b906134e19089908990899060240161586e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009590951694909417909352600a548151608480825260c0820190935292945061ffff6f0100000000000000000000000000000090910416926000928392839282018180368337019050509050863b6135ac57600080fd5b5a848110156135ba57600080fd5b84900360408104810389106135ce57600080fd5b505a60008087516020890160008c8ef193505a900391503d60848111156135f3575060845b808252806000602084013e5060408051606081018252931515845260208401929092529082015298975050505050505050565b60408051808201909152600080825260208201526000613646848661562d565b90506000816136558886615655565b61365f9190615655565b67ffffffffffffffff8b166000908152600360205260409020549091506bffffffffffffffffffffffff808316911610156136f25767ffffffffffffffff8a16600090815260036020526040908190205490517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff90911660048201526024016107b3565b67ffffffffffffffff8a16600090815260036020526040812080548392906137299084906bffffffffffffffffffffffff16615735565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915567ffffffffffffffff8c166000908152600360205260409020600101548b82169116101590506137d65767ffffffffffffffff8a16600090815260036020526040908190205490517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff90911660048201526024016107b3565b67ffffffffffffffff8a16600090815260036020526040812060010180548b92906138109084906bffffffffffffffffffffffff16615735565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550818461384a9190615655565b33600090815260016020526040812080549091906138779084906bffffffffffffffffffffffff16615655565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915530600090815260016020526040812080548b945090926138be91859116615655565b82546bffffffffffffffffffffffff9182166101009390930a92830291909202199091161790555073ffffffffffffffffffffffffffffffffffffffff8816600090815260046020908152604080832067ffffffffffffffff808f16855292529091208054600192600991613942918591690100000000000000000090041661584d565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040518060400160405280836bffffffffffffffffffffffff168152602001826bffffffffffffffffffffffff1681525092505050979650505050505050565b6139b06141ef565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000613a2f6133ed565b613a3885613005565b613a42338661425b565b613a4c8583610757565b8351600003613a86576040517ec1cfc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000613a9186612032565b90506000613a9f338861154f565b905060008873ffffffffffffffffffffffffffffffffffffffff1663a631571e6040518061016001604052808a8152602001613af58c67ffffffffffffffff166000908152600360208190526040909120015490565b815233602082015260408781015188519190920191613b1391615735565b6bffffffffffffffffffffffff168152602001600a60000160029054906101000a900468ffffffffffffffffff1668ffffffffffffffffff1681526020018b67ffffffffffffffff168152602001856020015167ffffffffffffffff1681526020018863ffffffff1681526020018961ffff168152602001856040015167ffffffffffffffff168152602001866020015173ffffffffffffffffffffffffffffffffffffffff168152506040518263ffffffff1660e01b8152600401613bd99190615899565b610160604051808303816000875af1158015613bf9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c1d91906159fe565b9050604051806101600160405280826000015181526020018a73ffffffffffffffffffffffffffffffffffffffff16815260200182604001516bffffffffffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff1681526020018967ffffffffffffffff1681526020018663ffffffff168152602001600a60000160029054906101000a900468ffffffffffffffffff1668ffffffffffffffffff1681526020018260e0015168ffffffffffffffffff16815260200182610100015164ffffffffff16815260200182610120015164ffffffffff16815260200182610140015163ffffffff16815250604051602001613d2491906154ac565b60405160208183030381529060405280519060200120600560008360000151815260200190815260200160002081905550613d64338983604001516142cf565b8767ffffffffffffffff168a82600001517ff67aec45c9a7ede407974a3e0c3a743dffeab99ee3f2d4c9a8144c2ebf2c7ec9866020015133328d8d8d8a60400151604051613db89796959493929190615ad1565b60405180910390a4519998505050505050505050565b67ffffffffffffffff81166000908152600360205260409020546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1680613e45576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff82161461255a576040517f5a68151d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60095460009081526008602052604090205473ffffffffffffffffffffffffffffffffffffffff1680613ec45750565b604080516000815260208101918290527f6b14daf80000000000000000000000000000000000000000000000000000000090915273ffffffffffffffffffffffffffffffffffffffff821690636b14daf890613f2590339060248101615b49565b602060405180830381865afa158015613f42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f66919061582b565b610754576040517f229062630000000000000000000000000000000000000000000000000000000081523360048201526024016107b3565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526113f89084906143aa565b614033614182565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586139fb3390565b3373ffffffffffffffffffffffffffffffffffffffff821603614105576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016107b3565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600654604051919261010090910416907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b60065460ff161561101f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064016107b3565b60065460ff1661101f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016107b3565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020908152604080832067ffffffffffffffff8516845290915290205460ff1661255a576040517f71e8313700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8216600090815260036020526040812060010180548392906143099084906bffffffffffffffffffffffff16615655565b82546bffffffffffffffffffffffff91821661010093840a908102920219161790915573ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832067ffffffffffffffff808916855292529091208054600194509092849261437f92849290041661584d565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505050565b600061440c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166144b69092919063ffffffff16565b8051909150156113f8578080602001905181019061442a919061582b565b6113f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107b3565b60606144c584846000856144cd565b949350505050565b60608247101561455f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107b3565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516145889190615b78565b60006040518083038185875af1925050503d80600081146145c5576040519150601f19603f3d011682016040523d82523d6000602084013e6145ca565b606091505b50915091506145db878383876145e6565b979650505050505050565b6060831561467c5782516000036146755773ffffffffffffffffffffffffffffffffffffffff85163b614675576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107b3565b50816144c5565b6144c583838151156146915781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107b39190614962565b828054828255906000526020600020906007016008900481019282156147645791602002820160005b8382111561473257835183826101000a81548163ffffffff021916908363ffffffff16021790555092602001926004016020816003010492830192600103026146ee565b80156147625782816101000a81549063ffffffff0219169055600401602081600301049283019260010302614732565b505b5061349392915061483f565b828054828255906000526020600020908101928215614764579160200282015b82811115614764578251825591602001919060010190614790565b828054828255906000526020600020908101928215614764579160200282015b8281111561476457825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020909201916001909101906147cb565b508054600082559060005260206000209081019061075491905b5b808211156134935760008155600101614840565b67ffffffffffffffff8116811461075457600080fd5b803561487581614854565b919050565b60006020828403121561488c57600080fd5b813561489781614854565b9392505050565b63ffffffff8116811461075457600080fd5b80356148758161489e565b600080604083850312156148ce57600080fd5b82356148d981614854565b915060208301356148e98161489e565b809150509250929050565b60005b8381101561490f5781810151838201526020016148f7565b50506000910152565b600081518084526149308160208601602086016148f4565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006148976020830184614918565b6000806040838503121561498857600080fd5b823561499381614854565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff811182821017156149f3576149f36149a1565b60405290565b604051610160810167ffffffffffffffff811182821017156149f3576149f36149a1565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614a6457614a646149a1565b604052919050565b803561ffff8116811461487557600080fd5b68ffffffffffffffffff8116811461075457600080fd5b803561487581614a7e565b600067ffffffffffffffff821115614aba57614aba6149a1565b5060051b60200190565b600082601f830112614ad557600080fd5b81356020614aea614ae583614aa0565b614a1d565b82815260059290921b84018101918181019086841115614b0957600080fd5b8286015b84811015614b2d578035614b208161489e565b8352918301918301614b0d565b509695505050505050565b600060208284031215614b4a57600080fd5b813567ffffffffffffffff80821115614b6257600080fd5b9083019060a08286031215614b7657600080fd5b614b7e6149d0565b614b8783614a6c565b81526020830135614b9781614a7e565b602082015260408301357fffffffff0000000000000000000000000000000000000000000000000000000081168114614bcf57600080fd5b6040820152614be060608401614a6c565b6060820152608083013582811115614bf757600080fd5b614c0387828601614ac4565b60808301525095945050505050565b600082601f830112614c2357600080fd5b813567ffffffffffffffff811115614c3d57614c3d6149a1565b614c6e60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614a1d565b818152846020838601011115614c8357600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff8116811461075457600080fd5b803561487581614ca0565b73ffffffffffffffffffffffffffffffffffffffff8116811461075457600080fd5b803561487581614cc5565b64ffffffffff8116811461075457600080fd5b803561487581614cf2565b60006101608284031215614d2357600080fd5b614d2b6149f9565b905081358152614d3d60208301614ce7565b6020820152614d4e60408301614cba565b6040820152614d5f60608301614ce7565b6060820152614d706080830161486a565b6080820152614d8160a083016148b0565b60a0820152614d9260c08301614a95565b60c0820152614da360e08301614a95565b60e0820152610100614db6818401614d05565b90820152610120614dc8838201614d05565b90820152610140614dda8382016148b0565b9082015292915050565b6000806000806000806102008789031215614dfe57600080fd5b863567ffffffffffffffff80821115614e1657600080fd5b614e228a838b01614c12565b97506020890135915080821115614e3857600080fd5b50614e4589828a01614c12565b9550506040870135614e5681614ca0565b93506060870135614e6681614ca0565b92506080870135614e7681614cc5565b9150614e858860a08901614d10565b90509295509295509295565b60078110614ec8577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60408101614eda8285614e91565b6bffffffffffffffffffffffff831660208301529392505050565b600082601f830112614f0657600080fd5b81356020614f16614ae583614aa0565b82815260059290921b84018101918181019086841115614f3557600080fd5b8286015b84811015614b2d578035614f4c81614cc5565b8352918301918301614f39565b60008060408385031215614f6c57600080fd5b823567ffffffffffffffff80821115614f8457600080fd5b818501915085601f830112614f9857600080fd5b81356020614fa8614ae583614aa0565b82815260059290921b84018101918181019089841115614fc757600080fd5b948201945b83861015614fe557853582529482019490820190614fcc565b96505086013592505080821115614ffb57600080fd5b5061500885828601614ef5565b9150509250929050565b60008083601f84011261502457600080fd5b50813567ffffffffffffffff81111561503c57600080fd5b60208301915083602082850101111561505457600080fd5b9250929050565b60008060008060008060a0878903121561507457600080fd5b863561507f81614854565b9550602087013567ffffffffffffffff81111561509b57600080fd5b6150a789828a01615012565b90965094506150ba905060408801614a6c565b925060608701356150ca8161489e565b80925050608087013590509295509295509295565b600080604083850312156150f257600080fd5b82356150fd81614854565b915060208301356148e981614cc5565b6000806040838503121561512057600080fd5b823561512b81614cc5565b915060208301356148e981614ca0565b6000806040838503121561514e57600080fd5b823561515981614cc5565b915060208301356148e981614854565b60006020828403121561517b57600080fd5b5035919050565b600081518084526020808501945080840160005b838110156151c857815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101615196565b509495945050505050565b6020815260006bffffffffffffffffffffffff808451166020840152602084015173ffffffffffffffffffffffffffffffffffffffff8082166040860152826040870151166060860152806060870151166080860152505050608083015160c060a084015261524560e0840182615182565b905060a084015160c08401528091505092915050565b6000806000806060858703121561527157600080fd5b843561527c81614cc5565b935060208501359250604085013567ffffffffffffffff81111561529f57600080fd5b6152ab87828801615012565b95989497509550505050565b604080825283519082018190526000906020906060840190828701845b828110156152f0578151845292840192908401906001016152d4565b505050838103828501526153048186615182565b9695505050505050565b6000602080835260c0830161ffff808651168386015268ffffffffffffffffff838701511660408601527fffffffff00000000000000000000000000000000000000000000000000000000604087015116606086015280606087015116608086015250608085015160a08086015281815180845260e0870191508483019350600092505b80831015614b2d57835163ffffffff168252928401926001929092019190840190615392565b6000602082840312156153ca57600080fd5b813561489781614cc5565b600080602083850312156153e857600080fd5b823567ffffffffffffffff8082111561540057600080fd5b818501915085601f83011261541457600080fd5b81358181111561542357600080fd5b8660206101608302850101111561543957600080fd5b60209290920196919550909350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff848116825283166020820152606081016144c56040830184614e91565b815181526020808301516101608301916154dd9084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060408301516154fd60408401826bffffffffffffffffffffffff169052565b506060830151615525606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080830151615541608084018267ffffffffffffffff169052565b5060a083015161555960a084018263ffffffff169052565b5060c083015161557660c084018268ffffffffffffffffff169052565b5060e083015161559360e084018268ffffffffffffffffff169052565b506101008381015164ffffffffff81168483015250506101208381015164ffffffffff81168483015250506101408381015163ffffffff8116848301525b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b64ffffffffff818116838216019080821115615626576156266155d9565b5092915050565b6bffffffffffffffffffffffff8181168382160280821691908281146155d1576155d16155d9565b6bffffffffffffffffffffffff818116838216019080821115615626576156266155d9565b6bffffffffffffffffffffffff8716815273ffffffffffffffffffffffffffffffffffffffff861660208201526156b46040820186614e91565b60c0606082015260006156ca60c0830186614918565b82810360808401526156dc8186614918565b905082810360a08401526156f08185614918565b9998505050505050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361572e5761572e6155d9565b5060010190565b6bffffffffffffffffffffffff828116828216039080821115615626576156266155d9565b600060ff821660ff8103615770576157706155d9565b60010192915050565b818103818111156115d9576115d96155d9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600067ffffffffffffffff8083168181036157d8576157d86155d9565b6001019392505050565b808201808211156115d9576115d96155d9565b60006020828403121561580757600080fd5b5051919050565b6000610160828403121561582157600080fd5b6148978383614d10565b60006020828403121561583d57600080fd5b8151801515811461489757600080fd5b67ffffffffffffffff818116838216019080821115615626576156266155d9565b8381526060602082015260006158876060830185614918565b82810360408401526153048185614918565b60208152600082516101608060208501526158b8610180850183614918565b91506020850151604085015260408501516158eb606086018273ffffffffffffffffffffffffffffffffffffffff169052565b5060608501516bffffffffffffffffffffffff8116608086015250608085015168ffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015167ffffffffffffffff811660e08601525060e08501516101006159628187018363ffffffff169052565b86015190506101206159798682018361ffff169052565b86015190506101406159968682018367ffffffffffffffff169052565b9095015173ffffffffffffffffffffffffffffffffffffffff1693019290925250919050565b805161487581614cc5565b805161487581614ca0565b805161487581614854565b80516148758161489e565b805161487581614a7e565b805161487581614cf2565b60006101608284031215615a1157600080fd5b615a196149f9565b82518152615a29602084016159bc565b6020820152615a3a604084016159c7565b6040820152615a4b606084016159bc565b6060820152615a5c608084016159d2565b6080820152615a6d60a084016159dd565b60a0820152615a7e60c084016159e8565b60c0820152615a8f60e084016159e8565b60e0820152610100615aa28185016159f3565b90820152610120615ab48482016159f3565b90820152610140615ac68482016159dd565b908201529392505050565b600073ffffffffffffffffffffffffffffffffffffffff808a168352808916602084015280881660408401525060e06060830152615b1260e0830187614918565b61ffff9590951660808301525063ffffffff9290921660a08301526bffffffffffffffffffffffff1660c090910152949350505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006144c56040830184614918565b60008251615b8a8184602087016148f4565b919091019291505056fea164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CannotRemoveWithPendingRequests\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"DuplicateRequestId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyRequestData\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"limit\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"IdentifierIsReserved\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"currentBalanceJuels\",\"type\":\"uint96\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"value\",\"type\":\"uint8\"}],\"name\":\"InvalidGasFlagValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidProposal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeProposedOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeSubscriptionOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RouteNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderMustAcceptTermsOfService\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TimeoutNotExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"maximumConsumers\",\"type\":\"uint16\"}],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"indexed\":false,\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"proposedContractSetId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proposedContractSetFromAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proposedContractSetToAddress\",\"type\":\"address\"}],\"name\":\"ContractProposed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"ContractUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"}],\"name\":\"RequestNotProcessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalCostJuels\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"callbackReturnData\",\"type\":\"bytes\"}],\"name\":\"RequestProcessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"}],\"name\":\"RequestStart\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"RequestTimedOut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"fundsRecipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fundsAmount\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_CALLBACK_RETURN_BYTES\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"createSubscriptionWithConsumer\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"juelsPerGas\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"costWithoutCallback\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"fulfill\",\"outputs\":[{\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"},{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getConsumer\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"}],\"internalType\":\"structIFunctionsSubscriptions.Consumer\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"getContractById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getFlags\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"getProposedContractById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getProposedContractSet\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getSubscription\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"blockedBalance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"internalType\":\"structIFunctionsSubscriptions.Subscription\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSubscriptionCount\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionIdStart\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionIdEnd\",\"type\":\"uint64\"}],\"name\":\"getSubscriptionsInRange\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"blockedBalance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"internalType\":\"structIFunctionsSubscriptions.Subscription[]\",\"name\":\"subscriptions\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTotalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"}],\"name\":\"isValidCallbackGasLimit\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"ownerWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"proposedContractSetIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"proposedContractSetAddresses\",\"type\":\"address[]\"}],\"name\":\"proposeContractsUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"proposeSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequest\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequestToProposed\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"allowListId\",\"type\":\"bytes32\"}],\"name\":\"setAllowListId\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"name\":\"setFlags\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment[]\",\"name\":\"requestsToTimeoutByCommitment\",\"type\":\"tuple[]\"}],\"name\":\"timeoutRequests\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"updateContracts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b506040516200673c3803806200673c833981016040819052620000349162000549565b6001600160a01b0382166080526006805460ff191690553380600081620000a25760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600680546001600160a01b0380851661010002610100600160a81b031990921691909117909155811615620000dc57620000dc81620000f8565b505050620000f081620001aa60201b60201c565b50506200071a565b336001600160a01b03821603620001525760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000099565b600780546001600160a01b0319166001600160a01b03838116918217909255600654604051919261010090910416907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b620001b4620002c0565b8051600a80546020808501516040860151606087015161ffff908116600160781b0261ffff60781b1960e09390931c6b010000000000000000000000029290921665ffffffffffff60581b196001600160481b0390941662010000026001600160581b031990961691909716179390931716939093171781556080830151805184936200024792600b9291019062000323565b5060a08201516002909101805460c0909301516001600160481b031662010000026001600160581b031990931661ffff909216919091179190911790556040517ea5832bf95f66c7814294cc4db681f20ee79608bfb8912a5321d66cfed5e98590620002b590839062000652565b60405180910390a150565b60065461010090046001600160a01b03163314620003215760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000099565b565b82805482825590600052602060002090600701600890048101928215620003c75791602002820160005b838211156200039357835183826101000a81548163ffffffff021916908363ffffffff16021790555092602001926004016020816003010492830192600103026200034d565b8015620003c55782816101000a81549063ffffffff021916905560040160208160030104928301926001030262000393565b505b50620003d5929150620003d9565b5090565b5b80821115620003d55760008155600101620003da565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b03811182821017156200042b576200042b620003f0565b60405290565b604051601f8201601f191681016001600160401b03811182821017156200045c576200045c620003f0565b604052919050565b805161ffff811681146200047757600080fd5b919050565b80516001600160481b03811681146200047757600080fd5b80516001600160e01b0319811681146200047757600080fd5b600082601f830112620004bf57600080fd5b815160206001600160401b03821115620004dd57620004dd620003f0565b8160051b620004ee82820162000431565b92835284810182019282810190878511156200050957600080fd5b83870192505b848310156200053e57825163ffffffff811681146200052e5760008081fd5b825291830191908301906200050f565b979650505050505050565b600080604083850312156200055d57600080fd5b82516001600160a01b03811681146200057557600080fd5b60208401519092506001600160401b03808211156200059357600080fd5b9084019060e08287031215620005a857600080fd5b620005b262000406565b620005bd8362000464565b8152620005cd602084016200047c565b6020820152620005e06040840162000494565b6040820152620005f36060840162000464565b60608201526080830151828111156200060b57600080fd5b6200061988828601620004ad565b6080830152506200062d60a0840162000464565b60a08201526200064060c084016200047c565b60c08201528093505050509250929050565b6020808252825161ffff90811683830152838201516001600160481b03166040808501919091528401516001600160e01b0319166060808501919091528401511660808084019190915283015160e060a0840152805161010084018190526000929182019083906101208601905b80831015620006e857835163ffffffff168252928401926001929092019190840190620006c0565b5060a087015161ffff811660c0880152935060c08701516001600160481b03811660e088015293509695505050505050565b608051615fea62000752600039600081816111cd0152818161208c015281816129b801528181612a7c01526135d30152615fea6000f3fe608060405234801561001057600080fd5b50600436106102e95760003560e01c80637341c10c11610191578063b734c0f4116100e3578063e72f6e3011610097578063ea320e0b11610071578063ea320e0b146106dd578063ec2454e5146106f0578063f2fde38b1461071057600080fd5b8063e72f6e30146106a4578063e82622aa146106b7578063e82ad7d4146106ca57600080fd5b8063c3f909d4116100c8578063c3f909d414610669578063cc77470a1461067e578063d7ae1d301461069157600080fd5b8063b734c0f41461064b578063badc3eb61461065357600080fd5b80639f87fad711610145578063a4c0ed361161011f578063a4c0ed361461061d578063a9c9a91814610630578063aab396bd1461064357600080fd5b80639f87fad7146105e2578063a21a23e4146105f5578063a47c7696146105fd57600080fd5b8063823597401161017657806382359740146105a45780638456cb59146105b75780638da5cb5b146105bf57600080fd5b80637341c10c1461058957806379ba50971461059c57600080fd5b806341db4ca31161024a5780635ed6dfba116101fe57806366419970116101d857806366419970146104e1578063674603d0146105085780636a2215de1461055157600080fd5b80635ed6dfba146104a85780636162a323146104bb57806366316d8d146104ce57600080fd5b80634b8832d31161022f5780634b8832d31461045057806355fedefa146104635780635c975abb1461049157600080fd5b806341db4ca31461041c578063461d27621461043d57600080fd5b80631ded3b36116102a1578063330605291161028657806333060529146103e05780633e871e4d146104015780633f4ba83a1461041457600080fd5b80631ded3b361461039f5780632a905ccc146103b257600080fd5b806310fc49c1116102d257806310fc49c11461032357806312b5834914610336578063181f5a771461035657600080fd5b806302bcc5b6146102ee5780630c5d49cb14610303575b600080fd5b6103016102fc366004614ba6565b610723565b005b61030b608481565b60405161ffff90911681526020015b60405180910390f35b610301610331366004614be7565b610783565b6000546040516bffffffffffffffffffffffff909116815260200161031a565b6103926040518060400160405280601781526020017f46756e6374696f6e7320526f757465722076312e302e3000000000000000000081525081565b60405161031a9190614c8e565b6103016103ad366004614ca1565b61087f565b600a5462010000900468ffffffffffffffffff1660405168ffffffffffffffffff909116815260200161031a565b6103f36103ee366004614f8c565b6108b1565b60405161031a929190615074565b61030161040f366004615135565b610c7c565b610301610e91565b61042f61042a366004615249565b610ea3565b60405190815260200161031a565b61042f61044b366004615249565b610f03565b61030161045e3660046152cd565b610f0f565b61042f610471366004614ba6565b67ffffffffffffffff166000908152600360208190526040909120015490565b60065460ff165b604051901515815260200161031a565b6103016104b63660046152fb565b61105d565b6103016104c93660046153bd565b611216565b6103016104dc3660046152fb565b611396565b60025467ffffffffffffffff165b60405167ffffffffffffffff909116815260200161031a565b61051b610516366004615490565b61147f565b6040805182511515815260208084015167ffffffffffffffff90811691830191909152928201519092169082015260600161031a565b61056461055f3660046154be565b61150f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161031a565b6103016105973660046152cd565b6115ce565b610301611781565b6103016105b2366004614ba6565b6118a8565b6103016119ef565b600654610100900473ffffffffffffffffffffffffffffffffffffffff16610564565b6103016105f03660046152cd565b6119ff565b6104ef611daa565b61061061060b366004614ba6565b611f37565b60405161031a91906155a7565b61030161062b3660046155ba565b61206c565b61056461063e3660046154be565b6122b8565b60095461042f565b610301612317565b61065b612463565b60405161031a929190615616565b610671612533565b60405161031a919061566d565b6104ef61068c366004615749565b61269a565b61030161069f3660046152cd565b61291a565b6103016106b2366004615749565b61297f565b6103016106c5366004615766565b612af8565b6104986106d8366004614ba6565b612db7565b6103016106eb3660046154be565b612f06565b6107036106fe3660046157dc565b612f13565b60405161031a91906157fa565b61030161071e366004615749565b6131a8565b61072b6131b9565b610734816131c1565b67ffffffffffffffff81166000908152600360205260408120546107809183916c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1690613237565b50565b67ffffffffffffffff8216600090815260036020819052604082200154600b54911a9081106107e8576040517f45c108ce00000000000000000000000000000000000000000000000000000000815260ff821660048201526024015b60405180910390fd5b6000600a6001018260ff16815481106108035761080361587a565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1690508063ffffffff168363ffffffff161115610879576040517f1d70f87a00000000000000000000000000000000000000000000000000000000815263ffffffff821660048201526024016107df565b50505050565b6108876131b9565b610890826131c1565b67ffffffffffffffff90911660009081526003602081905260409091200155565b6000806108bc613689565b826020015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610925576040517f8bec23e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82516000908152600560205260409020548061098a5783516020850151604051600295507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b60405180910390a25060009050610c71565b808460405160200161099c91906158db565b60405160208183030381529060405280519060200120146109f45783516020850151604051600695507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b8361012001518460a0015163ffffffff16610a0f9190615a37565b64ffffffffff165a1015610a5a5783516020850151604051600495507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b506000610a708460a0015163ffffffff16613691565b610a7a9088615a55565b9050600081878660c0015168ffffffffffffffffff16610a9a9190615a7d565b610aa49190615a7d565b9050610ab38560800151611f37565b600001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610b2b5784516020860151604051600596507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610b17918a9089906158a9565b60405180910390a25060009150610c719050565b84604001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610b905784516020860151604051600396507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610b17918a9089906158a9565b505082516000908152600560205260408120819055835160a08501516060860151610bc092918c918c9190613733565b8051909150610bd0576001610bd3565b60005b92506000610c0d8560800151866040015187606001518860c0015168ffffffffffffffffff168c610c078860200151613691565b8d6138f1565b9050846080015167ffffffffffffffff1685600001517f64778f26c70b60a8d7e29e2451b3844302d959448401c0535b768ed88c6b505e836020015189888f8f8960400151604051610c6496959493929190615aa2565b60405180910390a3519150505b965096945050505050565b610c84613c17565b8151815181141580610c965750600881115b15610ccd576040517fee03280800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610e47576000848281518110610cec57610cec61587a565b602002602001015190506000848381518110610d0a57610d0a61587a565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161480610d75575060008281526008602052604090205473ffffffffffffffffffffffffffffffffffffffff8281169116145b15610dac576040517fee03280800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260086020526040908190205490517f8b052f0f4bf82fede7daffea71592b29d5ef86af1f3c7daaa0345dbb2f52f48191610e2c91859173ffffffffffffffffffffffffffffffffffffffff1690859092835273ffffffffffffffffffffffffffffffffffffffff918216602084015216604082015260600190565b60405180910390a1505080610e4090615b25565b9050610cd0565b506040805180820190915283815260208082018490528451600d91610e709183918801906149e6565b506020828101518051610e899260018501920190614a2d565b505050505050565b610e99613c17565b610ea1613c9d565b565b600080610eaf8361150f565b9050610ef783828a8a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508c92508b9150613d1a9050565b98975050505050505050565b600080610eaf836122b8565b610f17613689565b610f20826140ef565b610f286141b5565b73ffffffffffffffffffffffffffffffffffffffff81161580610f8f575067ffffffffffffffff821660009081526003602052604090206001015473ffffffffffffffffffffffffffffffffffffffff8281166c0100000000000000000000000090920416145b15610fc6576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff821660008181526003602090815260409182902060010180546bffffffffffffffffffffffff166c0100000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8716908102919091179091558251338152918201527f69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be910160405180910390a25050565b6110656131b9565b806bffffffffffffffffffffffff1660000361109b5750306000908152600160205260409020546bffffffffffffffffffffffff165b306000908152600160205260409020546bffffffffffffffffffffffff908116908216811015611107576040517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff821660048201526024016107df565b30600090815260016020526040812080548492906111349084906bffffffffffffffffffffffff16615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550816000808282829054906101000a90046bffffffffffffffffffffffff1661118a9190615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061121183836bffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166142bf9092919063ffffffff16565b505050565b61121e613c17565b8051600a80546020808501516040860151606087015161ffff9081166f01000000000000000000000000000000027fffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffff60e09390931c6b01000000000000000000000002929092167fffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffff68ffffffffffffffffff90941662010000027fffffffffffffffffffffffffffffffffffffffffff0000000000000000000000909616919097161793909317169390931717815560808301518051849361130592600b92910190614aa7565b5060a08201516002909101805460c09093015168ffffffffffffffffff1662010000027fffffffffffffffffffffffffffffffffffffffffff000000000000000000000090931661ffff909216919091179190911790556040517ea5832bf95f66c7814294cc4db681f20ee79608bfb8912a5321d66cfed5e9859061138b90839061566d565b60405180910390a150565b61139e613689565b806bffffffffffffffffffffffff166000036113e6576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600160205260409020546bffffffffffffffffffffffff908116908216811015611452576040517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff821660048201526024016107df565b33600090815260016020526040812080548492906111349084906bffffffffffffffffffffffff16615b5d565b60408051606080820183526000808352602080840182905292840181905273ffffffffffffffffffffffffffffffffffffffff861681526004835283812067ffffffffffffffff868116835290845290849020845192830185525460ff81161515835261010081048216938301939093526901000000000000000000909204909116918101919091525b92915050565b6000805b600d5460ff8216101561159857600d805460ff83169081106115375761153761587a565b9060005260206000200154830361158857600e805460ff831690811061155f5761155f61587a565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff169392505050565b61159181615b82565b9050611513565b506040517f80833e33000000000000000000000000000000000000000000000000000000008152600481018390526024016107df565b6115d6613689565b6115df826140ef565b6115e76141b5565b60006115f6600a5461ffff1690565b67ffffffffffffffff841660009081526003602052604090206002015490915061ffff821611611658576040517fb72bc70300000000000000000000000000000000000000000000000000000000815261ffff821660048201526024016107df565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020908152604080832067ffffffffffffffff8716845290915290205460ff16156116a057505050565b73ffffffffffffffffffffffffffffffffffffffff8216600081815260046020908152604080832067ffffffffffffffff881680855290835281842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155600384528285206002018054918201815585529383902090930180547fffffffffffffffffffffffff000000000000000000000000000000000000000016851790555192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e091015b60405180910390a2505050565b60075473ffffffffffffffffffffffffffffffffffffffff163314611802576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016107df565b600680547fffffffffffffffffffffff0000000000000000000000000000000000000000ff81166101003381810292909217909355600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556040519290910473ffffffffffffffffffffffffffffffffffffffff169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6118b0613689565b6118b86141b5565b67ffffffffffffffff81166000908152600360205260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481169290910416338114611958576040517f4e1d9f1800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016107df565b67ffffffffffffffff831660008181526003602090815260409182902080546c01000000000000000000000000339081026bffffffffffffffffffffffff928316178355600190920180549091169055825173ffffffffffffffffffffffffffffffffffffffff87168152918201527f6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f09101611774565b6119f7613c17565b610ea161434c565b611a07613689565b611a10826140ef565b611a186141b5565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260046020908152604080832067ffffffffffffffff8087168552908352928190208151606081018352905460ff8116151582526101008104851693820193909352690100000000000000000090920490921691810191909152611a9782846143a7565b806040015167ffffffffffffffff16816020015167ffffffffffffffff1614611aec576040517f06eb10c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8316600090815260036020908152604080832060020180548251818502810185019093528083529192909190830182828015611b6757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611b3c575b5050505050905060005b8151811015611d0f578373ffffffffffffffffffffffffffffffffffffffff16828281518110611ba357611ba361587a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611cff578160018351611bd59190615ba1565b81518110611be557611be561587a565b6020026020010151600360008767ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000206002018281548110611c2857611c2861587a565b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff949094169390931790925567ffffffffffffffff87168152600390915260409020600201805480611ca257611ca2615bb4565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055611d0f565b611d0881615b25565b9050611b71565b5073ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832067ffffffffffffffff89168085529083529281902080547fffffffffffffffffffffffffffffff00000000000000000000000000000000001690555192835290917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b910160405180910390a250505050565b6000611db4613689565b611dbc6141b5565b60028054600090611dd69067ffffffffffffffff16615be3565b825467ffffffffffffffff8083166101009490940a93840293021916919091179091556040805160c0810182526000808252336020830152918101829052606081018290529192506080820190604051908082528060200260200182016040528015611e4c578160200160208202803683370190505b5081526000602091820181905267ffffffffffffffff841681526003825260409081902083518484015173ffffffffffffffffffffffffffffffffffffffff9081166c010000000000000000000000009081026bffffffffffffffffffffffff9384161784559386015160608701519091169093029216919091176001820155608083015180519192611ee792600285019290910190614a2d565b5060a0919091015160039091015560405133815267ffffffffffffffff8216907f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf9060200160405180910390a290565b6040805160c0810182526000808252602082018190529181018290526060808201839052608082015260a0810191909152611f71826131c1565b67ffffffffffffffff8216600090815260036020908152604091829020825160c08101845281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811684870152600185015491821684880152919004166060820152600282018054855181860281018601909652808652919492936080860193929083018282801561205257602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612027575b505050505081526020016003820154815250509050919050565b612074613689565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146120e3576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020811461211d576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061212b82840184614ba6565b67ffffffffffffffff81166000908152600360205260409020549091506c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff166121a4576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8116600090815260036020526040812080546bffffffffffffffffffffffff16918691906121db8385615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550846000808282829054906101000a90046bffffffffffffffffffffffff166122319190615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508167ffffffffffffffff167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f88287846122989190615c0a565b6040805192835260208301919091520160405180910390a2505050505050565b60008181526008602052604081205473ffffffffffffffffffffffffffffffffffffffff1680611509576040517f80833e33000000000000000000000000000000000000000000000000000000008152600481018490526024016107df565b61231f613c17565b60005b600d54811015612442576000600d60000182815481106123445761234461587a565b906000526020600020015490506000600d60010183815481106123695761236961587a565b6000918252602080832091909101548483526008825260409283902054835186815273ffffffffffffffffffffffffffffffffffffffff91821693810193909352169181018290529091507ff8a6175bca1ba37d682089187edc5e20a859989727f10ca6bd9a5bc0de8caf949060600160405180910390a160009182526008602052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905561243b81615b25565b9050612322565b50600d60006124518282614b51565b61245f600183016000614b51565b5050565b606080600d600001600d600101818054806020026020016040519081016040528092919081815260200182805480156124bb57602002820191906000526020600020905b8154815260200190600101908083116124a7575b505050505091508080548060200260200160405190810160405280929190818152602001828054801561252457602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116124f9575b50505050509050915091509091565b6040805160e0810182526000808252602082018190529181018290526060808201839052608082015260a0810182905260c08101919091526040805160e08082018352600a805461ffff808216855262010000820468ffffffffffffffffff166020808701919091526b010000000000000000000000830490941b7fffffffff0000000000000000000000000000000000000000000000000000000016858701526f01000000000000000000000000000000909104166060840152600b805485518185028101850190965280865293949193608086019383018282801561266557602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116126285790505b50505091835250506002919091015461ffff8116602083015262010000900468ffffffffffffffffff16604090910152919050565b60006126a4613689565b6126ac6141b5565b600280546000906126c69067ffffffffffffffff16615be3565b825467ffffffffffffffff8083166101009490940a93840293021916919091179091556040805160c081018252600080825233602083015291810182905260608101829052919250608082019060405190808252806020026020018201604052801561273c578160200160208202803683370190505b5081526000602091820181905267ffffffffffffffff841681526003825260409081902083518484015173ffffffffffffffffffffffffffffffffffffffff9081166c010000000000000000000000009081026bffffffffffffffffffffffff93841617845593860151606087015190911690930292169190911760018201556080830151805191926127d792600285019290910190614a2d565b5060a0919091015160039182015567ffffffffffffffff82166000818152602092835260408082206002018054600180820183559184528584200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff891690811790915583526004855281832084845285529181902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169092179091555133815290917f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf910160405180910390a260405173ffffffffffffffffffffffffffffffffffffffff8316815267ffffffffffffffff8216907f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e09060200160405180910390a2919050565b612922613689565b61292b826140ef565b6129336141b5565b61293c82612db7565b15612973576040517f06eb10c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61245f82826001613237565b6129876131b9565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612a14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a389190615c1d565b6000549091506bffffffffffffffffffffffff1681811015611211576000612a608284615ba1565b9050612aa373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001685836142bf565b6040805173ffffffffffffffffffffffffffffffffffffffff86168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a150505050565b612b00613689565b60005b81811015611211576000838383818110612b1f57612b1f61587a565b90506101600201803603810190612b369190615c36565b80516080820151600082815260056020908152604091829020549151949550929391929091612b67918691016158db565b6040516020818303038152906040528051906020012014612bb4576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015163ffffffff16421015612bf9576040517fa2376fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516040517f85b214cf0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff909116906385b214cf90602401600060405180830381600087803b158015612c6757600080fd5b505af1158015612c7b573d6000803e3d6000fd5b50505060408085015167ffffffffffffffff84166000908152600360205291822060010180549193509190612cbf9084906bffffffffffffffffffffffff16615b5d565b82546bffffffffffffffffffffffff9182166101009390930a928302919092021990911617905550606083015173ffffffffffffffffffffffffffffffffffffffff16600090815260046020908152604080832067ffffffffffffffff808616855292529091208054600192600991612d479185916901000000000000000000900416615c53565b825467ffffffffffffffff9182166101009390930a9283029190920219909116179055506000828152600560205260408082208290555183917ff1ca1e9147be737b04a2b018a79405f687a97de8dd8a2559bbe62357343af41491a250505080612db090615b25565b9050612b03565b67ffffffffffffffff8116600090815260036020908152604080832060020180548251818502810185019093528083528493830182828015612e2f57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612e04575b5050505050905060005b8151811015612efc57600060046000848481518110612e5a57612e5a61587a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040908101600090812067ffffffffffffffff808a168352908452908290208251606081018452905460ff8116151582526101008104831694820185905269010000000000000000009004909116918101829052925014612eeb57506001949350505050565b50612ef581615b25565b9050612e39565b5060009392505050565b612f0e613c17565b600955565b60608167ffffffffffffffff168367ffffffffffffffff161180612f46575060025467ffffffffffffffff908116908316115b80612f5b575060025467ffffffffffffffff16155b15612f92576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612f9c8383615c74565b612fa7906001615c53565b67ffffffffffffffff1667ffffffffffffffff811115612fc957612fc9614ccd565b60405190808252806020026020018201604052801561304657816020015b6040805160c081018252600080825260208083018290529282018190526060808301829052608083015260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181612fe75790505b50905060005b6130568484615c74565b67ffffffffffffffff1681116131a1576003600061307e8367ffffffffffffffff8816615c0a565b67ffffffffffffffff1681526020808201929092526040908101600020815160c08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481168488015260018501549182168487015291900416606082015260028201805484518187028101870190955280855291949293608086019390929083018282801561316057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311613135575b505050505081526020016003820154815250508282815181106131855761318561587a565b60200260200101819052508061319a90615b25565b905061304c565b5092915050565b6131b0613c17565b6107808161441b565b610ea1613c17565b67ffffffffffffffff81166000908152600360205260409020546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16610780576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff83166000908152600360209081526040808320815160c08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481168488015260018501549182168487015291900416606082015260028201805484518187028101870190955280855291949293608086019390929083018282801561331857602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116132ed575b50505091835250506003919091015460209091015280519091506000805b83608001515181101561342e5760008460800151828151811061335b5761335b61587a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff8116600090815260048352604080822067ffffffffffffffff808e16845294529020549092506133bb9169010000000000000000009091041684615c53565b73ffffffffffffffffffffffffffffffffffffffff909116600090815260046020908152604080832067ffffffffffffffff8c168452909152902080547fffffffffffffffffffffffffffffff0000000000000000000000000000000000169055915061342781615b25565b9050613336565b5067ffffffffffffffff8616600090815260036020526040812081815560018101829055906134606002830182614b51565b50600060039190910155600c5461ffff81169062010000900468ffffffffffffffffff1685801561349e57508161ffff168367ffffffffffffffff16105b1561355a576000846bffffffffffffffffffffffff168268ffffffffffffffffff16116134d6578168ffffffffffffffffff166134d8565b845b90506bffffffffffffffffffffffff81161561355857306000908152600160205260408120805483929061351b9084906bffffffffffffffffffffffff16615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080856135559190615b5d565b94505b505b6bffffffffffffffffffffffff841615613617576000805485919081906135909084906bffffffffffffffffffffffff16615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061361787856bffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166142bf9092919063ffffffff16565b6040805173ffffffffffffffffffffffffffffffffffffffff891681526bffffffffffffffffffffffff8616602082015267ffffffffffffffff8a16917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815910160405180910390a25050505050505050565b610ea1614517565b60006bffffffffffffffffffffffff82111561372f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f362062697473000000000000000000000000000000000000000000000000000060648201526084016107df565b5090565b60408051606080820183526000808352602083015291810191909152813b1580156137865750506040805160608101825260008082526020808301829052835191825281018352918101919091526138e8565b600a546040516000916b010000000000000000000000900460e01b906137b4908a908a908a90602401615c95565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009590951694909417909352600a548151608480825260c0820190935292945061ffff6f01000000000000000000000000000000909104169260009283928392820181803683370190505090505a8481101561388257600080fd5b8490036040810481038a1061389657600080fd5b505a60008087516020890160008d8ff193505a900391503d60848111156138bb575060845b808252806000602084013e5060408051606081018252931515845260208401929092529082015293505050505b95945050505050565b604080518082019091526000808252602082015260006139118486615a55565b90506000816139208886615a7d565b61392a9190615a7d565b67ffffffffffffffff8b166000908152600360205260409020549091506bffffffffffffffffffffffff80831691161080613991575067ffffffffffffffff8a166000908152600360205260409020600101546bffffffffffffffffffffffff808b169116105b156139f45767ffffffffffffffff8a16600090815260036020526040908190205490517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff90911660048201526024016107df565b67ffffffffffffffff8a1660009081526003602052604081208054839290613a2b9084906bffffffffffffffffffffffff16615b5d565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915567ffffffffffffffff8c16600090815260036020526040812060010180548d94509092613a7f91859116615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508184613ab99190615a7d565b3360009081526001602052604081208054909190613ae69084906bffffffffffffffffffffffff16615a7d565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915530600090815260016020526040812080548b94509092613b2d91859116615a7d565b82546bffffffffffffffffffffffff9182166101009390930a92830291909202199091161790555073ffffffffffffffffffffffffffffffffffffffff8816600090815260046020908152604080832067ffffffffffffffff808f16855292529091208054600192600991613bb19185916901000000000000000000900416615c53565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040518060400160405280836bffffffffffffffffffffffff168152602001826bffffffffffffffffffffffff1681525092505050979650505050505050565b600654610100900473ffffffffffffffffffffffffffffffffffffffff163314610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016107df565b613ca5614584565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000613d24613689565b613d2d856131c1565b613d3733866143a7565b613d418583610783565b8351600003613d7b576040517ec1cfc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000613d8686611f37565b90506000613d94338861147f565b600a54604080516101608101825289815267ffffffffffffffff8b1660009081526003602081815293822001549495506201000090930468ffffffffffffffffff169373ffffffffffffffffffffffffffffffffffffffff8d169263a631571e929190820190815233602082015260408881015189519190920191613e1891615b5d565b6bffffffffffffffffffffffff1681526020018568ffffffffffffffffff1681526020018c67ffffffffffffffff168152602001866020015167ffffffffffffffff1681526020018963ffffffff1681526020018a61ffff168152602001866040015167ffffffffffffffff168152602001876020015173ffffffffffffffffffffffffffffffffffffffff168152506040518263ffffffff1660e01b8152600401613ec49190615cc0565b610160604051808303816000875af1158015613ee4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f089190615e25565b805160009081526005602052604090205490915015613f595780516040517f304f32e800000000000000000000000000000000000000000000000000000000815260048101919091526024016107df565b604051806101600160405280826000015181526020018b73ffffffffffffffffffffffffffffffffffffffff16815260200182604001516bffffffffffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff1681526020018a67ffffffffffffffff1681526020018763ffffffff1681526020018368ffffffffffffffffff1681526020018260e0015168ffffffffffffffffff16815260200182610100015164ffffffffff16815260200182610120015164ffffffffff16815260200182610140015163ffffffff1681525060405160200161404491906158db565b60405160208183030381529060405280519060200120600560008360000151815260200190815260200160002081905550614084338a83604001516145f0565b8867ffffffffffffffff168b82600001517ff67aec45c9a7ede407974a3e0c3a743dffeab99ee3f2d4c9a8144c2ebf2c7ec9876020015133328e8e8e8a604001516040516140d89796959493929190615ef8565b60405180910390a4519a9950505050505050505050565b67ffffffffffffffff81166000908152600360205260409020546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1680614166576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff82161461245f576040517f5a68151d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60095460009081526008602052604090205473ffffffffffffffffffffffffffffffffffffffff16806141e55750565b604080516000815260208101918290527f6b14daf80000000000000000000000000000000000000000000000000000000090915273ffffffffffffffffffffffffffffffffffffffff821690636b14daf89061424690339060248101615f70565b602060405180830381865afa158015614263573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142879190615f9f565b610780576040517f229062630000000000000000000000000000000000000000000000000000000081523360048201526024016107df565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526112119084906146cb565b614354614517565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613cf03390565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020908152604080832067ffffffffffffffff8516845290915290205460ff1661245f576040517f71e8313700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff82160361449a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016107df565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600654604051919261010090910416907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b60065460ff1615610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064016107df565b60065460ff16610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016107df565b67ffffffffffffffff82166000908152600360205260408120600101805483929061462a9084906bffffffffffffffffffffffff16615a7d565b82546bffffffffffffffffffffffff91821661010093840a908102920219161790915573ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832067ffffffffffffffff80891685529252909120805460019450909284926146a0928492900416615c53565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505050565b600061472d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166147d79092919063ffffffff16565b805190915015611211578080602001905181019061474b9190615f9f565b611211576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107df565b60606147e684846000856147ee565b949350505050565b606082471015614880576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107df565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516148a99190615fc1565b60006040518083038185875af1925050503d80600081146148e6576040519150601f19603f3d011682016040523d82523d6000602084013e6148eb565b606091505b50915091506148fc87838387614907565b979650505050505050565b6060831561499d5782516000036149965773ffffffffffffffffffffffffffffffffffffffff85163b614996576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107df565b50816147e6565b6147e683838151156149b25781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107df9190614c8e565b828054828255906000526020600020908101928215614a21579160200282015b82811115614a21578251825591602001919060010190614a06565b5061372f929150614b6b565b828054828255906000526020600020908101928215614a21579160200282015b82811115614a2157825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190614a4d565b82805482825590600052602060002090600701600890048101928215614a215791602002820160005b83821115614b1457835183826101000a81548163ffffffff021916908363ffffffff1602179055509260200192600401602081600301049283019260010302614ad0565b8015614b445782816101000a81549063ffffffff0219169055600401602081600301049283019260010302614b14565b505061372f929150614b6b565b508054600082559060005260206000209081019061078091905b5b8082111561372f5760008155600101614b6c565b67ffffffffffffffff8116811461078057600080fd5b8035614ba181614b80565b919050565b600060208284031215614bb857600080fd5b8135614bc381614b80565b9392505050565b63ffffffff8116811461078057600080fd5b8035614ba181614bca565b60008060408385031215614bfa57600080fd5b8235614c0581614b80565b91506020830135614c1581614bca565b809150509250929050565b60005b83811015614c3b578181015183820152602001614c23565b50506000910152565b60008151808452614c5c816020860160208601614c20565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000614bc36020830184614c44565b60008060408385031215614cb457600080fd5b8235614cbf81614b80565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610160810167ffffffffffffffff81118282101715614d2057614d20614ccd565b60405290565b60405160e0810167ffffffffffffffff81118282101715614d2057614d20614ccd565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614d9057614d90614ccd565b604052919050565b600082601f830112614da957600080fd5b813567ffffffffffffffff811115614dc357614dc3614ccd565b614df460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614d49565b818152846020838601011115614e0957600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff8116811461078057600080fd5b8035614ba181614e26565b73ffffffffffffffffffffffffffffffffffffffff8116811461078057600080fd5b8035614ba181614e4b565b68ffffffffffffffffff8116811461078057600080fd5b8035614ba181614e78565b64ffffffffff8116811461078057600080fd5b8035614ba181614e9a565b60006101608284031215614ecb57600080fd5b614ed3614cfc565b905081358152614ee560208301614e6d565b6020820152614ef660408301614e40565b6040820152614f0760608301614e6d565b6060820152614f1860808301614b96565b6080820152614f2960a08301614bdc565b60a0820152614f3a60c08301614e8f565b60c0820152614f4b60e08301614e8f565b60e0820152610100614f5e818401614ead565b90820152610120614f70838201614ead565b90820152610140614f82838201614bdc565b9082015292915050565b6000806000806000806102008789031215614fa657600080fd5b863567ffffffffffffffff80821115614fbe57600080fd5b614fca8a838b01614d98565b97506020890135915080821115614fe057600080fd5b50614fed89828a01614d98565b9550506040870135614ffe81614e26565b9350606087013561500e81614e26565b9250608087013561501e81614e4b565b915061502d8860a08901614eb8565b90509295509295509295565b60078110615070577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b604081016150828285615039565b6bffffffffffffffffffffffff831660208301529392505050565b600067ffffffffffffffff8211156150b7576150b7614ccd565b5060051b60200190565b600082601f8301126150d257600080fd5b813560206150e76150e28361509d565b614d49565b82815260059290921b8401810191818101908684111561510657600080fd5b8286015b8481101561512a57803561511d81614e4b565b835291830191830161510a565b509695505050505050565b6000806040838503121561514857600080fd5b823567ffffffffffffffff8082111561516057600080fd5b818501915085601f83011261517457600080fd5b813560206151846150e28361509d565b82815260059290921b840181019181810190898411156151a357600080fd5b948201945b838610156151c1578535825294820194908201906151a8565b965050860135925050808211156151d757600080fd5b506151e4858286016150c1565b9150509250929050565b60008083601f84011261520057600080fd5b50813567ffffffffffffffff81111561521857600080fd5b60208301915083602082850101111561523057600080fd5b9250929050565b803561ffff81168114614ba157600080fd5b60008060008060008060a0878903121561526257600080fd5b863561526d81614b80565b9550602087013567ffffffffffffffff81111561528957600080fd5b61529589828a016151ee565b90965094506152a8905060408801615237565b925060608701356152b881614bca565b80925050608087013590509295509295509295565b600080604083850312156152e057600080fd5b82356152eb81614b80565b91506020830135614c1581614e4b565b6000806040838503121561530e57600080fd5b823561531981614e4b565b91506020830135614c1581614e26565b80357fffffffff0000000000000000000000000000000000000000000000000000000081168114614ba157600080fd5b600082601f83011261536a57600080fd5b8135602061537a6150e28361509d565b82815260059290921b8401810191818101908684111561539957600080fd5b8286015b8481101561512a5780356153b081614bca565b835291830191830161539d565b6000602082840312156153cf57600080fd5b813567ffffffffffffffff808211156153e757600080fd5b9083019060e082860312156153fb57600080fd5b615403614d26565b61540c83615237565b815261541a60208401614e8f565b602082015261542b60408401615329565b604082015261543c60608401615237565b606082015260808301358281111561545357600080fd5b61545f87828601615359565b60808301525061547160a08401615237565b60a082015261548260c08401614e8f565b60c082015295945050505050565b600080604083850312156154a357600080fd5b82356154ae81614e4b565b91506020830135614c1581614b80565b6000602082840312156154d057600080fd5b5035919050565b600081518084526020808501945080840160005b8381101561551d57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016154eb565b509495945050505050565b60006bffffffffffffffffffffffff808351168452602083015173ffffffffffffffffffffffffffffffffffffffff8082166020870152826040860151166040870152806060860151166060870152505050608082015160c0608085015261559360c08501826154d7565b60a093840151949093019390935250919050565b602081526000614bc36020830184615528565b600080600080606085870312156155d057600080fd5b84356155db81614e4b565b935060208501359250604085013567ffffffffffffffff8111156155fe57600080fd5b61560a878288016151ee565b95989497509550505050565b604080825283519082018190526000906020906060840190828701845b8281101561564f57815184529284019290840190600101615633565b5050508381038285015261566381866154d7565b9695505050505050565b60006020808352610100830161ffff808651168386015268ffffffffffffffffff838701511660408601527fffffffff00000000000000000000000000000000000000000000000000000000604087015116606086015280606087015116608086015250608085015160e060a0860152818151808452610120870191508483019350600092505b8083101561571a57835163ffffffff1682529284019260019290920191908401906156f4565b5060a087015161ffff811660c0880152935060c087015168ffffffffffffffffff811660e08801529350615663565b60006020828403121561575b57600080fd5b8135614bc381614e4b565b6000806020838503121561577957600080fd5b823567ffffffffffffffff8082111561579157600080fd5b818501915085601f8301126157a557600080fd5b8135818111156157b457600080fd5b866020610160830285010111156157ca57600080fd5b60209290920196919550909350505050565b600080604083850312156157ef57600080fd5b82356154ae81614b80565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561586d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261585b858351615528565b94509285019290850190600101615821565b5092979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff848116825283166020820152606081016147e66040830184615039565b8151815260208083015161016083019161590c9084018273ffffffffffffffffffffffffffffffffffffffff169052565b50604083015161592c60408401826bffffffffffffffffffffffff169052565b506060830151615954606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080830151615970608084018267ffffffffffffffff169052565b5060a083015161598860a084018263ffffffff169052565b5060c08301516159a560c084018268ffffffffffffffffff169052565b5060e08301516159c260e084018268ffffffffffffffffff169052565b506101008381015164ffffffffff81168483015250506101208381015164ffffffffff81168483015250506101408381015163ffffffff8116848301525b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b64ffffffffff8181168382160190808211156131a1576131a1615a08565b6bffffffffffffffffffffffff818116838216028082169190828114615a0057615a00615a08565b6bffffffffffffffffffffffff8181168382160190808211156131a1576131a1615a08565b6bffffffffffffffffffffffff8716815273ffffffffffffffffffffffffffffffffffffffff86166020820152615adc6040820186615039565b60c060608201526000615af260c0830186614c44565b8281036080840152615b048186614c44565b905082810360a0840152615b188185614c44565b9998505050505050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615b5657615b56615a08565b5060010190565b6bffffffffffffffffffffffff8281168282160390808211156131a1576131a1615a08565b600060ff821660ff8103615b9857615b98615a08565b60010192915050565b8181038181111561150957611509615a08565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600067ffffffffffffffff808316818103615c0057615c00615a08565b6001019392505050565b8082018082111561150957611509615a08565b600060208284031215615c2f57600080fd5b5051919050565b60006101608284031215615c4957600080fd5b614bc38383614eb8565b67ffffffffffffffff8181168382160190808211156131a1576131a1615a08565b67ffffffffffffffff8281168282160390808211156131a1576131a1615a08565b838152606060208201526000615cae6060830185614c44565b82810360408401526156638185614c44565b6020815260008251610160806020850152615cdf610180850183614c44565b9150602085015160408501526040850151615d12606086018273ffffffffffffffffffffffffffffffffffffffff169052565b5060608501516bffffffffffffffffffffffff8116608086015250608085015168ffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015167ffffffffffffffff811660e08601525060e0850151610100615d898187018363ffffffff169052565b8601519050610120615da08682018361ffff169052565b8601519050610140615dbd8682018367ffffffffffffffff169052565b9095015173ffffffffffffffffffffffffffffffffffffffff1693019290925250919050565b8051614ba181614e4b565b8051614ba181614e26565b8051614ba181614b80565b8051614ba181614bca565b8051614ba181614e78565b8051614ba181614e9a565b60006101608284031215615e3857600080fd5b615e40614cfc565b82518152615e5060208401615de3565b6020820152615e6160408401615dee565b6040820152615e7260608401615de3565b6060820152615e8360808401615df9565b6080820152615e9460a08401615e04565b60a0820152615ea560c08401615e0f565b60c0820152615eb660e08401615e0f565b60e0820152610100615ec9818501615e1a565b90820152610120615edb848201615e1a565b90820152610140615eed848201615e04565b908201529392505050565b600073ffffffffffffffffffffffffffffffffffffffff808a168352808916602084015280881660408401525060e06060830152615f3960e0830187614c44565b61ffff9590951660808301525063ffffffff9290921660a08301526bffffffffffffffffffffffff1660c090910152949350505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006147e66040830184614c44565b600060208284031215615fb157600080fd5b81518015158114614bc357600080fd5b60008251615fd3818460208701614c20565b919091019291505056fea164736f6c6343000813000a", } var FunctionsRouterABI = FunctionsRouterMetaData.ABI @@ -451,6 +453,28 @@ func (_FunctionsRouter *FunctionsRouterCallerSession) GetSubscriptionCount() (ui return _FunctionsRouter.Contract.GetSubscriptionCount(&_FunctionsRouter.CallOpts) } +func (_FunctionsRouter *FunctionsRouterCaller) GetSubscriptionsInRange(opts *bind.CallOpts, subscriptionIdStart uint64, subscriptionIdEnd uint64) ([]IFunctionsSubscriptionsSubscription, error) { + var out []interface{} + err := _FunctionsRouter.contract.Call(opts, &out, "getSubscriptionsInRange", subscriptionIdStart, subscriptionIdEnd) + + if err != nil { + return *new([]IFunctionsSubscriptionsSubscription), err + } + + out0 := *abi.ConvertType(out[0], new([]IFunctionsSubscriptionsSubscription)).(*[]IFunctionsSubscriptionsSubscription) + + return out0, err + +} + +func (_FunctionsRouter *FunctionsRouterSession) GetSubscriptionsInRange(subscriptionIdStart uint64, subscriptionIdEnd uint64) ([]IFunctionsSubscriptionsSubscription, error) { + return _FunctionsRouter.Contract.GetSubscriptionsInRange(&_FunctionsRouter.CallOpts, subscriptionIdStart, subscriptionIdEnd) +} + +func (_FunctionsRouter *FunctionsRouterCallerSession) GetSubscriptionsInRange(subscriptionIdStart uint64, subscriptionIdEnd uint64) ([]IFunctionsSubscriptionsSubscription, error) { + return _FunctionsRouter.Contract.GetSubscriptionsInRange(&_FunctionsRouter.CallOpts, subscriptionIdStart, subscriptionIdEnd) +} + func (_FunctionsRouter *FunctionsRouterCaller) GetTotalBalance(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _FunctionsRouter.contract.Call(opts, &out, "getTotalBalance") @@ -3358,7 +3382,7 @@ func (_FunctionsRouter *FunctionsRouter) ParseLog(log types.Log) (generated.Abig } func (FunctionsRouterConfigUpdated) Topic() common.Hash { - return common.HexToHash("0x049ce2e6e1420eb4b07b425e90129186833eb346bda40b37d5d921aad482f71c") + return common.HexToHash("0x00a5832bf95f66c7814294cc4db681f20ee79608bfb8912a5321d66cfed5e985") } func (FunctionsRouterContractProposed) Topic() common.Hash { @@ -3460,6 +3484,8 @@ type FunctionsRouterInterface interface { GetSubscriptionCount(opts *bind.CallOpts) (uint64, error) + GetSubscriptionsInRange(opts *bind.CallOpts, subscriptionIdStart uint64, subscriptionIdEnd uint64) ([]IFunctionsSubscriptionsSubscription, error) + GetTotalBalance(opts *bind.CallOpts) (*big.Int, error) IsValidCallbackGasLimit(opts *bind.CallOpts, subscriptionId uint64, callbackGasLimit uint32) error diff --git a/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 0d7dc5a6217..07a431d993a 100644 --- a/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -3,11 +3,11 @@ functions: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsRequest.abi functions_allow_list: ../../../contracts/solc/v0.8.19/functions/1_0_0/TermsOfServiceAllowList.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/TermsOfServiceAllowList.bin b2697ad4dfece903a1d34028826a017fa445eb3cd984006f1734fa9d47836ca0 functions_billing_registry_events_mock: ../../../contracts/solc/v0.8.6/functions/0_0_0/FunctionsBillingRegistryEventsMock.abi ../../../contracts/solc/v0.8.6/functions/0_0_0/FunctionsBillingRegistryEventsMock.bin 50deeb883bd9c3729702be335c0388f9d8553bab4be5e26ecacac496a89e2b77 functions_client: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsClient.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsClient.bin 2368f537a04489c720a46733f8596c4fc88a31062ecfa966d05f25dd98608aca -functions_client_example: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsClientExample.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsClientExample.bin 25036bdb94a50a81df4222418bf9aa1e0c8540d5834b7e6e639aa63a2a2c8206 -functions_coordinator: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsCoordinator.bin e453fd45029ff99658d029bfbb8711b748c432323f12585c039a30977e801a79 -functions_load_test_client: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsLoadTestClient.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsLoadTestClient.bin 1323b4ee0bcefd61a248177cf84d98015ae08e2b05223e06a1724112efdca8cd +functions_client_example: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsClientExample.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsClientExample.bin abf32e69f268f40e8530eb8d8e96bf310b798a4c0049a58022d9d2fb527b601b +functions_coordinator: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsCoordinator.bin 21bd322caf977c4802d2c17419b57487cca438c7c5fafc52a9a9e1c9f4a72289 +functions_load_test_client: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsLoadTestClient.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsLoadTestClient.bin c8dbbd5ebb34435800d6674700068837c3a252db60046a14b0e61e829db517de functions_oracle_events_mock: ../../../contracts/solc/v0.8.6/functions/0_0_0/FunctionsOracleEventsMock.abi ../../../contracts/solc/v0.8.6/functions/0_0_0/FunctionsOracleEventsMock.bin 3ca70f966f8fe751987f0ccb50bebb6aa5be77e4a9f835d1ae99e0e9bfb7d52c -functions_router: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsRouter.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsRouter.bin dd1d3527e19d65efe029c4a131ded44dc0ca961e5c4f459743992435431ec478 +functions_router: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsRouter.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsRouter.bin 9dedd3a36043605fd9bedf821e7ec5b4281a5c7ae2e4a1955f37aff8ba13519f functions_v1_events_mock: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsV1EventsMock.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsV1EventsMock.bin 0f0ba42e0cc33c7abc8b8fd4fdfce903748a169886dd5f16cfdd56e75bcf708d ocr2dr: ../../../contracts/solc/v0.8.6/functions/0_0_0/Functions.abi ../../../contracts/solc/v0.8.6/functions/0_0_0/Functions.bin d9a794b33f47cc57563d216f7cf3a612309fc3062356a27e30005cf1d59e449d ocr2dr_client: ../../../contracts/solc/v0.8.6/functions/0_0_0/FunctionsClient.abi ../../../contracts/solc/v0.8.6/functions/0_0_0/FunctionsClient.bin 84aa63f9dbc5c7eac240db699b09e613ca4c6cd56dab10bdc25b02461b717e21 diff --git a/core/gethwrappers/generated/streams_lookup_upkeep_wrapper/streams_lookup_upkeep_wrapper.go b/core/gethwrappers/generated/streams_lookup_upkeep_wrapper/streams_lookup_upkeep_wrapper.go index e9d48584339..3332ac8215e 100644 --- a/core/gethwrappers/generated/streams_lookup_upkeep_wrapper/streams_lookup_upkeep_wrapper.go +++ b/core/gethwrappers/generated/streams_lookup_upkeep_wrapper/streams_lookup_upkeep_wrapper.go @@ -31,8 +31,8 @@ var ( ) var StreamsLookupUpkeepMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_testRange\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_useArbBlock\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_staging\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_verify\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"v0\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"v1\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"verifiedV0\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"verifiedV1\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"ed\",\"type\":\"bytes\"}],\"name\":\"MercuryPerformEvent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"callbackReturnBool\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"eligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feeds\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"interval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previousPerformBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"value\",\"type\":\"bool\"}],\"name\":\"setCallbackReturnBool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_feeds\",\"type\":\"string[]\"}],\"name\":\"setFeeds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_timeParamKey\",\"type\":\"string\"}],\"name\":\"setParamKeys\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"value\",\"type\":\"bool\"}],\"name\":\"setShouldRevertCallback\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"shouldRevertCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"staging\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testRange\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbBlock\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162001b9c38038062001b9c833981016040819052620000349162000232565b60008581556001859055600281905560038190556004558215156080526040805180820190915260098152680cccacac892c890caf60bb1b602082015260069062000080908262000335565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b6020820152600790620000b2908262000335565b50604051806040016040528060405180608001604052806042815260200162001b1860429139815260200160405180608001604052806042815260200162001b5a6042913990526200010990600590600262000145565b506008805463ff000000199215156101000261ff00199415159490941661ffff1990911617929092171663010000001790555062000401915050565b82805482825590600052602060002090810192821562000190579160200282015b828111156200019057825182906200017f908262000335565b509160200191906001019062000166565b506200019e929150620001a2565b5090565b808211156200019e576000620001b98282620001c3565b50600101620001a2565b508054620001d190620002a6565b6000825580601f10620001e2575050565b601f01602090049060005260206000209081019062000202919062000205565b50565b5b808211156200019e576000815560010162000206565b805180151581146200022d57600080fd5b919050565b600080600080600060a086880312156200024b57600080fd5b855194506020860151935062000264604087016200021c565b925062000274606087016200021c565b915062000284608087016200021c565b90509295509295909350565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620002bb57607f821691505b602082108103620002dc57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200033057600081815260208120601f850160051c810160208610156200030b5750805b601f850160051c820191505b818110156200032c5782815560010162000317565b5050505b505050565b81516001600160401b0381111562000351576200035162000290565b6200036981620003628454620002a6565b84620002e2565b602080601f831160018114620003a15760008415620003885750858301515b600019600386901b1c1916600185901b1785556200032c565b600085815260208120601f198616915b82811015620003d257888601518255948401946001909101908401620003b1565b5085821015620003f15787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6080516116e662000432600039600081816103070152818161039001528181610a560152610bbe01526116e66000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c80636e04ff0d116100d8578063947a36fb1161008c578063d826f88f11610066578063d826f88f1461035e578063d832d92f14610372578063fc735e991461037a57600080fd5b8063947a36fb14610345578063afb28d1f1461034e578063c98f10b01461035657600080fd5b806386b728e2116100bd57806386b728e21461030257806386e330af14610329578063917d895f1461033c57600080fd5b80636e04ff0d146102dc5780638340507c146102ef57600080fd5b80634a5479f31161013a5780635b48391a116101145780635b48391a1461028357806361bc221a146102ca5780636250a13a146102d357600080fd5b80634a5479f3146101fc5780634b56a42e1461021c5780634bdb38621461023d57600080fd5b80631d1970b71161016b5780631d1970b7146101c35780632cb15864146101d05780634585e33b146101e757600080fd5b806302be021f14610187578063102d538b146101af575b600080fd5b60085461019a9062010000900460ff1681565b60405190151581526020015b60405180910390f35b60085461019a906301000000900460ff1681565b60085461019a9060ff1681565b6101d960035481565b6040519081526020016101a6565b6101fa6101f5366004610d52565b61038c565b005b61020f61020a366004610dc4565b610873565b6040516101a69190610e4b565b61022f61022a366004610fa3565b61091f565b6040516101a6929190611077565b6101fa61024b36600461109a565b6008805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff909216919091179055565b6101fa61029136600461109a565b600880549115156301000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff909216919091179055565b6101d960045481565b6101d960005481565b61022f6102ea366004610d52565b6109fa565b6101fa6102fd3660046110bc565b610b59565b61019a7f000000000000000000000000000000000000000000000000000000000000000081565b6101fa610337366004611109565b610b77565b6101d960025481565b6101d960015481565b61020f610b8e565b61020f610b9b565b6101fa600060028190556003819055600455565b61019a610ba8565b60085461019a90610100900460ff1681565b60007f00000000000000000000000000000000000000000000000000000000000000001561042b57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610400573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061042491906111ba565b905061042e565b50435b60035460000361043e5760038190555b60008061044d84860186610fa3565b60028590556004549193509150610465906001611202565b600455604080516020808201835260008083528351918201909352918252600854909190610100900460ff16156107df5760085460ff1615610642577360448b880c9f3b501af3f343da9284148bd7d77c73ffffffffffffffffffffffffffffffffffffffff16638e760afe856000815181106104e4576104e461121b565b60200260200101516040518263ffffffff1660e01b81526004016105089190610e4b565b6000604051808303816000875af1158015610527573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261056d919081019061124a565b91507360448b880c9f3b501af3f343da9284148bd7d77c73ffffffffffffffffffffffffffffffffffffffff16638e760afe856001815181106105b2576105b261121b565b60200260200101516040518263ffffffff1660e01b81526004016105d69190610e4b565b6000604051808303816000875af11580156105f5573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261063b919081019061124a565b90506107df565b7309dff56a4ff44e0f4436260a04f5cfa65636a48173ffffffffffffffffffffffffffffffffffffffff16638e760afe856000815181106106855761068561121b565b60200260200101516040518263ffffffff1660e01b81526004016106a99190610e4b565b6000604051808303816000875af11580156106c8573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261070e919081019061124a565b91507309dff56a4ff44e0f4436260a04f5cfa65636a48173ffffffffffffffffffffffffffffffffffffffff16638e760afe856001815181106107535761075361121b565b60200260200101516040518263ffffffff1660e01b81526004016107779190610e4b565b6000604051808303816000875af1158015610796573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526107dc919081019061124a565b90505b843373ffffffffffffffffffffffffffffffffffffffff167f1c85d6186f024e964616014c8247533455ec5129a5095711202292f8a7ea1d548660008151811061082b5761082b61121b565b6020026020010151876001815181106108465761084661121b565b60200260200101518686896040516108629594939291906112c1565b60405180910390a350505050505050565b6005818154811061088357600080fd5b90600052602060002001600091509050805461089e9061132e565b80601f01602080910402602001604051908101604052809291908181526020018280546108ca9061132e565b80156109175780601f106108ec57610100808354040283529160200191610917565b820191906000526020600020905b8154815290600101906020018083116108fa57829003601f168201915b505050505081565b60085460009060609062010000900460ff161561099d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f73686f756c6452657665727443616c6c6261636b20697320747275650000000060448201526064015b60405180910390fd5b600084846040516020016109b2929190611381565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526008546301000000900460ff1693509150505b9250929050565b60006060610a06610ba8565b610a52576000848481818080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509597509195506109f3945050505050565b60007f000000000000000000000000000000000000000000000000000000000000000015610af157606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ac6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aea91906111ba565b9050610af4565b50435b604080516c6400000000000000000000000060208201528151601481830301815260348201928390527ff055e4a200000000000000000000000000000000000000000000000000000000909252610994916006916005916007918691906038016114a7565b6006610b6583826115ac565b506007610b7282826115ac565b505050565b8051610b8a906005906020840190610c8d565b5050565b6006805461089e9061132e565b6007805461089e9061132e565b6000600354600003610bba5750600190565b60007f000000000000000000000000000000000000000000000000000000000000000015610c5957606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c5291906111ba565b9050610c5c565b50435b600054600354610c6c90836116c6565b108015610c875750600154600254610c8490836116c6565b10155b91505090565b828054828255906000526020600020908101928215610cd3579160200282015b82811115610cd35782518290610cc390826115ac565b5091602001919060010190610cad565b50610cdf929150610ce3565b5090565b80821115610cdf576000610cf78282610d00565b50600101610ce3565b508054610d0c9061132e565b6000825580601f10610d1c575050565b601f016020900490600052602060002090810190610d3a9190610d3d565b50565b5b80821115610cdf5760008155600101610d3e565b60008060208385031215610d6557600080fd5b823567ffffffffffffffff80821115610d7d57600080fd5b818501915085601f830112610d9157600080fd5b813581811115610da057600080fd5b866020828501011115610db257600080fd5b60209290920196919550909350505050565b600060208284031215610dd657600080fd5b5035919050565b60005b83811015610df8578181015183820152602001610de0565b50506000910152565b60008151808452610e19816020860160208601610ddd565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610e5e6020830184610e01565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610edb57610edb610e65565b604052919050565b600067ffffffffffffffff821115610efd57610efd610e65565b5060051b60200190565b600067ffffffffffffffff821115610f2157610f21610e65565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112610f5e57600080fd5b8135610f71610f6c82610f07565b610e94565b818152846020838601011115610f8657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215610fb657600080fd5b823567ffffffffffffffff80821115610fce57600080fd5b818501915085601f830112610fe257600080fd5b81356020610ff2610f6c83610ee3565b82815260059290921b8401810191818101908984111561101157600080fd5b8286015b848110156110495780358681111561102d5760008081fd5b61103b8c86838b0101610f4d565b845250918301918301611015565b509650508601359250508082111561106057600080fd5b5061106d85828601610f4d565b9150509250929050565b82151581526040602082015260006110926040830184610e01565b949350505050565b6000602082840312156110ac57600080fd5b81358015158114610e5e57600080fd5b600080604083850312156110cf57600080fd5b823567ffffffffffffffff808211156110e757600080fd5b6110f386838701610f4d565b9350602085013591508082111561106057600080fd5b6000602080838503121561111c57600080fd5b823567ffffffffffffffff8082111561113457600080fd5b818501915085601f83011261114857600080fd5b8135611156610f6c82610ee3565b81815260059190911b8301840190848101908883111561117557600080fd5b8585015b838110156111ad578035858111156111915760008081fd5b61119f8b89838a0101610f4d565b845250918601918601611179565b5098975050505050505050565b6000602082840312156111cc57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115611215576112156111d3565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561125c57600080fd5b815167ffffffffffffffff81111561127357600080fd5b8201601f8101841361128457600080fd5b8051611292610f6c82610f07565b8181528560208385010111156112a757600080fd5b6112b8826020830160208601610ddd565b95945050505050565b60a0815260006112d460a0830188610e01565b82810360208401526112e68188610e01565b905082810360408401526112fa8187610e01565b9050828103606084015261130e8186610e01565b905082810360808401526113228185610e01565b98975050505050505050565b600181811c9082168061134257607f821691505b60208210810361137b577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b838110156113f6577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030185526113e4868351610e01565b955093820193908201906001016113aa565b5050858403818701525050506112b88185610e01565b600081546114198161132e565b808552602060018381168015611436576001811461146e5761149c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b890101955061149c565b866000528260002060005b858110156114945781548a8201860152908301908401611479565b890184019650505b505050505092915050565b60a0815260006114ba60a083018861140c565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b8381101561152c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe087840301855261151a838361140c565b948601949250600191820191016114e1565b50508681036040880152611540818b61140c565b94505050505084606084015282810360808401526113228185610e01565b601f821115610b7257600081815260208120601f850160051c810160208610156115855750805b601f850160051c820191505b818110156115a457828155600101611591565b505050505050565b815167ffffffffffffffff8111156115c6576115c6610e65565b6115da816115d4845461132e565b8461155e565b602080601f83116001811461162d57600084156115f75750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556115a4565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561167a5788860151825594840194600190910190840161165b565b50858210156116b657878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b81810381811115611215576112156111d356fea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_testRange\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_useArbBlock\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_staging\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_verify\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"v0\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"verifiedV0\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"ed\",\"type\":\"bytes\"}],\"name\":\"MercuryPerformEvent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"callbackReturnBool\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"eligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feeds\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"interval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previousPerformBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"value\",\"type\":\"bool\"}],\"name\":\"setCallbackReturnBool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_feeds\",\"type\":\"string[]\"}],\"name\":\"setFeeds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_timeParamKey\",\"type\":\"string\"}],\"name\":\"setParamKeys\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"value\",\"type\":\"bool\"}],\"name\":\"setShouldRevertCallback\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"shouldRevertCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"staging\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testRange\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbBlock\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b5060405162001a6a38038062001a6a83398101604081905262000034916200020f565b60008581556001859055600281905560038190556004558215156080526040805180820190915260078152666665656449447360c81b60208201526006906200007e908262000312565b50604080518082019091526009815268074696d657374616d760bc1b6020820152600790620000ae908262000312565b50604051806020016040528060405180608001604052806042815260200162001a28604291399052620000e690600590600162000122565b506008805463ff000000199215156101000261ff00199415159490941661ffff19909116179290921716630100000017905550620003de915050565b8280548282559060005260206000209081019282156200016d579160200282015b828111156200016d57825182906200015c908262000312565b509160200191906001019062000143565b506200017b9291506200017f565b5090565b808211156200017b576000620001968282620001a0565b506001016200017f565b508054620001ae9062000283565b6000825580601f10620001bf575050565b601f016020900490600052602060002090810190620001df9190620001e2565b50565b5b808211156200017b5760008155600101620001e3565b805180151581146200020a57600080fd5b919050565b600080600080600060a086880312156200022857600080fd5b85519450602086015193506200024160408701620001f9565b92506200025160608701620001f9565b91506200026160808701620001f9565b90509295509295909350565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200029857607f821691505b602082108103620002b957634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200030d57600081815260208120601f850160051c81016020861015620002e85750805b601f850160051c820191505b818110156200030957828155600101620002f4565b5050505b505050565b81516001600160401b038111156200032e576200032e6200026d565b62000346816200033f845462000283565b84620002bf565b602080601f8311600181146200037e5760008415620003655750858301515b600019600386901b1c1916600185901b17855562000309565b600085815260208120601f198616915b82811015620003af578886015182559484019460019091019084016200038e565b5085821015620003ce5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6080516116196200040f60003960008181610307015281816103900152818161090c0152610a7b01526116196000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c80636e04ff0d116100d8578063947a36fb1161008c578063d826f88f11610066578063d826f88f1461035e578063d832d92f14610372578063fc735e991461037a57600080fd5b8063947a36fb14610345578063afb28d1f1461034e578063c98f10b01461035657600080fd5b806386b728e2116100bd57806386b728e21461030257806386e330af14610329578063917d895f1461033c57600080fd5b80636e04ff0d146102dc5780638340507c146102ef57600080fd5b80634a5479f31161013a5780635b48391a116101145780635b48391a1461028357806361bc221a146102ca5780636250a13a146102d357600080fd5b80634a5479f3146101fc5780634b56a42e1461021c5780634bdb38621461023d57600080fd5b80631d1970b71161016b5780631d1970b7146101c35780632cb15864146101d05780634585e33b146101e757600080fd5b806302be021f14610187578063102d538b146101af575b600080fd5b60085461019a9062010000900460ff1681565b60405190151581526020015b60405180910390f35b60085461019a906301000000900460ff1681565b60085461019a9060ff1681565b6101d960035481565b6040519081526020016101a6565b6101fa6101f5366004610c0f565b61038c565b005b61020f61020a366004610c81565b6106b9565b6040516101a69190610d08565b61022f61022a366004610e60565b610765565b6040516101a6929190610f34565b6101fa61024b366004610f57565b6008805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff909216919091179055565b6101fa610291366004610f57565b600880549115156301000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff909216919091179055565b6101d960045481565b6101d960005481565b61022f6102ea366004610c0f565b610840565b6101fa6102fd366004610f79565b610a16565b61019a7f000000000000000000000000000000000000000000000000000000000000000081565b6101fa610337366004610fc6565b610a34565b6101d960025481565b6101d960015481565b61020f610a4b565b61020f610a58565b6101fa600060028190556003819055600455565b61019a610a65565b60085461019a90610100900460ff1681565b60007f00000000000000000000000000000000000000000000000000000000000000001561042b57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610400573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104249190611077565b905061042e565b50435b60035460000361043e5760038190555b60008061044d84860186610e60565b600285905560045491935091506104659060016110bf565b600455604080516020808201835260008083528351918201909352918252600854909190610100900460ff16156106435760085460ff1615610574577360448b880c9f3b501af3f343da9284148bd7d77c73ffffffffffffffffffffffffffffffffffffffff16638e760afe856000815181106104e4576104e46110d8565b60200260200101516040518263ffffffff1660e01b81526004016105089190610d08565b6000604051808303816000875af1158015610527573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261056d9190810190611107565b9150610643565b7309dff56a4ff44e0f4436260a04f5cfa65636a48173ffffffffffffffffffffffffffffffffffffffff16638e760afe856000815181106105b7576105b76110d8565b60200260200101516040518263ffffffff1660e01b81526004016105db9190610d08565b6000604051808303816000875af11580156105fa573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526106409190810190611107565b91505b843373ffffffffffffffffffffffffffffffffffffffff167ff0f72c0b235fc8687d6a67c02ca543473a3cef8a18b48490f10e475a8dda13908660008151811061068f5761068f6110d8565b602002602001015185876040516106a89392919061117e565b60405180910390a350505050505050565b600581815481106106c957600080fd5b9060005260206000200160009150905080546106e4906111c1565b80601f0160208091040260200160405190810160405280929190818152602001828054610710906111c1565b801561075d5780601f106107325761010080835404028352916020019161075d565b820191906000526020600020905b81548152906001019060200180831161074057829003601f168201915b505050505081565b60085460009060609062010000900460ff16156107e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f73686f756c6452657665727443616c6c6261636b20697320747275650000000060448201526064015b60405180910390fd5b600084846040516020016107f8929190611214565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526008546301000000900460ff1693509150505b9250929050565b6000606061084c610a65565b610898576000848481818080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250959750919550610839945050505050565b6040517f666565644964486578000000000000000000000000000000000000000000000060208201526000906029016040516020818303038152906040528051906020012060066040516020016108ef919061129f565b60405160208183030381529060405280519060200120036109ae577f0000000000000000000000000000000000000000000000000000000000000000156109a757606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561097c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109a09190611077565b90506109b1565b50436109b1565b50425b604080516c6400000000000000000000000060208201528151601481830301815260348201928390527ff055e4a2000000000000000000000000000000000000000000000000000000009092526107da916006916005916007918691906038016113ce565b6006610a2283826114df565b506007610a2f82826114df565b505050565b8051610a47906005906020840190610b4a565b5050565b600680546106e4906111c1565b600780546106e4906111c1565b6000600354600003610a775750600190565b60007f000000000000000000000000000000000000000000000000000000000000000015610b1657606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610aeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0f9190611077565b9050610b19565b50435b600054600354610b2990836115f9565b108015610b445750600154600254610b4190836115f9565b10155b91505090565b828054828255906000526020600020908101928215610b90579160200282015b82811115610b905782518290610b8090826114df565b5091602001919060010190610b6a565b50610b9c929150610ba0565b5090565b80821115610b9c576000610bb48282610bbd565b50600101610ba0565b508054610bc9906111c1565b6000825580601f10610bd9575050565b601f016020900490600052602060002090810190610bf79190610bfa565b50565b5b80821115610b9c5760008155600101610bfb565b60008060208385031215610c2257600080fd5b823567ffffffffffffffff80821115610c3a57600080fd5b818501915085601f830112610c4e57600080fd5b813581811115610c5d57600080fd5b866020828501011115610c6f57600080fd5b60209290920196919550909350505050565b600060208284031215610c9357600080fd5b5035919050565b60005b83811015610cb5578181015183820152602001610c9d565b50506000910152565b60008151808452610cd6816020860160208601610c9a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610d1b6020830184610cbe565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d9857610d98610d22565b604052919050565b600067ffffffffffffffff821115610dba57610dba610d22565b5060051b60200190565b600067ffffffffffffffff821115610dde57610dde610d22565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112610e1b57600080fd5b8135610e2e610e2982610dc4565b610d51565b818152846020838601011115610e4357600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215610e7357600080fd5b823567ffffffffffffffff80821115610e8b57600080fd5b818501915085601f830112610e9f57600080fd5b81356020610eaf610e2983610da0565b82815260059290921b84018101918181019089841115610ece57600080fd5b8286015b84811015610f0657803586811115610eea5760008081fd5b610ef88c86838b0101610e0a565b845250918301918301610ed2565b5096505086013592505080821115610f1d57600080fd5b50610f2a85828601610e0a565b9150509250929050565b8215158152604060208201526000610f4f6040830184610cbe565b949350505050565b600060208284031215610f6957600080fd5b81358015158114610d1b57600080fd5b60008060408385031215610f8c57600080fd5b823567ffffffffffffffff80821115610fa457600080fd5b610fb086838701610e0a565b93506020850135915080821115610f1d57600080fd5b60006020808385031215610fd957600080fd5b823567ffffffffffffffff80821115610ff157600080fd5b818501915085601f83011261100557600080fd5b8135611013610e2982610da0565b81815260059190911b8301840190848101908883111561103257600080fd5b8585015b8381101561106a5780358581111561104e5760008081fd5b61105c8b89838a0101610e0a565b845250918601918601611036565b5098975050505050505050565b60006020828403121561108957600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156110d2576110d2611090565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561111957600080fd5b815167ffffffffffffffff81111561113057600080fd5b8201601f8101841361114157600080fd5b805161114f610e2982610dc4565b81815285602083850101111561116457600080fd5b611175826020830160208601610c9a565b95945050505050565b6060815260006111916060830186610cbe565b82810360208401526111a38186610cbe565b905082810360408401526111b78185610cbe565b9695505050505050565b600181811c908216806111d557607f821691505b60208210810361120e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015611289577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018552611277868351610cbe565b9550938201939082019060010161123d565b5050858403818701525050506111758185610cbe565b60008083546112ad816111c1565b600182811680156112c557600181146112f857611327565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0084168752821515830287019450611327565b8760005260208060002060005b8581101561131e5781548a820152908401908201611305565b50505082870194505b50929695505050505050565b60008154611340816111c1565b80855260206001838116801561135d5760018114611395576113c3565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b89010195506113c3565b866000528260002060005b858110156113bb5781548a82018601529083019084016113a0565b890184019650505b505050505092915050565b60a0815260006113e160a0830188611333565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b83811015611453577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030185526114418383611333565b94860194925060019182019101611408565b50508681036040880152611467818b611333565b94505050505084606084015282810360808401526114858185610cbe565b98975050505050505050565b601f821115610a2f57600081815260208120601f850160051c810160208610156114b85750805b601f850160051c820191505b818110156114d7578281556001016114c4565b505050505050565b815167ffffffffffffffff8111156114f9576114f9610d22565b61150d8161150784546111c1565b84611491565b602080601f831160018114611560576000841561152a5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556114d7565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156115ad5788860151825594840194600190910190840161158e565b50858210156115e957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b818103818111156110d2576110d261109056fea164736f6c6343000810000a307830303032386339313564366166306664363662626132643066633934303532323662636138643638303633333331323161376439383332313033643135363363", } var StreamsLookupUpkeepABI = StreamsLookupUpkeepMetaData.ABI @@ -661,9 +661,7 @@ type StreamsLookupUpkeepMercuryPerformEvent struct { Sender common.Address BlockNumber *big.Int V0 []byte - V1 []byte VerifiedV0 []byte - VerifiedV1 []byte Ed []byte Raw types.Log } @@ -749,7 +747,7 @@ func (_StreamsLookupUpkeep *StreamsLookupUpkeep) ParseLog(log types.Log) (genera } func (StreamsLookupUpkeepMercuryPerformEvent) Topic() common.Hash { - return common.HexToHash("0x1c85d6186f024e964616014c8247533455ec5129a5095711202292f8a7ea1d54") + return common.HexToHash("0xf0f72c0b235fc8687d6a67c02ca543473a3cef8a18b48490f10e475a8dda1390") } func (_StreamsLookupUpkeep *StreamsLookupUpkeep) Address() common.Address { diff --git a/core/gethwrappers/generated/trusted_blockhash_store/trusted_blockhash_store.go b/core/gethwrappers/generated/trusted_blockhash_store/trusted_blockhash_store.go index 0ddddead4bd..27f7c4ebbb5 100644 --- a/core/gethwrappers/generated/trusted_blockhash_store/trusted_blockhash_store.go +++ b/core/gethwrappers/generated/trusted_blockhash_store/trusted_blockhash_store.go @@ -32,7 +32,7 @@ var ( var TrustedBlockhashStoreMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"whitelist\",\"type\":\"address[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidRecentBlockhash\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrustedBlockhashes\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInWhitelist\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getBlockhash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_whitelist\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_whitelistStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"whitelist\",\"type\":\"address[]\"}],\"name\":\"setWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"store\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"storeEarliest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"blockNums\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"blockhashes\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"recentBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"recentBlockhash\",\"type\":\"bytes32\"}],\"name\":\"storeTrusted\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"header\",\"type\":\"bytes\"}],\"name\":\"storeVerifyHeader\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b50604051620014db380380620014db8339810160408190526200003491620003e8565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d9565b505050620000d2816200018560201b60201c565b5062000517565b6001600160a01b038116331415620001345760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200018f620002ec565b60006004805480602002602001604051908101604052809291908181526020018280548015620001e957602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311620001ca575b5050855193945062000207936004935060208701925090506200034a565b5060005b81518110156200027757600060036000848481518110620002305762000230620004eb565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055806200026e81620004c1565b9150506200020b565b5060005b8251811015620002e757600160036000858481518110620002a057620002a0620004eb565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff191691151591909117905580620002de81620004c1565b9150506200027b565b505050565b6000546001600160a01b03163314620003485760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b828054828255906000526020600020908101928215620003a2579160200282015b82811115620003a257825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906200036b565b50620003b0929150620003b4565b5090565b5b80821115620003b05760008155600101620003b5565b80516001600160a01b0381168114620003e357600080fd5b919050565b60006020808385031215620003fc57600080fd5b82516001600160401b03808211156200041457600080fd5b818501915085601f8301126200042957600080fd5b8151818111156200043e576200043e62000501565b8060051b604051601f19603f8301168101818110858211171562000466576200046662000501565b604052828152858101935084860182860187018a10156200048657600080fd5b600095505b83861015620004b4576200049f81620003cb565b8552600195909501949386019386016200048b565b5098975050505050505050565b6000600019821415620004e457634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b610fb480620005276000396000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80638da5cb5b11610081578063f2fde38b1161005b578063f2fde38b146101b5578063f4217648146101c8578063fadff0e1146101db57600080fd5b80638da5cb5b14610143578063e9413d3814610161578063e9ecc1541461018257600080fd5b80636057361d116100b25780636057361d1461012057806379ba50971461013357806383b6d6b71461013b57600080fd5b80633b69ad60146100ce5780635c7de309146100e3575b600080fd5b6100e16100dc366004610cf6565b6101ee565b005b6100f66100f1366004610d8d565b610326565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100e161012e366004610d8d565b61035d565b6100e16103e8565b6100e16104e5565b60005473ffffffffffffffffffffffffffffffffffffffff166100f6565b61017461016f366004610d8d565b6104ff565b604051908152602001610117565b6101a5610190366004610c27565b60036020526000908152604090205460ff1681565b6040519015158152602001610117565b6100e16101c3366004610c27565b61057b565b6100e16101d6366004610c42565b61058f565b6100e16101e9366004610da6565b610745565b60006101f9836107e8565b9050818114610234576040517fd2f69c9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526003602052604090205460ff1661027d576040517f5b0aa2ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8584146102b6576040517fbd75093300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8681101561031c578585828181106102d3576102d3610f49565b90506020020135600260008a8a858181106102f0576102f0610f49565b90506020020135815260200190815260200160002081905550808061031490610ee1565b9150506102b9565b5050505050505050565b6004818154811061033657600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b6000610368826107e8565b9050806103d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f626c6f636b68617368286e29206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60009182526002602052604090912055565b60015473ffffffffffffffffffffffffffffffffffffffff163314610469576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016103cd565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6104fd6101006104f36108f6565b61012e9190610eca565b565b60008181526002602052604081205480610575576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f626c6f636b68617368206e6f7420666f756e6420696e2073746f72650000000060448201526064016103cd565b92915050565b61058361099c565b61058c81610a1d565b50565b61059761099c565b600060048054806020026020016040519081016040528092919081815260200182805480156105fc57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116105d1575b5050855193945061061893600493506020870192509050610b13565b5060005b81518110156106ac5760006003600084848151811061063d5761063d610f49565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055806106a481610ee1565b91505061061c565b5060005b8251811015610740576001600360008584815181106106d1576106d1610f49565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558061073881610ee1565b9150506106b0565b505050565b60026000610754846001610eb2565b8152602001908152602001600020548180519060200120146107d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f6865616465722068617320756e6b6e6f776e20626c6f636b686173680000000060448201526064016103cd565b6024015160009182526002602052604090912055565b60004661a4b18114806107fd575062066eed81145b156108e6576101008367ffffffffffffffff166108186108f6565b6108229190610eca565b118061083f57506108316108f6565b8367ffffffffffffffff1610155b1561084d5750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152606490632b407a829060240160206040518083038186803b1580156108a757600080fd5b505afa1580156108bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108df9190610d74565b9392505050565b505067ffffffffffffffff164090565b60004661a4b181148061090b575062066eed81145b1561099557606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561095757600080fd5b505afa15801561096b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098f9190610d74565b91505090565b4391505090565b60005473ffffffffffffffffffffffffffffffffffffffff1633146104fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103cd565b73ffffffffffffffffffffffffffffffffffffffff8116331415610a9d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103cd565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610b8d579160200282015b82811115610b8d57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190610b33565b50610b99929150610b9d565b5090565b5b80821115610b995760008155600101610b9e565b803573ffffffffffffffffffffffffffffffffffffffff81168114610bd657600080fd5b919050565b60008083601f840112610bed57600080fd5b50813567ffffffffffffffff811115610c0557600080fd5b6020830191508360208260051b8501011115610c2057600080fd5b9250929050565b600060208284031215610c3957600080fd5b6108df82610bb2565b60006020808385031215610c5557600080fd5b823567ffffffffffffffff80821115610c6d57600080fd5b818501915085601f830112610c8157600080fd5b813581811115610c9357610c93610f78565b8060051b9150610ca4848301610e63565b8181528481019084860184860187018a1015610cbf57600080fd5b600095505b83861015610ce957610cd581610bb2565b835260019590950194918601918601610cc4565b5098975050505050505050565b60008060008060008060808789031215610d0f57600080fd5b863567ffffffffffffffff80821115610d2757600080fd5b610d338a838b01610bdb565b90985096506020890135915080821115610d4c57600080fd5b50610d5989828a01610bdb565b979a9699509760408101359660609091013595509350505050565b600060208284031215610d8657600080fd5b5051919050565b600060208284031215610d9f57600080fd5b5035919050565b60008060408385031215610db957600080fd5b8235915060208084013567ffffffffffffffff80821115610dd957600080fd5b818601915086601f830112610ded57600080fd5b813581811115610dff57610dff610f78565b610e2f847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610e63565b91508082528784828501011115610e4557600080fd5b80848401858401376000848284010152508093505050509250929050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610eaa57610eaa610f78565b604052919050565b60008219821115610ec557610ec5610f1a565b500190565b600082821015610edc57610edc610f1a565b500390565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610f1357610f13610f1a565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x60806040523480156200001157600080fd5b50604051620014e8380380620014e88339810160408190526200003491620003e8565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d9565b505050620000d2816200018560201b60201c565b5062000517565b6001600160a01b038116331415620001345760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200018f620002ec565b60006004805480602002602001604051908101604052809291908181526020018280548015620001e957602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311620001ca575b5050855193945062000207936004935060208701925090506200034a565b5060005b81518110156200027757600060036000848481518110620002305762000230620004eb565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055806200026e81620004c1565b9150506200020b565b5060005b8251811015620002e757600160036000858481518110620002a057620002a0620004eb565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff191691151591909117905580620002de81620004c1565b9150506200027b565b505050565b6000546001600160a01b03163314620003485760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b828054828255906000526020600020908101928215620003a2579160200282015b82811115620003a257825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906200036b565b50620003b0929150620003b4565b5090565b5b80821115620003b05760008155600101620003b5565b80516001600160a01b0381168114620003e357600080fd5b919050565b60006020808385031215620003fc57600080fd5b82516001600160401b03808211156200041457600080fd5b818501915085601f8301126200042957600080fd5b8151818111156200043e576200043e62000501565b8060051b604051601f19603f8301168101818110858211171562000466576200046662000501565b604052828152858101935084860182860187018a10156200048657600080fd5b600095505b83861015620004b4576200049f81620003cb565b8552600195909501949386019386016200048b565b5098975050505050505050565b6000600019821415620004e457634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b610fc180620005276000396000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80638da5cb5b11610081578063f2fde38b1161005b578063f2fde38b146101b5578063f4217648146101c8578063fadff0e1146101db57600080fd5b80638da5cb5b14610143578063e9413d3814610161578063e9ecc1541461018257600080fd5b80636057361d116100b25780636057361d1461012057806379ba50971461013357806383b6d6b71461013b57600080fd5b80633b69ad60146100ce5780635c7de309146100e3575b600080fd5b6100e16100dc366004610d03565b6101ee565b005b6100f66100f1366004610d9a565b610326565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100e161012e366004610d9a565b61035d565b6100e16103e8565b6100e16104e5565b60005473ffffffffffffffffffffffffffffffffffffffff166100f6565b61017461016f366004610d9a565b6104ff565b604051908152602001610117565b6101a5610190366004610c34565b60036020526000908152604090205460ff1681565b6040519015158152602001610117565b6100e16101c3366004610c34565b61057b565b6100e16101d6366004610c4f565b61058f565b6100e16101e9366004610db3565b610745565b60006101f9836107e8565b9050818114610234576040517fd2f69c9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526003602052604090205460ff1661027d576040517f5b0aa2ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8584146102b6576040517fbd75093300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8681101561031c578585828181106102d3576102d3610f56565b90506020020135600260008a8a858181106102f0576102f0610f56565b90506020020135815260200190815260200160002081905550808061031490610eee565b9150506102b9565b5050505050505050565b6004818154811061033657600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b6000610368826107e8565b9050806103d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f626c6f636b68617368286e29206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60009182526002602052604090912055565b60015473ffffffffffffffffffffffffffffffffffffffff163314610469576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016103cd565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6104fd6101006104f3610903565b61012e9190610ed7565b565b60008181526002602052604081205480610575576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f626c6f636b68617368206e6f7420666f756e6420696e2073746f72650000000060448201526064016103cd565b92915050565b6105836109a9565b61058c81610a2a565b50565b6105976109a9565b600060048054806020026020016040519081016040528092919081815260200182805480156105fc57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116105d1575b5050855193945061061893600493506020870192509050610b20565b5060005b81518110156106ac5760006003600084848151811061063d5761063d610f56565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055806106a481610eee565b91505061061c565b5060005b8251811015610740576001600360008584815181106106d1576106d1610f56565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558061073881610eee565b9150506106b0565b505050565b60026000610754846001610ebf565b8152602001908152602001600020548180519060200120146107d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f6865616465722068617320756e6b6e6f776e20626c6f636b686173680000000060448201526064016103cd565b6024015160009182526002602052604090912055565b60004661a4b18114806107fd575062066eed81145b8061080a575062066eee81145b156108f3576101008367ffffffffffffffff16610825610903565b61082f9190610ed7565b118061084c575061083e610903565b8367ffffffffffffffff1610155b1561085a5750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152606490632b407a829060240160206040518083038186803b1580156108b457600080fd5b505afa1580156108c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ec9190610d81565b9392505050565b505067ffffffffffffffff164090565b60004661a4b1811480610918575062066eed81145b156109a257606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561096457600080fd5b505afa158015610978573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099c9190610d81565b91505090565b4391505090565b60005473ffffffffffffffffffffffffffffffffffffffff1633146104fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103cd565b73ffffffffffffffffffffffffffffffffffffffff8116331415610aaa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103cd565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610b9a579160200282015b82811115610b9a57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190610b40565b50610ba6929150610baa565b5090565b5b80821115610ba65760008155600101610bab565b803573ffffffffffffffffffffffffffffffffffffffff81168114610be357600080fd5b919050565b60008083601f840112610bfa57600080fd5b50813567ffffffffffffffff811115610c1257600080fd5b6020830191508360208260051b8501011115610c2d57600080fd5b9250929050565b600060208284031215610c4657600080fd5b6108ec82610bbf565b60006020808385031215610c6257600080fd5b823567ffffffffffffffff80821115610c7a57600080fd5b818501915085601f830112610c8e57600080fd5b813581811115610ca057610ca0610f85565b8060051b9150610cb1848301610e70565b8181528481019084860184860187018a1015610ccc57600080fd5b600095505b83861015610cf657610ce281610bbf565b835260019590950194918601918601610cd1565b5098975050505050505050565b60008060008060008060808789031215610d1c57600080fd5b863567ffffffffffffffff80821115610d3457600080fd5b610d408a838b01610be8565b90985096506020890135915080821115610d5957600080fd5b50610d6689828a01610be8565b979a9699509760408101359660609091013595509350505050565b600060208284031215610d9357600080fd5b5051919050565b600060208284031215610dac57600080fd5b5035919050565b60008060408385031215610dc657600080fd5b8235915060208084013567ffffffffffffffff80821115610de657600080fd5b818601915086601f830112610dfa57600080fd5b813581811115610e0c57610e0c610f85565b610e3c847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610e70565b91508082528784828501011115610e5257600080fd5b80848401858401376000848284010152508093505050509250929050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610eb757610eb7610f85565b604052919050565b60008219821115610ed257610ed2610f27565b500190565b600082821015610ee957610ee9610f27565b500390565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610f2057610f20610f27565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", } var TrustedBlockhashStoreABI = TrustedBlockhashStoreMetaData.ABI diff --git a/core/gethwrappers/generated/verifiable_load_log_trigger_upkeep_wrapper/verifiable_load_log_trigger_upkeep_wrapper.go b/core/gethwrappers/generated/verifiable_load_log_trigger_upkeep_wrapper/verifiable_load_log_trigger_upkeep_wrapper.go index d88f15f96a2..8fda91a42a6 100644 --- a/core/gethwrappers/generated/verifiable_load_log_trigger_upkeep_wrapper/verifiable_load_log_trigger_upkeep_wrapper.go +++ b/core/gethwrappers/generated/verifiable_load_log_trigger_upkeep_wrapper/verifiable_load_log_trigger_upkeep_wrapper.go @@ -56,7 +56,7 @@ type Log struct { var VerifiableLoadLogTriggerUpkeepMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"_registrar\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_useArb\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_useMercury\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"LogEmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"LogEmittedAgain\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"UpkeepTopUp\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BUCKET_SIZE\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"addLinkAmount\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchCancelUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"topic0\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic1\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic2\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic3\",\"type\":\"bytes32\"}],\"name\":\"batchPreparingUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"type\":\"uint8\"}],\"name\":\"batchPreparingUpkeepsSimple\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"number\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"checkGasToBurn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"performGasToBurn\",\"type\":\"uint256\"}],\"name\":\"batchRegisterUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"}],\"name\":\"batchSendLogs\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"interval\",\"type\":\"uint32\"}],\"name\":\"batchSetIntervals\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchUpdatePipelineData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchWithdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"bucketedDelays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"buckets\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"burnPerformGas\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"checkGasToBurns\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"txIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"source\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"topics\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structLog\",\"name\":\"log\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"checkLog\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"counters\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"delays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"dummyMap\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"eligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emittedAgainSig\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emittedSig\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feedsHex\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"firstPerformBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"gasLimits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveUpkeepIDsDeployedByThisContract\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getAllActiveUpkeepIDsOnRegistry\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"bucket\",\"type\":\"uint16\"}],\"name\":\"getBucketedDelays\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getBucketedDelaysLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getDelays\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getDelaysLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"topic0\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic1\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic2\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic3\",\"type\":\"bytes32\"}],\"name\":\"getLogTriggerConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"logTrigger\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getMinBalanceForUpkeep\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"p\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getPxDelayLastNPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"bucket\",\"type\":\"uint16\"}],\"name\":\"getSumDelayInBucket\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getSumDelayLastNPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getTriggerType\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepInfo\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"maxValidBlocknumber\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"lastPerformedBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"amountSpent\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structKeeperRegistryBase2_1.UpkeepInfo\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepPrivilegeConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepTriggerConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"intervals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"lastTopUpBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkToken\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"logNum\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minBalanceThresholdMultiplier\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"performDataSizes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"performGasToBurns\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"previousPerformBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registrar\",\"outputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registry\",\"outputs\":[{\"internalType\":\"contractIKeeperRegistryMaster\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"}],\"name\":\"sendLog\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"newRegistrar\",\"type\":\"address\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_feeds\",\"type\":\"string[]\"}],\"name\":\"setFeeds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"}],\"name\":\"setInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_log\",\"type\":\"uint8\"}],\"name\":\"setLog\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_timeParamKey\",\"type\":\"string\"}],\"name\":\"setParamKeys\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setPerformDataSize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"cfg\",\"type\":\"bytes\"}],\"name\":\"setUpkeepPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"topUpFund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"topic0\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic1\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic2\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic3\",\"type\":\"bytes32\"}],\"name\":\"updateLogTriggerConfig1\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"cfg\",\"type\":\"bytes\"}],\"name\":\"updateLogTriggerConfig2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"pipelineData\",\"type\":\"bytes\"}],\"name\":\"updateUpkeepPipelineData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepTopUpCheckInterval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbitrumBlockNum\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useMercury\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"withdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x7f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf086080527fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d60a0526005601455601580546001600160681b0319166c140000000002c68af0bb140000179055606460e0526101c0604052604261014081815261010091829190620065b6610160398152602001604051806080016040528060428152602001620065f8604291399052620000be906016906002620003de565b506040805180820190915260098152680cccacac892c890caf60bb1b6020820152601790620000ee90826200055a565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b60208201526018906200012090826200055a565b503480156200012e57600080fd5b506040516200663a3803806200663a833981016040819052620001519162000652565b82823380600081620001aa5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620001dd57620001dd8162000333565b5050601180546001600160a01b0319166001600160a01b038516908117909155604080516330fe427560e21b815281516000945063c3f909d4926004808401939192918290030181865afa1580156200023a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200026091906200069e565b50601380546001600160a01b0319166001600160a01b038381169190911790915560115460408051631b6b6d2360e01b81529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015620002c6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ec9190620006cf565b601280546001600160a01b0319166001600160a01b039290921691909117905550151560c052506019805461ffff191691151561ff00191691909117905550620006f69050565b336001600160a01b038216036200038d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620001a1565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b82805482825590600052602060002090810192821562000429579160200282015b828111156200042957825182906200041890826200055a565b5091602001919060010190620003ff565b50620004379291506200043b565b5090565b80821115620004375760006200045282826200045c565b506001016200043b565b5080546200046a90620004cb565b6000825580601f106200047b575050565b601f0160209004906000526020600020908101906200049b91906200049e565b50565b5b808211156200043757600081556001016200049f565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620004e057607f821691505b6020821081036200050157634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200055557600081815260208120601f850160051c81016020861015620005305750805b601f850160051c820191505b8181101562000551578281556001016200053c565b5050505b505050565b81516001600160401b03811115620005765762000576620004b5565b6200058e81620005878454620004cb565b8462000507565b602080601f831160018114620005c65760008415620005ad5750858301515b600019600386901b1c1916600185901b17855562000551565b600085815260208120601f198616915b82811015620005f757888601518255948401946001909101908401620005d6565b5085821015620006165787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b03811681146200049b57600080fd5b805180151581146200064d57600080fd5b919050565b6000806000606084860312156200066857600080fd5b8351620006758162000626565b925062000685602085016200063c565b915062000695604085016200063c565b90509250925092565b60008060408385031215620006b257600080fd5b8251620006bf8162000626565b6020939093015192949293505050565b600060208284031215620006e257600080fd5b8151620006ef8162000626565b9392505050565b60805160a05160c05160e051615e5c6200075a600039600081816105b901526124af015260008181610a2d0152613ff00152600081816108a601528181611fa80152613a3e015260008181610dca01528181611f780152613a130152615e5c6000f3fe6080604052600436106105265760003560e01c80637b103999116102af578063af953a4a11610179578063daee1aeb116100d6578063e83ce5581161008a578063fa333dfb1161006f578063fa333dfb14611066578063fba7ffa314611119578063fcdc1f631461114657600080fd5b8063e83ce55814611027578063f2fde38b1461104657600080fd5b8063de818253116100bb578063de81825314610f90578063e0114adb14610fe4578063e45530831461101157600080fd5b8063daee1aeb14610f50578063dbef701e14610f7057600080fd5b8063c41c815b1161012d578063d4c2490011610112578063d4c2490014610ef0578063d6051a7214610f10578063da6cba4714610f3057600080fd5b8063c41c815b14610ec1578063c98f10b014610edb57600080fd5b8063b657bc9c1161015e578063b657bc9c14610e61578063becde0e114610e81578063c041982214610ea157600080fd5b8063af953a4a14610e2c578063afb28d1f14610e4c57600080fd5b8063948108f7116102275780639d385eaa116101db578063a6548248116101c0578063a654824814610db8578063a6b5947514610dec578063a72aa27e14610e0c57600080fd5b80639d385eaa14610d785780639d6f1cc714610d9857600080fd5b80639ac542eb1161020c5780639ac542eb14610cf05780639b42935414610d1a5780639b51fb0d14610d4757600080fd5b8063948108f714610cb057806396cebc7c14610cd057600080fd5b806386e330af1161027e5780638da5cb5b116102635780638da5cb5b14610c385780638fcb3fba14610c63578063924ca57814610c9057600080fd5b806386e330af14610bf8578063873c758614610c1857600080fd5b80637b10399914610b6b5780637e7a46dc14610b985780638243444a14610bb85780638340507c14610bd857600080fd5b806345d2ec17116103f057806360457ff51161036857806373644cce1161031c578063776898c811610301578063776898c814610b1657806379ba509714610b3657806379ea994314610b4b57600080fd5b806373644cce14610abc5780637672130314610ae957600080fd5b8063642f6cef1161034d578063642f6cef14610a1b57806369cdbadb14610a5f5780637145f11b14610a8c57600080fd5b806360457ff5146109c9578063636092e8146109f657600080fd5b80635147cd59116103bf57806357970e93116103a457806357970e93146109675780635d4ee7f3146109945780635f17e616146109a957600080fd5b80635147cd591461091557806351c98be31461094757600080fd5b806345d2ec1714610867578063469820931461089457806346e7a63e146108c85780634b56a42e146108f557600080fd5b806320e3dbd41161049e5780632b20e397116104525780633ebe8d6c116104375780633ebe8d6c146107f957806340691db4146108195780634585e33b1461084757600080fd5b80632b20e3971461077a578063328ffd11146107cc57600080fd5b806328c4b57b1161048357806328c4b57b1461070d57806329e0a8411461072d5780632a9032d31461075a57600080fd5b806320e3dbd4146106cd5780632636aecf146106ed57600080fd5b806319d97a94116104f55780631e010439116104da5780631e0104391461063b578063206c32e814610678578063207b6516146106ad57600080fd5b806319d97a94146105ee5780631cdde2511461061b57600080fd5b806306c1cc0014610532578063077ac621146105545780630b7d33e61461058757806312c55027146105a757600080fd5b3661052d57005b600080fd5b34801561053e57600080fd5b5061055261054d366004614772565b611173565b005b34801561056057600080fd5b5061057461056f366004614825565b6113c2565b6040519081526020015b60405180910390f35b34801561059357600080fd5b506105526105a236600461485a565b611400565b3480156105b357600080fd5b506105db7f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff909116815260200161057e565b3480156105fa57600080fd5b5061060e6106093660046148a1565b61148e565b60405161057e9190614928565b34801561062757600080fd5b5061055261063636600461495d565b61154b565b34801561064757600080fd5b5061065b6106563660046148a1565b611688565b6040516bffffffffffffffffffffffff909116815260200161057e565b34801561068457600080fd5b506106986106933660046149c2565b61171d565b6040805192835260208301919091520161057e565b3480156106b957600080fd5b5061060e6106c83660046148a1565b6117a0565b3480156106d957600080fd5b506105526106e83660046149ee565b6117f8565b3480156106f957600080fd5b50610552610708366004614a50565b6119c2565b34801561071957600080fd5b50610574610728366004614aca565b611c8b565b34801561073957600080fd5b5061074d6107483660046148a1565b611cf6565b60405161057e9190614af6565b34801561076657600080fd5b50610552610775366004614c37565b611dfb565b34801561078657600080fd5b506011546107a79073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161057e565b3480156107d857600080fd5b506105746107e73660046148a1565b60036020526000908152604090205481565b34801561080557600080fd5b506105746108143660046148a1565b611edc565b34801561082557600080fd5b50610839610834366004614c79565b611f45565b60405161057e929190614cdc565b34801561085357600080fd5b50610552610862366004614d39565b6123a9565b34801561087357600080fd5b506108876108823660046149c2565b6125f8565b60405161057e9190614d6f565b3480156108a057600080fd5b506105747f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d457600080fd5b506105746108e33660046148a1565b600a6020526000908152604090205481565b34801561090157600080fd5b50610839610910366004614dd7565b612667565b34801561092157600080fd5b506109356109303660046148a1565b6126bb565b60405160ff909116815260200161057e565b34801561095357600080fd5b50610552610962366004614e94565b61274f565b34801561097357600080fd5b506012546107a79073ffffffffffffffffffffffffffffffffffffffff1681565b3480156109a057600080fd5b506105526127f3565b3480156109b557600080fd5b506105526109c4366004614eeb565b61292e565b3480156109d557600080fd5b506105746109e43660046148a1565b60076020526000908152604090205481565b348015610a0257600080fd5b5060155461065b906bffffffffffffffffffffffff1681565b348015610a2757600080fd5b50610a4f7f000000000000000000000000000000000000000000000000000000000000000081565b604051901515815260200161057e565b348015610a6b57600080fd5b50610574610a7a3660046148a1565b60086020526000908152604090205481565b348015610a9857600080fd5b50610a4f610aa73660046148a1565b600b6020526000908152604090205460ff1681565b348015610ac857600080fd5b50610574610ad73660046148a1565b6000908152600c602052604090205490565b348015610af557600080fd5b50610574610b043660046148a1565b60046020526000908152604090205481565b348015610b2257600080fd5b50610a4f610b313660046148a1565b6129fb565b348015610b4257600080fd5b50610552612a4d565b348015610b5757600080fd5b506107a7610b663660046148a1565b612b4a565b348015610b7757600080fd5b506013546107a79073ffffffffffffffffffffffffffffffffffffffff1681565b348015610ba457600080fd5b50610552610bb3366004614f0d565b612bde565b348015610bc457600080fd5b50610552610bd3366004614f0d565b612c6f565b348015610be457600080fd5b50610552610bf3366004614f59565b612cc9565b348015610c0457600080fd5b50610552610c13366004614fa6565b612ce7565b348015610c2457600080fd5b50610887610c33366004614eeb565b612cfa565b348015610c4457600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166107a7565b348015610c6f57600080fd5b50610574610c7e3660046148a1565b60056020526000908152604090205481565b348015610c9c57600080fd5b50610552610cab366004614eeb565b612db7565b348015610cbc57600080fd5b50610552610ccb366004615057565b612ffc565b348015610cdc57600080fd5b50610552610ceb366004615087565b613114565b348015610cfc57600080fd5b50601554610935906c01000000000000000000000000900460ff1681565b348015610d2657600080fd5b50610552610d35366004614eeb565b60009182526009602052604090912055565b348015610d5357600080fd5b506105db610d623660046148a1565b600e6020526000908152604090205461ffff1681565b348015610d8457600080fd5b50610887610d933660046148a1565b61331e565b348015610da457600080fd5b5061060e610db33660046148a1565b613380565b348015610dc457600080fd5b506105747f000000000000000000000000000000000000000000000000000000000000000081565b348015610df857600080fd5b50610552610e07366004614aca565b61342c565b348015610e1857600080fd5b50610552610e273660046150a4565b613495565b348015610e3857600080fd5b50610552610e473660046148a1565b613540565b348015610e5857600080fd5b5061060e6135c6565b348015610e6d57600080fd5b5061065b610e7c3660046148a1565b6135d3565b348015610e8d57600080fd5b50610552610e9c366004614c37565b61362b565b348015610ead57600080fd5b50610887610ebc366004614eeb565b6136c5565b348015610ecd57600080fd5b50601954610a4f9060ff1681565b348015610ee757600080fd5b5061060e6137c2565b348015610efc57600080fd5b50610552610f0b3660046150c9565b6137cf565b348015610f1c57600080fd5b50610698610f2b366004614eeb565b61384e565b348015610f3c57600080fd5b50610552610f4b3660046150ee565b6138b7565b348015610f5c57600080fd5b50610552610f6b366004614c37565b613c1e565b348015610f7c57600080fd5b50610574610f8b366004614eeb565b613ce9565b348015610f9c57600080fd5b50610552610fab366004615087565b6019805460ff909216610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909216919091179055565b348015610ff057600080fd5b50610574610fff3660046148a1565b60096020526000908152604090205481565b34801561101d57600080fd5b5061057460145481565b34801561103357600080fd5b5060195461093590610100900460ff1681565b34801561105257600080fd5b506105526110613660046149ee565b613d1a565b34801561107257600080fd5b5061060e611081366004615156565b6040805160c0808201835273ffffffffffffffffffffffffffffffffffffffff9890981680825260ff97881660208084019182528385019889526060808501988952608080860198895260a095860197885286519283019490945291519099168985015296519688019690965293519486019490945290519184019190915251828401528051808303909301835260e0909101905290565b34801561112557600080fd5b506105746111343660046148a1565b60066020526000908152604090205481565b34801561115257600080fd5b506105746111613660046148a1565b60026020526000908152604090205481565b6040805161018081018252600461014082019081527f746573740000000000000000000000000000000000000000000000000000000061016083015281528151602081810184526000808352818401929092523083850181905263ffffffff8b166060850152608084015260ff808a1660a08501528451808301865283815260c085015260e0840189905284519182019094529081526101008201526bffffffffffffffffffffffff8516610120820152601254601154919273ffffffffffffffffffffffffffffffffffffffff9182169263095ea7b3921690611259908c16886151de565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526bffffffffffffffffffffffff1660248201526044016020604051808303816000875af11580156112d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112fb9190615222565b5060008860ff1667ffffffffffffffff81111561131a5761131a614614565b604051908082528060200260200182016040528015611343578160200160208202803683370190505b50905060005b8960ff168160ff1610156113b657600061136284613d2e565b905080838360ff168151811061137a5761137a61523d565b602090810291909101810191909152600091825260088152604080832088905560079091529020849055806113ae8161526c565b915050611349565b50505050505050505050565b600d60205282600052604060002060205281600052604060002081815481106113ea57600080fd5b9060005260206000200160009250925050505481565b6013546040517f0b7d33e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690630b7d33e690611458908590859060040161528b565b600060405180830381600087803b15801561147257600080fd5b505af1158015611486573d6000803e3d6000fd5b505050505050565b6013546040517f19d97a940000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff16906319d97a94906024015b600060405180830381865afa1580156114ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261154591908101906152f1565b92915050565b6013546040517ffa333dfb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015260ff8816602483015260448201879052606482018690526084820185905260a4820184905290911690634ee88d35908990309063fa333dfb9060c401600060405180830381865afa1580156115ea573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261163091908101906152f1565b6040518363ffffffff1660e01b815260040161164d92919061528b565b600060405180830381600087803b15801561166757600080fd5b505af115801561167b573d6000803e3d6000fd5b5050505050505050505050565b6013546040517f1e0104390000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690631e010439906024015b602060405180830381865afa1580156116f9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115459190615331565b6000828152600d6020908152604080832061ffff85168452825280832080548251818502810185019093528083528493849392919083018282801561178157602002820191906000526020600020905b81548152602001906001019080831161176d575b50505050509050611793818251613dfc565b92509250505b9250929050565b6013546040517f207b65160000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063207b6516906024016114e2565b601180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155604080517fc3f909d400000000000000000000000000000000000000000000000000000000815281516000939263c3f909d492600480820193918290030181865afa15801561188e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b29190615359565b50601380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691909117909155601154604080517f1b6b6d230000000000000000000000000000000000000000000000000000000081529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015611955573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119799190615387565b601280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555050565b8560005b81811015611c805760008989838181106119e2576119e261523d565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc8283604051602001611a1b91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401611a4792919061528b565b600060405180830381600087803b158015611a6157600080fd5b505af1158015611a75573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015611aeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b0f91906153a4565b90508060ff16600103611c6b576040517ffa333dfb000000000000000000000000000000000000000000000000000000008152306004820181905260ff8b166024830152604482018a9052606482018890526084820188905260a4820187905260009163fa333dfb9060c401600060405180830381865afa158015611b98573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611bde91908101906152f1565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590611c37908690859060040161528b565b600060405180830381600087803b158015611c5157600080fd5b505af1158015611c65573d6000803e3d6000fd5b50505050505b50508080611c78906153c1565b9150506119c6565b505050505050505050565b6000838152600c602090815260408083208054825181850281018501909352808352611cec93830182828015611ce057602002820191906000526020600020905b815481526020019060010190808311611ccc575b50505050508484613e81565b90505b9392505050565b604080516101408101825260008082526020820181905260609282018390528282018190526080820181905260a0820181905260c0820181905260e082018190526101008201526101208101919091526013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c7c3a19a90602401600060405180830381865afa158015611db5573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611545919081019061541c565b8060005b818160ff161015611ed65760135473ffffffffffffffffffffffffffffffffffffffff1663c8048022858560ff8516818110611e3d57611e3d61523d565b905060200201356040518263ffffffff1660e01b8152600401611e6291815260200190565b600060405180830381600087803b158015611e7c57600080fd5b505af1158015611e90573d6000803e3d6000fd5b50505050611ec384848360ff16818110611eac57611eac61523d565b90506020020135600f613fe090919063ffffffff16565b5080611ece8161526c565b915050611dff565b50505050565b6000818152600e602052604081205461ffff1681805b8261ffff168161ffff1611611f3d576000858152600d6020908152604080832061ffff85168452909152902054611f29908361553b565b915080611f358161554e565b915050611ef2565b509392505050565b6000606060005a90506000611f58613fec565b9050600085806020019051810190611f70919061556f565b6019549091507f000000000000000000000000000000000000000000000000000000000000000090610100900460ff1615611fc857507f00000000000000000000000000000000000000000000000000000000000000005b80611fd660c08a018a615588565b6000818110611fe757611fe761523d565b905060200201350361234757600061200260c08a018a615588565b60018181106120135761201361523d565b9050602002013560405160200161202c91815260200190565b6040516020818303038152906040529050600081806020019051810190612053919061556f565b90508381146120c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f75706b6565702069647320646f6e2774206d617463680000000000000000000060448201526064015b60405180910390fd5b60006120d260c08c018c615588565b60028181106120e3576120e361523d565b905060200201356040516020016120fc91815260200190565b6040516020818303038152906040529050600081806020019051810190612123919061556f565b9050600061213460c08e018e615588565b60038181106121455761214561523d565b9050602002013560405160200161215e91815260200190565b60405160208183030381529060405290506000818060200190518101906121859190615387565b6000868152600860205260409020549091505b805a6121a4908d6155f0565b6121b090613a9861553b565b10156121f15783406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055612198565b60195460ff161561229957604080516020810188905290810185905273ffffffffffffffffffffffffffffffffffffffff831660608201526017906016906018908790608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527ff055e4a20000000000000000000000000000000000000000000000000000000082526120ba95949392916004016156f1565b60408051600280825260608201909252600091816020015b60608152602001906001900390816122b15790505060408051602081018a905290810187905273ffffffffffffffffffffffffffffffffffffffff851660608201529091506000906080016040516020818303038152906040529050600182826040516020016123229291906157b4565b6040516020818303038152906040529e509e5050505050505050505050505050611799565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f756e6578706563746564206576656e742073696700000000000000000000000060448201526064016120ba565b60005a90506000806123bd84860186614dd7565b915091506000806000838060200190518101906123da9190615848565b6000838152600560209081526040808320546004909252822054949750929550909350909190612408613fec565b90508260000361242857600086815260056020526040902081905561256c565b600061243486836155f0565b6000888152600e6020908152604080832054600d835281842061ffff9091168085529083528184208054835181860281018601909452808452959650909491929091908301828280156124a657602002820191906000526020600020905b815481526020019060010190808311612492575b505050505090507f000000000000000000000000000000000000000000000000000000000000000061ffff1681510361252157816124e38161554e565b60008b8152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83161790559250505b506000888152600d6020908152604080832061ffff9094168352928152828220805460018181018355918452828420018590558a8352600c8252928220805493840181558252902001555b60008681526006602052604081205461258690600161553b565b60008881526006602090815260408083208490556004909152902083905590506125b08783612db7565b6040513090839089907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a46125ea878b8461342c565b505050505050505050505050565b6000828152600d6020908152604080832061ffff8516845282529182902080548351818402810184019094528084526060939283018282801561265a57602002820191906000526020600020905b815481526020019060010190808311612646575b5050505050905092915050565b60006060600084846040516020016126809291906157b4565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526001969095509350505050565b6013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690635147cd5990602401602060405180830381865afa15801561272b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154591906153a4565b8160005b818110156127ec5730635f17e6168686848181106127735761277361523d565b90506020020135856040518363ffffffff1660e01b81526004016127a792919091825263ffffffff16602082015260400190565b600060405180830381600087803b1580156127c157600080fd5b505af11580156127d5573d6000803e3d6000fd5b5050505080806127e4906153c1565b915050612753565b5050505050565b6127fb61408e565b6012546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561286a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288e919061556f565b6012546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810183905291925073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015612906573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061292a9190615222565b5050565b60008281526003602090815260408083208490556005825280832083905560068252808320839055600c909152812061296691614513565b6000828152600e602052604081205461ffff16905b8161ffff168161ffff16116129c2576000848152600d6020908152604080832061ffff8516845290915281206129b091614513565b806129ba8161554e565b91505061297b565b5050506000908152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055565b6000818152600560205260408120548103612a1857506001919050565b600082815260036020908152604080832054600490925290912054612a3b613fec565b612a4591906155f0565b101592915050565b60015473ffffffffffffffffffffffffffffffffffffffff163314612ace576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016120ba565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6013546040517f79ea99430000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff16906379ea994390602401602060405180830381865afa158015612bba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115459190615387565b6013546040517fcd7f71b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063cd7f71b590612c3890869086908690600401615876565b600060405180830381600087803b158015612c5257600080fd5b505af1158015612c66573d6000803e3d6000fd5b50505050505050565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690634ee88d3590612c3890869086908690600401615876565b6017612cd58382615910565b506018612ce28282615910565b505050565b805161292a906016906020840190614531565b6013546040517f06e3b632000000000000000000000000000000000000000000000000000000008152600481018490526024810183905260609173ffffffffffffffffffffffffffffffffffffffff16906306e3b63290604401600060405180830381865afa158015612d71573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611cef9190810190615a2a565b601454600083815260026020526040902054612dd390836155f0565b111561292a576013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905260009173ffffffffffffffffffffffffffffffffffffffff169063c7c3a19a90602401600060405180830381865afa158015612e49573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612e8f919081019061541c565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810186905291925060009173ffffffffffffffffffffffffffffffffffffffff9091169063b657bc9c90602401602060405180830381865afa158015612f04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f289190615331565b601554909150612f4c9082906c01000000000000000000000000900460ff166151de565b6bffffffffffffffffffffffff1682606001516bffffffffffffffffffffffff161015611ed657601554612f8f9085906bffffffffffffffffffffffff16612ffc565b60008481526002602090815260409182902085905560155482518781526bffffffffffffffffffffffff909116918101919091529081018490527f49d4100ab0124eb4a9a65dc4ea08d6412a43f6f05c49194983f5b322bcc0a5c09060600160405180910390a150505050565b6012546013546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526bffffffffffffffffffffffff8416602482015291169063095ea7b3906044016020604051808303816000875af1158015613084573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130a89190615222565b506013546040517f948108f7000000000000000000000000000000000000000000000000000000008152600481018490526bffffffffffffffffffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063948108f790604401611458565b6040517fc04198220000000000000000000000000000000000000000000000000000000081526000600482018190526024820181905290309063c041982290604401600060405180830381865afa158015613173573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526131b99190810190615a2a565b805190915060006131c8613fec565b905060005b828110156127ec5760008482815181106131e9576131e961523d565b60209081029190910101516013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905291925060009173ffffffffffffffffffffffffffffffffffffffff90911690635147cd5990602401602060405180830381865afa158015613269573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061328d91906153a4565b90508060ff16600103613309578660ff166000036132d9576040513090859084907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4613309565b6040513090859084907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a45b50508080613316906153c1565b9150506131cd565b6000818152600c602090815260409182902080548351818402810184019094528084526060939283018282801561337457602002820191906000526020600020905b815481526020019060010190808311613360575b50505050509050919050565b6016818154811061339057600080fd5b9060005260206000200160009150905080546133ab90615603565b80601f01602080910402602001604051908101604052809291908181526020018280546133d790615603565b80156134245780601f106133f957610100808354040283529160200191613424565b820191906000526020600020905b81548152906001019060200180831161340757829003601f168201915b505050505081565b6000838152600760205260409020545b805a61344890856155f0565b6134549061271061553b565b1015611ed65781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905561343c565b6013546040517fa72aa27e0000000000000000000000000000000000000000000000000000000081526004810184905263ffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063a72aa27e90604401600060405180830381600087803b15801561350d57600080fd5b505af1158015613521573d6000803e3d6000fd5b505050600092835250600a602052604090912063ffffffff9091169055565b6013546040517f744bfe610000000000000000000000000000000000000000000000000000000081526004810183905230602482015273ffffffffffffffffffffffffffffffffffffffff9091169063744bfe6190604401600060405180830381600087803b1580156135b257600080fd5b505af11580156127ec573d6000803e3d6000fd5b601780546133ab90615603565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff169063b657bc9c906024016116dc565b8060005b818163ffffffff161015611ed6573063af953a4a858563ffffffff851681811061365b5761365b61523d565b905060200201356040518263ffffffff1660e01b815260040161368091815260200190565b600060405180830381600087803b15801561369a57600080fd5b505af11580156136ae573d6000803e3d6000fd5b5050505080806136bd90615abb565b91505061362f565b606060006136d3600f614111565b905080841061370e576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826000036137235761372084826155f0565b92505b60008367ffffffffffffffff81111561373e5761373e614614565b604051908082528060200260200182016040528015613767578160200160208202803683370190505b50905060005b848110156137b95761378a613782828861553b565b600f9061411b565b82828151811061379c5761379c61523d565b6020908102919091010152806137b1816153c1565b91505061376d565b50949350505050565b601880546133ab90615603565b60006137d9613fec565b90508160ff1660000361381a576040513090829085907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4505050565b6040513090829085907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a4505050565b6000828152600c602090815260408083208054825181850281018501909352808352849384939291908301828280156138a657602002820191906000526020600020905b815481526020019060010190808311613892575b505050505090506117938185613dfc565b8260005b818110156114865760008686838181106138d7576138d761523d565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc828360405160200161391091815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b815260040161393c92919061528b565b600060405180830381600087803b15801561395657600080fd5b505af115801561396a573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa1580156139e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a0491906153a4565b90508060ff16600103613c09577f000000000000000000000000000000000000000000000000000000000000000060ff871615613a5e57507f00000000000000000000000000000000000000000000000000000000000000005b60003073ffffffffffffffffffffffffffffffffffffffff1663fa333dfb30898588604051602001613a9291815260200190565b604051602081830303815290604052613aaa90615ad4565b60405160e086901b7fffffffff0000000000000000000000000000000000000000000000000000000016815273ffffffffffffffffffffffffffffffffffffffff909416600485015260ff90921660248401526044830152606482015260006084820181905260a482015260c401600060405180830381865afa158015613b35573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052613b7b91908101906152f1565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590613bd4908790859060040161528b565b600060405180830381600087803b158015613bee57600080fd5b505af1158015613c02573d6000803e3d6000fd5b5050505050505b50508080613c16906153c1565b9150506138bb565b8060005b81811015611ed6576000848483818110613c3e57613c3e61523d565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc8283604051602001613c7791815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401613ca392919061528b565b600060405180830381600087803b158015613cbd57600080fd5b505af1158015613cd1573d6000803e3d6000fd5b50505050508080613ce1906153c1565b915050613c22565b600c6020528160005260406000208181548110613d0557600080fd5b90600052602060002001600091509150505481565b613d2261408e565b613d2b81614127565b50565b6011546040517f3f678e11000000000000000000000000000000000000000000000000000000008152600091829173ffffffffffffffffffffffffffffffffffffffff90911690633f678e1190613d89908690600401615b16565b6020604051808303816000875af1158015613da8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dcc919061556f565b9050613dd9600f8261421c565b506060909201516000838152600a6020526040902063ffffffff90911690555090565b815160009081908190841580613e125750808510155b15613e1b578094505b60008092505b85831015613e7757866001613e3685856155f0565b613e4091906155f0565b81518110613e5057613e5061523d565b602002602001015181613e63919061553b565b905082613e6f816153c1565b935050613e21565b9694955050505050565b82516000908190831580613e955750808410155b15613e9e578093505b60008467ffffffffffffffff811115613eb957613eb9614614565b604051908082528060200260200182016040528015613ee2578160200160208202803683370190505b509050600092505b84831015613f5057866001613eff85856155f0565b613f0991906155f0565b81518110613f1957613f1961523d565b6020026020010151818481518110613f3357613f3361523d565b602090810291909101015282613f48816153c1565b935050613eea565b613f6981600060018451613f6491906155f0565b614228565b85606403613fa2578060018251613f8091906155f0565b81518110613f9057613f9061523d565b60200260200101519350505050611cef565b806064825188613fb29190615c68565b613fbc9190615cd4565b81518110613fcc57613fcc61523d565b602002602001015193505050509392505050565b6000611cef83836143a0565b60007f00000000000000000000000000000000000000000000000000000000000000001561408957606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614060573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614084919061556f565b905090565b504390565b60005473ffffffffffffffffffffffffffffffffffffffff16331461410f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016120ba565b565b6000611545825490565b6000611cef838361449a565b3373ffffffffffffffffffffffffffffffffffffffff8216036141a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016120ba565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611cef83836144c4565b8181808203614238575050505050565b60008560026142478787615ce8565b6142519190615d08565b61425b9087615d70565b8151811061426b5761426b61523d565b602002602001015190505b81831361437a575b808684815181106142915761429161523d565b602002602001015110156142b157826142a981615d98565b93505061427e565b8582815181106142c3576142c361523d565b60200260200101518110156142e457816142dc81615dc9565b9250506142b1565b818313614375578582815181106142fd576142fd61523d565b60200260200101518684815181106143175761431761523d565b60200260200101518785815181106143315761433161523d565b6020026020010188858151811061434a5761434a61523d565b6020908102919091010191909152528261436381615d98565b935050818061437190615dc9565b9250505b614276565b8185121561438d5761438d868684614228565b8383121561148657611486868486614228565b600081815260018301602052604081205480156144895760006143c46001836155f0565b85549091506000906143d8906001906155f0565b905081811461443d5760008660000182815481106143f8576143f861523d565b906000526020600020015490508087600001848154811061441b5761441b61523d565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061444e5761444e615e20565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611545565b6000915050611545565b5092915050565b60008260000182815481106144b1576144b161523d565b9060005260206000200154905092915050565b600081815260018301602052604081205461450b57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611545565b506000611545565b5080546000825590600052602060002090810190613d2b9190614587565b828054828255906000526020600020908101928215614577579160200282015b8281111561457757825182906145679082615910565b5091602001919060010190614551565b5061458392915061459c565b5090565b5b808211156145835760008155600101614588565b808211156145835760006145b082826145b9565b5060010161459c565b5080546145c590615603565b6000825580601f106145d5575050565b601f016020900490600052602060002090810190613d2b9190614587565b60ff81168114613d2b57600080fd5b63ffffffff81168114613d2b57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610140810167ffffffffffffffff8111828210171561466757614667614614565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156146b4576146b4614614565b604052919050565b600067ffffffffffffffff8211156146d6576146d6614614565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261471357600080fd5b8135614726614721826146bc565b61466d565b81815284602083860101111561473b57600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff81168114613d2b57600080fd5b600080600080600080600060e0888a03121561478d57600080fd5b8735614798816145f3565b965060208801356147a881614602565b955060408801356147b8816145f3565b9450606088013567ffffffffffffffff8111156147d457600080fd5b6147e08a828b01614702565b94505060808801356147f181614758565b9699959850939692959460a0840135945060c09093013592915050565b803561ffff8116811461482057600080fd5b919050565b60008060006060848603121561483a57600080fd5b8335925061484a6020850161480e565b9150604084013590509250925092565b6000806040838503121561486d57600080fd5b82359150602083013567ffffffffffffffff81111561488b57600080fd5b61489785828601614702565b9150509250929050565b6000602082840312156148b357600080fd5b5035919050565b60005b838110156148d55781810151838201526020016148bd565b50506000910152565b600081518084526148f68160208601602086016148ba565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611cef60208301846148de565b73ffffffffffffffffffffffffffffffffffffffff81168114613d2b57600080fd5b600080600080600080600060e0888a03121561497857600080fd5b87359650602088013561498a8161493b565b9550604088013561499a816145f3565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b600080604083850312156149d557600080fd5b823591506149e56020840161480e565b90509250929050565b600060208284031215614a0057600080fd5b8135611cef8161493b565b60008083601f840112614a1d57600080fd5b50813567ffffffffffffffff811115614a3557600080fd5b6020830191508360208260051b850101111561179957600080fd5b600080600080600080600060c0888a031215614a6b57600080fd5b873567ffffffffffffffff811115614a8257600080fd5b614a8e8a828b01614a0b565b9098509650506020880135614aa2816145f3565b96999598509596604081013596506060810135956080820135955060a0909101359350915050565b600080600060608486031215614adf57600080fd5b505081359360208301359350604090920135919050565b60208152614b1d60208201835173ffffffffffffffffffffffffffffffffffffffff169052565b60006020830151614b36604084018263ffffffff169052565b506040830151610140806060850152614b536101608501836148de565b91506060850151614b7460808601826bffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015163ffffffff811660e08601525060e0850151610100614be0818701836bffffffffffffffffffffffff169052565b8601519050610120614bf58682018315159052565b8601518584037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001838701529050614c2d83826148de565b9695505050505050565b60008060208385031215614c4a57600080fd5b823567ffffffffffffffff811115614c6157600080fd5b614c6d85828601614a0b565b90969095509350505050565b60008060408385031215614c8c57600080fd5b823567ffffffffffffffff80821115614ca457600080fd5b908401906101008287031215614cb957600080fd5b90925060208401359080821115614ccf57600080fd5b5061489785828601614702565b8215158152604060208201526000611cec60408301846148de565b60008083601f840112614d0957600080fd5b50813567ffffffffffffffff811115614d2157600080fd5b60208301915083602082850101111561179957600080fd5b60008060208385031215614d4c57600080fd5b823567ffffffffffffffff811115614d6357600080fd5b614c6d85828601614cf7565b6020808252825182820181905260009190848201906040850190845b81811015614da757835183529284019291840191600101614d8b565b50909695505050505050565b600067ffffffffffffffff821115614dcd57614dcd614614565b5060051b60200190565b60008060408385031215614dea57600080fd5b823567ffffffffffffffff80821115614e0257600080fd5b818501915085601f830112614e1657600080fd5b81356020614e2661472183614db3565b82815260059290921b84018101918181019089841115614e4557600080fd5b8286015b84811015614e7d57803586811115614e615760008081fd5b614e6f8c86838b0101614702565b845250918301918301614e49565b5096505086013592505080821115614ccf57600080fd5b600080600060408486031215614ea957600080fd5b833567ffffffffffffffff811115614ec057600080fd5b614ecc86828701614a0b565b9094509250506020840135614ee081614602565b809150509250925092565b60008060408385031215614efe57600080fd5b50508035926020909101359150565b600080600060408486031215614f2257600080fd5b83359250602084013567ffffffffffffffff811115614f4057600080fd5b614f4c86828701614cf7565b9497909650939450505050565b60008060408385031215614f6c57600080fd5b823567ffffffffffffffff80821115614f8457600080fd5b614f9086838701614702565b93506020850135915080821115614ccf57600080fd5b60006020808385031215614fb957600080fd5b823567ffffffffffffffff80821115614fd157600080fd5b818501915085601f830112614fe557600080fd5b8135614ff361472182614db3565b81815260059190911b8301840190848101908883111561501257600080fd5b8585015b8381101561504a5780358581111561502e5760008081fd5b61503c8b89838a0101614702565b845250918601918601615016565b5098975050505050505050565b6000806040838503121561506a57600080fd5b82359150602083013561507c81614758565b809150509250929050565b60006020828403121561509957600080fd5b8135611cef816145f3565b600080604083850312156150b757600080fd5b82359150602083013561507c81614602565b600080604083850312156150dc57600080fd5b82359150602083013561507c816145f3565b6000806000806060858703121561510457600080fd5b843567ffffffffffffffff81111561511b57600080fd5b61512787828801614a0b565b909550935050602085013561513b816145f3565b9150604085013561514b816145f3565b939692955090935050565b60008060008060008060c0878903121561516f57600080fd5b863561517a8161493b565b9550602087013561518a816145f3565b95989597505050506040840135936060810135936080820135935060a0909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006bffffffffffffffffffffffff80831681851681830481118215151615615209576152096151af565b02949350505050565b8051801515811461482057600080fd5b60006020828403121561523457600080fd5b611cef82615212565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff821660ff8103615282576152826151af565b60010192915050565b828152604060208201526000611cec60408301846148de565b600082601f8301126152b557600080fd5b81516152c3614721826146bc565b8181528460208386010111156152d857600080fd5b6152e98260208301602087016148ba565b949350505050565b60006020828403121561530357600080fd5b815167ffffffffffffffff81111561531a57600080fd5b6152e9848285016152a4565b805161482081614758565b60006020828403121561534357600080fd5b8151611cef81614758565b80516148208161493b565b6000806040838503121561536c57600080fd5b82516153778161493b565b6020939093015192949293505050565b60006020828403121561539957600080fd5b8151611cef8161493b565b6000602082840312156153b657600080fd5b8151611cef816145f3565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036153f2576153f26151af565b5060010190565b805161482081614602565b805167ffffffffffffffff8116811461482057600080fd5b60006020828403121561542e57600080fd5b815167ffffffffffffffff8082111561544657600080fd5b90830190610140828603121561545b57600080fd5b615463614643565b61546c8361534e565b815261547a602084016153f9565b602082015260408301518281111561549157600080fd5b61549d878286016152a4565b6040830152506154af60608401615326565b60608201526154c06080840161534e565b60808201526154d160a08401615404565b60a08201526154e260c084016153f9565b60c08201526154f360e08401615326565b60e0820152610100615506818501615212565b90820152610120838101518381111561551e57600080fd5b61552a888287016152a4565b918301919091525095945050505050565b80820180821115611545576115456151af565b600061ffff808316818103615565576155656151af565b6001019392505050565b60006020828403121561558157600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126155bd57600080fd5b83018035915067ffffffffffffffff8211156155d857600080fd5b6020019150600581901b360382131561179957600080fd5b81810381811115611545576115456151af565b600181811c9082168061561757607f821691505b602082108103615650577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000815461566381615603565b80855260206001838116801561568057600181146156b8576156e6565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b89010195506156e6565b866000528260002060005b858110156156de5781548a82018601529083019084016156c3565b890184019650505b505050505092915050565b60a08152600061570460a0830188615656565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b83811015615776577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030185526157648383615656565b9486019492506001918201910161572b565b5050868103604088015261578a818b615656565b94505050505084606084015282810360808401526157a881856148de565b98975050505050505050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015615829577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030185526158178683516148de565b955093820193908201906001016157dd565b50508584038187015250505061583f81856148de565b95945050505050565b60008060006060848603121561585d57600080fd5b83519250602084015191506040840151614ee08161493b565b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b601f821115612ce257600081815260208120601f850160051c810160208610156158f15750805b601f850160051c820191505b81811015611486578281556001016158fd565b815167ffffffffffffffff81111561592a5761592a614614565b61593e816159388454615603565b846158ca565b602080601f831160018114615991576000841561595b5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555611486565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156159de578886015182559484019460019091019084016159bf565b5085821015615a1a57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b60006020808385031215615a3d57600080fd5b825167ffffffffffffffff811115615a5457600080fd5b8301601f81018513615a6557600080fd5b8051615a7361472182614db3565b81815260059190911b82018301908381019087831115615a9257600080fd5b928401925b82841015615ab057835182529284019290840190615a97565b979650505050505050565b600063ffffffff808316818103615565576155656151af565b80516020808301519190811015615650577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b6020815260008251610140806020850152615b356101608501836148de565b915060208501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe080868503016040870152615b7184836148de565b935060408701519150615b9c606087018373ffffffffffffffffffffffffffffffffffffffff169052565b606087015163ffffffff811660808801529150608087015173ffffffffffffffffffffffffffffffffffffffff811660a0880152915060a087015160ff811660c0880152915060c08701519150808685030160e0870152615bfd84836148de565b935060e08701519150610100818786030181880152615c1c85846148de565b945080880151925050610120818786030181880152615c3b85846148de565b94508088015192505050615c5e828601826bffffffffffffffffffffffff169052565b5090949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615ca057615ca06151af565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082615ce357615ce3615ca5565b500490565b8181036000831280158383131683831282161715614493576144936151af565b600082615d1757615d17615ca5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615615d6b57615d6b6151af565b500590565b8082018281126000831280158216821582161715615d9057615d906151af565b505092915050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036153f2576153f26151af565b60007f80000000000000000000000000000000000000000000000000000000000000008203615dfa57615dfa6151af565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", + Bin: "0x7f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf086080527fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d60a0526005601455601580546001600160681b0319166c140000000002c68af0bb140000179055606460e0526101c0604052604261014081815261010091829190620066ec6101603981526020016040518060800160405280604281526020016200672e604291399052620000be906016906002620003de565b506040805180820190915260098152680cccacac892c890caf60bb1b6020820152601790620000ee90826200055a565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b60208201526018906200012090826200055a565b503480156200012e57600080fd5b506040516200677038038062006770833981016040819052620001519162000652565b82823380600081620001aa5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620001dd57620001dd8162000333565b5050601180546001600160a01b0319166001600160a01b038516908117909155604080516330fe427560e21b815281516000945063c3f909d4926004808401939192918290030181865afa1580156200023a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200026091906200069e565b50601380546001600160a01b0319166001600160a01b038381169190911790915560115460408051631b6b6d2360e01b81529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015620002c6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ec9190620006cf565b601280546001600160a01b0319166001600160a01b039290921691909117905550151560c052506019805461ffff191691151561ff00191691909117905550620006f69050565b336001600160a01b038216036200038d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620001a1565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b82805482825590600052602060002090810192821562000429579160200282015b828111156200042957825182906200041890826200055a565b5091602001919060010190620003ff565b50620004379291506200043b565b5090565b80821115620004375760006200045282826200045c565b506001016200043b565b5080546200046a90620004cb565b6000825580601f106200047b575050565b601f0160209004906000526020600020908101906200049b91906200049e565b50565b5b808211156200043757600081556001016200049f565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620004e057607f821691505b6020821081036200050157634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200055557600081815260208120601f850160051c81016020861015620005305750805b601f850160051c820191505b8181101562000551578281556001016200053c565b5050505b505050565b81516001600160401b03811115620005765762000576620004b5565b6200058e81620005878454620004cb565b8462000507565b602080601f831160018114620005c65760008415620005ad5750858301515b600019600386901b1c1916600185901b17855562000551565b600085815260208120601f198616915b82811015620005f757888601518255948401946001909101908401620005d6565b5085821015620006165787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b03811681146200049b57600080fd5b805180151581146200064d57600080fd5b919050565b6000806000606084860312156200066857600080fd5b8351620006758162000626565b925062000685602085016200063c565b915062000695604085016200063c565b90509250925092565b60008060408385031215620006b257600080fd5b8251620006bf8162000626565b6020939093015192949293505050565b600060208284031215620006e257600080fd5b8151620006ef8162000626565b9392505050565b60805160a05160c05160e051615f926200075a600039600081816105b90152612551015260008181610a2d01526140920152600081816108a601528181611fa80152613ae0015260008181610dca01528181611f780152613ab50152615f926000f3fe6080604052600436106105265760003560e01c80637b103999116102af578063af953a4a11610179578063daee1aeb116100d6578063e83ce5581161008a578063fa333dfb1161006f578063fa333dfb14611066578063fba7ffa314611119578063fcdc1f631461114657600080fd5b8063e83ce55814611027578063f2fde38b1461104657600080fd5b8063de818253116100bb578063de81825314610f90578063e0114adb14610fe4578063e45530831461101157600080fd5b8063daee1aeb14610f50578063dbef701e14610f7057600080fd5b8063c41c815b1161012d578063d4c2490011610112578063d4c2490014610ef0578063d6051a7214610f10578063da6cba4714610f3057600080fd5b8063c41c815b14610ec1578063c98f10b014610edb57600080fd5b8063b657bc9c1161015e578063b657bc9c14610e61578063becde0e114610e81578063c041982214610ea157600080fd5b8063af953a4a14610e2c578063afb28d1f14610e4c57600080fd5b8063948108f7116102275780639d385eaa116101db578063a6548248116101c0578063a654824814610db8578063a6b5947514610dec578063a72aa27e14610e0c57600080fd5b80639d385eaa14610d785780639d6f1cc714610d9857600080fd5b80639ac542eb1161020c5780639ac542eb14610cf05780639b42935414610d1a5780639b51fb0d14610d4757600080fd5b8063948108f714610cb057806396cebc7c14610cd057600080fd5b806386e330af1161027e5780638da5cb5b116102635780638da5cb5b14610c385780638fcb3fba14610c63578063924ca57814610c9057600080fd5b806386e330af14610bf8578063873c758614610c1857600080fd5b80637b10399914610b6b5780637e7a46dc14610b985780638243444a14610bb85780638340507c14610bd857600080fd5b806345d2ec17116103f057806360457ff51161036857806373644cce1161031c578063776898c811610301578063776898c814610b1657806379ba509714610b3657806379ea994314610b4b57600080fd5b806373644cce14610abc5780637672130314610ae957600080fd5b8063642f6cef1161034d578063642f6cef14610a1b57806369cdbadb14610a5f5780637145f11b14610a8c57600080fd5b806360457ff5146109c9578063636092e8146109f657600080fd5b80635147cd59116103bf57806357970e93116103a457806357970e93146109675780635d4ee7f3146109945780635f17e616146109a957600080fd5b80635147cd591461091557806351c98be31461094757600080fd5b806345d2ec1714610867578063469820931461089457806346e7a63e146108c85780634b56a42e146108f557600080fd5b806320e3dbd41161049e5780632b20e397116104525780633ebe8d6c116104375780633ebe8d6c146107f957806340691db4146108195780634585e33b1461084757600080fd5b80632b20e3971461077a578063328ffd11146107cc57600080fd5b806328c4b57b1161048357806328c4b57b1461070d57806329e0a8411461072d5780632a9032d31461075a57600080fd5b806320e3dbd4146106cd5780632636aecf146106ed57600080fd5b806319d97a94116104f55780631e010439116104da5780631e0104391461063b578063206c32e814610678578063207b6516146106ad57600080fd5b806319d97a94146105ee5780631cdde2511461061b57600080fd5b806306c1cc0014610532578063077ac621146105545780630b7d33e61461058757806312c55027146105a757600080fd5b3661052d57005b600080fd5b34801561053e57600080fd5b5061055261054d366004614814565b611173565b005b34801561056057600080fd5b5061057461056f3660046148c7565b6113c2565b6040519081526020015b60405180910390f35b34801561059357600080fd5b506105526105a23660046148fc565b611400565b3480156105b357600080fd5b506105db7f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff909116815260200161057e565b3480156105fa57600080fd5b5061060e610609366004614943565b61148e565b60405161057e91906149ca565b34801561062757600080fd5b506105526106363660046149ff565b61154b565b34801561064757600080fd5b5061065b610656366004614943565b611688565b6040516bffffffffffffffffffffffff909116815260200161057e565b34801561068457600080fd5b50610698610693366004614a64565b61171d565b6040805192835260208301919091520161057e565b3480156106b957600080fd5b5061060e6106c8366004614943565b6117a0565b3480156106d957600080fd5b506105526106e8366004614a90565b6117f8565b3480156106f957600080fd5b50610552610708366004614af2565b6119c2565b34801561071957600080fd5b50610574610728366004614b6c565b611c8b565b34801561073957600080fd5b5061074d610748366004614943565b611cf6565b60405161057e9190614b98565b34801561076657600080fd5b50610552610775366004614cd9565b611dfb565b34801561078657600080fd5b506011546107a79073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161057e565b3480156107d857600080fd5b506105746107e7366004614943565b60036020526000908152604090205481565b34801561080557600080fd5b50610574610814366004614943565b611edc565b34801561082557600080fd5b50610839610834366004614d1b565b611f45565b60405161057e929190614d7e565b34801561085357600080fd5b50610552610862366004614ddb565b61244b565b34801561087357600080fd5b50610887610882366004614a64565b61269a565b60405161057e9190614e11565b3480156108a057600080fd5b506105747f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d457600080fd5b506105746108e3366004614943565b600a6020526000908152604090205481565b34801561090157600080fd5b50610839610910366004614e79565b612709565b34801561092157600080fd5b50610935610930366004614943565b61275d565b60405160ff909116815260200161057e565b34801561095357600080fd5b50610552610962366004614f36565b6127f1565b34801561097357600080fd5b506012546107a79073ffffffffffffffffffffffffffffffffffffffff1681565b3480156109a057600080fd5b50610552612895565b3480156109b557600080fd5b506105526109c4366004614f8d565b6129d0565b3480156109d557600080fd5b506105746109e4366004614943565b60076020526000908152604090205481565b348015610a0257600080fd5b5060155461065b906bffffffffffffffffffffffff1681565b348015610a2757600080fd5b50610a4f7f000000000000000000000000000000000000000000000000000000000000000081565b604051901515815260200161057e565b348015610a6b57600080fd5b50610574610a7a366004614943565b60086020526000908152604090205481565b348015610a9857600080fd5b50610a4f610aa7366004614943565b600b6020526000908152604090205460ff1681565b348015610ac857600080fd5b50610574610ad7366004614943565b6000908152600c602052604090205490565b348015610af557600080fd5b50610574610b04366004614943565b60046020526000908152604090205481565b348015610b2257600080fd5b50610a4f610b31366004614943565b612a9d565b348015610b4257600080fd5b50610552612aef565b348015610b5757600080fd5b506107a7610b66366004614943565b612bec565b348015610b7757600080fd5b506013546107a79073ffffffffffffffffffffffffffffffffffffffff1681565b348015610ba457600080fd5b50610552610bb3366004614faf565b612c80565b348015610bc457600080fd5b50610552610bd3366004614faf565b612d11565b348015610be457600080fd5b50610552610bf3366004614ffb565b612d6b565b348015610c0457600080fd5b50610552610c13366004615048565b612d89565b348015610c2457600080fd5b50610887610c33366004614f8d565b612d9c565b348015610c4457600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166107a7565b348015610c6f57600080fd5b50610574610c7e366004614943565b60056020526000908152604090205481565b348015610c9c57600080fd5b50610552610cab366004614f8d565b612e59565b348015610cbc57600080fd5b50610552610ccb3660046150f9565b61309e565b348015610cdc57600080fd5b50610552610ceb366004615129565b6131b6565b348015610cfc57600080fd5b50601554610935906c01000000000000000000000000900460ff1681565b348015610d2657600080fd5b50610552610d35366004614f8d565b60009182526009602052604090912055565b348015610d5357600080fd5b506105db610d62366004614943565b600e6020526000908152604090205461ffff1681565b348015610d8457600080fd5b50610887610d93366004614943565b6133c0565b348015610da457600080fd5b5061060e610db3366004614943565b613422565b348015610dc457600080fd5b506105747f000000000000000000000000000000000000000000000000000000000000000081565b348015610df857600080fd5b50610552610e07366004614b6c565b6134ce565b348015610e1857600080fd5b50610552610e27366004615146565b613537565b348015610e3857600080fd5b50610552610e47366004614943565b6135e2565b348015610e5857600080fd5b5061060e613668565b348015610e6d57600080fd5b5061065b610e7c366004614943565b613675565b348015610e8d57600080fd5b50610552610e9c366004614cd9565b6136cd565b348015610ead57600080fd5b50610887610ebc366004614f8d565b613767565b348015610ecd57600080fd5b50601954610a4f9060ff1681565b348015610ee757600080fd5b5061060e613864565b348015610efc57600080fd5b50610552610f0b36600461516b565b613871565b348015610f1c57600080fd5b50610698610f2b366004614f8d565b6138f0565b348015610f3c57600080fd5b50610552610f4b366004615190565b613959565b348015610f5c57600080fd5b50610552610f6b366004614cd9565b613cc0565b348015610f7c57600080fd5b50610574610f8b366004614f8d565b613d8b565b348015610f9c57600080fd5b50610552610fab366004615129565b6019805460ff909216610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909216919091179055565b348015610ff057600080fd5b50610574610fff366004614943565b60096020526000908152604090205481565b34801561101d57600080fd5b5061057460145481565b34801561103357600080fd5b5060195461093590610100900460ff1681565b34801561105257600080fd5b50610552611061366004614a90565b613dbc565b34801561107257600080fd5b5061060e6110813660046151f8565b6040805160c0808201835273ffffffffffffffffffffffffffffffffffffffff9890981680825260ff97881660208084019182528385019889526060808501988952608080860198895260a095860197885286519283019490945291519099168985015296519688019690965293519486019490945290519184019190915251828401528051808303909301835260e0909101905290565b34801561112557600080fd5b50610574611134366004614943565b60066020526000908152604090205481565b34801561115257600080fd5b50610574611161366004614943565b60026020526000908152604090205481565b6040805161018081018252600461014082019081527f746573740000000000000000000000000000000000000000000000000000000061016083015281528151602081810184526000808352818401929092523083850181905263ffffffff8b166060850152608084015260ff808a1660a08501528451808301865283815260c085015260e0840189905284519182019094529081526101008201526bffffffffffffffffffffffff8516610120820152601254601154919273ffffffffffffffffffffffffffffffffffffffff9182169263095ea7b3921690611259908c1688615280565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526bffffffffffffffffffffffff1660248201526044016020604051808303816000875af11580156112d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112fb91906152c4565b5060008860ff1667ffffffffffffffff81111561131a5761131a6146b6565b604051908082528060200260200182016040528015611343578160200160208202803683370190505b50905060005b8960ff168160ff1610156113b657600061136284613dd0565b905080838360ff168151811061137a5761137a6152df565b602090810291909101810191909152600091825260088152604080832088905560079091529020849055806113ae8161530e565b915050611349565b50505050505050505050565b600d60205282600052604060002060205281600052604060002081815481106113ea57600080fd5b9060005260206000200160009250925050505481565b6013546040517f0b7d33e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690630b7d33e690611458908590859060040161532d565b600060405180830381600087803b15801561147257600080fd5b505af1158015611486573d6000803e3d6000fd5b505050505050565b6013546040517f19d97a940000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff16906319d97a94906024015b600060405180830381865afa1580156114ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526115459190810190615393565b92915050565b6013546040517ffa333dfb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015260ff8816602483015260448201879052606482018690526084820185905260a4820184905290911690634ee88d35908990309063fa333dfb9060c401600060405180830381865afa1580156115ea573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526116309190810190615393565b6040518363ffffffff1660e01b815260040161164d92919061532d565b600060405180830381600087803b15801561166757600080fd5b505af115801561167b573d6000803e3d6000fd5b5050505050505050505050565b6013546040517f1e0104390000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690631e010439906024015b602060405180830381865afa1580156116f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154591906153d3565b6000828152600d6020908152604080832061ffff85168452825280832080548251818502810185019093528083528493849392919083018282801561178157602002820191906000526020600020905b81548152602001906001019080831161176d575b50505050509050611793818251613e9e565b92509250505b9250929050565b6013546040517f207b65160000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063207b6516906024016114e2565b601180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155604080517fc3f909d400000000000000000000000000000000000000000000000000000000815281516000939263c3f909d492600480820193918290030181865afa15801561188e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b291906153fb565b50601380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691909117909155601154604080517f1b6b6d230000000000000000000000000000000000000000000000000000000081529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015611955573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119799190615429565b601280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555050565b8560005b81811015611c805760008989838181106119e2576119e26152df565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc8283604051602001611a1b91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401611a4792919061532d565b600060405180830381600087803b158015611a6157600080fd5b505af1158015611a75573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015611aeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b0f9190615446565b90508060ff16600103611c6b576040517ffa333dfb000000000000000000000000000000000000000000000000000000008152306004820181905260ff8b166024830152604482018a9052606482018890526084820188905260a4820187905260009163fa333dfb9060c401600060405180830381865afa158015611b98573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611bde9190810190615393565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590611c37908690859060040161532d565b600060405180830381600087803b158015611c5157600080fd5b505af1158015611c65573d6000803e3d6000fd5b50505050505b50508080611c7890615463565b9150506119c6565b505050505050505050565b6000838152600c602090815260408083208054825181850281018501909352808352611cec93830182828015611ce057602002820191906000526020600020905b815481526020019060010190808311611ccc575b50505050508484613f23565b90505b9392505050565b604080516101408101825260008082526020820181905260609282018390528282018190526080820181905260a0820181905260c0820181905260e082018190526101008201526101208101919091526013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c7c3a19a90602401600060405180830381865afa158015611db5573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261154591908101906154be565b8060005b818160ff161015611ed65760135473ffffffffffffffffffffffffffffffffffffffff1663c8048022858560ff8516818110611e3d57611e3d6152df565b905060200201356040518263ffffffff1660e01b8152600401611e6291815260200190565b600060405180830381600087803b158015611e7c57600080fd5b505af1158015611e90573d6000803e3d6000fd5b50505050611ec384848360ff16818110611eac57611eac6152df565b90506020020135600f61408290919063ffffffff16565b5080611ece8161530e565b915050611dff565b50505050565b6000818152600e602052604081205461ffff1681805b8261ffff168161ffff1611611f3d576000858152600d6020908152604080832061ffff85168452909152902054611f2990836155dd565b915080611f35816155f0565b915050611ef2565b509392505050565b6000606060005a90506000611f5861408e565b9050600085806020019051810190611f709190615611565b6019549091507f000000000000000000000000000000000000000000000000000000000000000090610100900460ff1615611fc857507f00000000000000000000000000000000000000000000000000000000000000005b80611fd660c08a018a61562a565b6000818110611fe757611fe76152df565b90506020020135036123e957600061200260c08a018a61562a565b6001818110612013576120136152df565b9050602002013560405160200161202c91815260200190565b60405160208183030381529060405290506000818060200190518101906120539190615611565b90508381146120c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f75706b6565702069647320646f6e2774206d617463680000000000000000000060448201526064015b60405180910390fd5b60006120d260c08c018c61562a565b60028181106120e3576120e36152df565b905060200201356040516020016120fc91815260200190565b60405160208183030381529060405290506000818060200190518101906121239190615611565b9050600061213460c08e018e61562a565b6003818110612145576121456152df565b9050602002013560405160200161215e91815260200190565b60405160208183030381529060405290506000818060200190518101906121859190615429565b6000868152600860205260409020549091505b805a6121a4908d615692565b6121b090613a986155dd565b10156121f15783406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055612198565b6040517f6665656449644865780000000000000000000000000000000000000000000000602082015260009060290160405160208183030381529060405280519060200120601760405160200161224891906156f8565b604051602081830303815290604052805190602001200361226a57508361226d565b50425b60195460ff161561231557604080516020810189905290810186905273ffffffffffffffffffffffffffffffffffffffff841660608201526017906016906018908490608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527ff055e4a20000000000000000000000000000000000000000000000000000000082526120ba9594939291600401615827565b60165460009067ffffffffffffffff811115612333576123336146b6565b60405190808252806020026020018201604052801561236657816020015b60608152602001906001900390816123515790505b5060408051602081018b905290810188905273ffffffffffffffffffffffffffffffffffffffff861660608201529091506000906080016040516020818303038152906040529050600182826040516020016123c39291906158ea565b6040516020818303038152906040529f509f505050505050505050505050505050611799565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f756e6578706563746564206576656e742073696700000000000000000000000060448201526064016120ba565b60005a905060008061245f84860186614e79565b9150915060008060008380602001905181019061247c919061597e565b60008381526005602090815260408083205460049092528220549497509295509093509091906124aa61408e565b9050826000036124ca57600086815260056020526040902081905561260e565b60006124d68683615692565b6000888152600e6020908152604080832054600d835281842061ffff90911680855290835281842080548351818602810186019094528084529596509094919290919083018282801561254857602002820191906000526020600020905b815481526020019060010190808311612534575b505050505090507f000000000000000000000000000000000000000000000000000000000000000061ffff168151036125c35781612585816155f0565b60008b8152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83161790559250505b506000888152600d6020908152604080832061ffff9094168352928152828220805460018181018355918452828420018590558a8352600c8252928220805493840181558252902001555b6000868152600660205260408120546126289060016155dd565b60008881526006602090815260408083208490556004909152902083905590506126528783612e59565b6040513090839089907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a461268c878b846134ce565b505050505050505050505050565b6000828152600d6020908152604080832061ffff851684528252918290208054835181840281018401909452808452606093928301828280156126fc57602002820191906000526020600020905b8154815260200190600101908083116126e8575b5050505050905092915050565b60006060600084846040516020016127229291906158ea565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526001969095509350505050565b6013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690635147cd5990602401602060405180830381865afa1580156127cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115459190615446565b8160005b8181101561288e5730635f17e616868684818110612815576128156152df565b90506020020135856040518363ffffffff1660e01b815260040161284992919091825263ffffffff16602082015260400190565b600060405180830381600087803b15801561286357600080fd5b505af1158015612877573d6000803e3d6000fd5b50505050808061288690615463565b9150506127f5565b5050505050565b61289d614130565b6012546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561290c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129309190615611565b6012546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810183905291925073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af11580156129a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129cc91906152c4565b5050565b60008281526003602090815260408083208490556005825280832083905560068252808320839055600c9091528120612a08916145b5565b6000828152600e602052604081205461ffff16905b8161ffff168161ffff1611612a64576000848152600d6020908152604080832061ffff851684529091528120612a52916145b5565b80612a5c816155f0565b915050612a1d565b5050506000908152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055565b6000818152600560205260408120548103612aba57506001919050565b600082815260036020908152604080832054600490925290912054612add61408e565b612ae79190615692565b101592915050565b60015473ffffffffffffffffffffffffffffffffffffffff163314612b70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016120ba565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6013546040517f79ea99430000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff16906379ea994390602401602060405180830381865afa158015612c5c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115459190615429565b6013546040517fcd7f71b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063cd7f71b590612cda908690869086906004016159ac565b600060405180830381600087803b158015612cf457600080fd5b505af1158015612d08573d6000803e3d6000fd5b50505050505050565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690634ee88d3590612cda908690869086906004016159ac565b6017612d778382615a46565b506018612d848282615a46565b505050565b80516129cc9060169060208401906145d3565b6013546040517f06e3b632000000000000000000000000000000000000000000000000000000008152600481018490526024810183905260609173ffffffffffffffffffffffffffffffffffffffff16906306e3b63290604401600060405180830381865afa158015612e13573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611cef9190810190615b60565b601454600083815260026020526040902054612e759083615692565b11156129cc576013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905260009173ffffffffffffffffffffffffffffffffffffffff169063c7c3a19a90602401600060405180830381865afa158015612eeb573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612f3191908101906154be565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810186905291925060009173ffffffffffffffffffffffffffffffffffffffff9091169063b657bc9c90602401602060405180830381865afa158015612fa6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fca91906153d3565b601554909150612fee9082906c01000000000000000000000000900460ff16615280565b6bffffffffffffffffffffffff1682606001516bffffffffffffffffffffffff161015611ed6576015546130319085906bffffffffffffffffffffffff1661309e565b60008481526002602090815260409182902085905560155482518781526bffffffffffffffffffffffff909116918101919091529081018490527f49d4100ab0124eb4a9a65dc4ea08d6412a43f6f05c49194983f5b322bcc0a5c09060600160405180910390a150505050565b6012546013546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526bffffffffffffffffffffffff8416602482015291169063095ea7b3906044016020604051808303816000875af1158015613126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061314a91906152c4565b506013546040517f948108f7000000000000000000000000000000000000000000000000000000008152600481018490526bffffffffffffffffffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063948108f790604401611458565b6040517fc04198220000000000000000000000000000000000000000000000000000000081526000600482018190526024820181905290309063c041982290604401600060405180830381865afa158015613215573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261325b9190810190615b60565b8051909150600061326a61408e565b905060005b8281101561288e57600084828151811061328b5761328b6152df565b60209081029190910101516013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905291925060009173ffffffffffffffffffffffffffffffffffffffff90911690635147cd5990602401602060405180830381865afa15801561330b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332f9190615446565b90508060ff166001036133ab578660ff1660000361337b576040513090859084907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a46133ab565b6040513090859084907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a45b505080806133b890615463565b91505061326f565b6000818152600c602090815260409182902080548351818402810184019094528084526060939283018282801561341657602002820191906000526020600020905b815481526020019060010190808311613402575b50505050509050919050565b6016818154811061343257600080fd5b90600052602060002001600091509050805461344d906156a5565b80601f0160208091040260200160405190810160405280929190818152602001828054613479906156a5565b80156134c65780601f1061349b576101008083540402835291602001916134c6565b820191906000526020600020905b8154815290600101906020018083116134a957829003601f168201915b505050505081565b6000838152600760205260409020545b805a6134ea9085615692565b6134f6906127106155dd565b1015611ed65781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556134de565b6013546040517fa72aa27e0000000000000000000000000000000000000000000000000000000081526004810184905263ffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063a72aa27e90604401600060405180830381600087803b1580156135af57600080fd5b505af11580156135c3573d6000803e3d6000fd5b505050600092835250600a602052604090912063ffffffff9091169055565b6013546040517f744bfe610000000000000000000000000000000000000000000000000000000081526004810183905230602482015273ffffffffffffffffffffffffffffffffffffffff9091169063744bfe6190604401600060405180830381600087803b15801561365457600080fd5b505af115801561288e573d6000803e3d6000fd5b6017805461344d906156a5565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff169063b657bc9c906024016116dc565b8060005b818163ffffffff161015611ed6573063af953a4a858563ffffffff85168181106136fd576136fd6152df565b905060200201356040518263ffffffff1660e01b815260040161372291815260200190565b600060405180830381600087803b15801561373c57600080fd5b505af1158015613750573d6000803e3d6000fd5b50505050808061375f90615bf1565b9150506136d1565b60606000613775600f6141b3565b90508084106137b0576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826000036137c5576137c28482615692565b92505b60008367ffffffffffffffff8111156137e0576137e06146b6565b604051908082528060200260200182016040528015613809578160200160208202803683370190505b50905060005b8481101561385b5761382c61382482886155dd565b600f906141bd565b82828151811061383e5761383e6152df565b60209081029190910101528061385381615463565b91505061380f565b50949350505050565b6018805461344d906156a5565b600061387b61408e565b90508160ff166000036138bc576040513090829085907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4505050565b6040513090829085907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a4505050565b6000828152600c6020908152604080832080548251818502810185019093528083528493849392919083018282801561394857602002820191906000526020600020905b815481526020019060010190808311613934575b505050505090506117938185613e9e565b8260005b81811015611486576000868683818110613979576139796152df565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc82836040516020016139b291815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016139de92919061532d565b600060405180830381600087803b1580156139f857600080fd5b505af1158015613a0c573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015613a82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613aa69190615446565b90508060ff16600103613cab577f000000000000000000000000000000000000000000000000000000000000000060ff871615613b0057507f00000000000000000000000000000000000000000000000000000000000000005b60003073ffffffffffffffffffffffffffffffffffffffff1663fa333dfb30898588604051602001613b3491815260200190565b604051602081830303815290604052613b4c90615c0a565b60405160e086901b7fffffffff0000000000000000000000000000000000000000000000000000000016815273ffffffffffffffffffffffffffffffffffffffff909416600485015260ff90921660248401526044830152606482015260006084820181905260a482015260c401600060405180830381865afa158015613bd7573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052613c1d9190810190615393565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590613c76908790859060040161532d565b600060405180830381600087803b158015613c9057600080fd5b505af1158015613ca4573d6000803e3d6000fd5b5050505050505b50508080613cb890615463565b91505061395d565b8060005b81811015611ed6576000848483818110613ce057613ce06152df565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc8283604051602001613d1991815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401613d4592919061532d565b600060405180830381600087803b158015613d5f57600080fd5b505af1158015613d73573d6000803e3d6000fd5b50505050508080613d8390615463565b915050613cc4565b600c6020528160005260406000208181548110613da757600080fd5b90600052602060002001600091509150505481565b613dc4614130565b613dcd816141c9565b50565b6011546040517f3f678e11000000000000000000000000000000000000000000000000000000008152600091829173ffffffffffffffffffffffffffffffffffffffff90911690633f678e1190613e2b908690600401615c4c565b6020604051808303816000875af1158015613e4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e6e9190615611565b9050613e7b600f826142be565b506060909201516000838152600a6020526040902063ffffffff90911690555090565b815160009081908190841580613eb45750808510155b15613ebd578094505b60008092505b85831015613f1957866001613ed88585615692565b613ee29190615692565b81518110613ef257613ef26152df565b602002602001015181613f0591906155dd565b905082613f1181615463565b935050613ec3565b9694955050505050565b82516000908190831580613f375750808410155b15613f40578093505b60008467ffffffffffffffff811115613f5b57613f5b6146b6565b604051908082528060200260200182016040528015613f84578160200160208202803683370190505b509050600092505b84831015613ff257866001613fa18585615692565b613fab9190615692565b81518110613fbb57613fbb6152df565b6020026020010151818481518110613fd557613fd56152df565b602090810291909101015282613fea81615463565b935050613f8c565b61400b816000600184516140069190615692565b6142ca565b856064036140445780600182516140229190615692565b81518110614032576140326152df565b60200260200101519350505050611cef565b8060648251886140549190615d9e565b61405e9190615e0a565b8151811061406e5761406e6152df565b602002602001015193505050509392505050565b6000611cef8383614442565b60007f00000000000000000000000000000000000000000000000000000000000000001561412b57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614102573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141269190615611565b905090565b504390565b60005473ffffffffffffffffffffffffffffffffffffffff1633146141b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016120ba565b565b6000611545825490565b6000611cef838361453c565b3373ffffffffffffffffffffffffffffffffffffffff821603614248576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016120ba565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611cef8383614566565b81818082036142da575050505050565b60008560026142e98787615e1e565b6142f39190615e3e565b6142fd9087615ea6565b8151811061430d5761430d6152df565b602002602001015190505b81831361441c575b80868481518110614333576143336152df565b60200260200101511015614353578261434b81615ece565b935050614320565b858281518110614365576143656152df565b6020026020010151811015614386578161437e81615eff565b925050614353565b8183136144175785828151811061439f5761439f6152df565b60200260200101518684815181106143b9576143b96152df565b60200260200101518785815181106143d3576143d36152df565b602002602001018885815181106143ec576143ec6152df565b6020908102919091010191909152528261440581615ece565b935050818061441390615eff565b9250505b614318565b8185121561442f5761442f8686846142ca565b83831215611486576114868684866142ca565b6000818152600183016020526040812054801561452b576000614466600183615692565b855490915060009061447a90600190615692565b90508181146144df57600086600001828154811061449a5761449a6152df565b90600052602060002001549050808760000184815481106144bd576144bd6152df565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806144f0576144f0615f56565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611545565b6000915050611545565b5092915050565b6000826000018281548110614553576145536152df565b9060005260206000200154905092915050565b60008181526001830160205260408120546145ad57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611545565b506000611545565b5080546000825590600052602060002090810190613dcd9190614629565b828054828255906000526020600020908101928215614619579160200282015b8281111561461957825182906146099082615a46565b50916020019190600101906145f3565b5061462592915061463e565b5090565b5b80821115614625576000815560010161462a565b80821115614625576000614652828261465b565b5060010161463e565b508054614667906156a5565b6000825580601f10614677575050565b601f016020900490600052602060002090810190613dcd9190614629565b60ff81168114613dcd57600080fd5b63ffffffff81168114613dcd57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610140810167ffffffffffffffff81118282101715614709576147096146b6565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614756576147566146b6565b604052919050565b600067ffffffffffffffff821115614778576147786146b6565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f8301126147b557600080fd5b81356147c86147c38261475e565b61470f565b8181528460208386010111156147dd57600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff81168114613dcd57600080fd5b600080600080600080600060e0888a03121561482f57600080fd5b873561483a81614695565b9650602088013561484a816146a4565b9550604088013561485a81614695565b9450606088013567ffffffffffffffff81111561487657600080fd5b6148828a828b016147a4565b9450506080880135614893816147fa565b9699959850939692959460a0840135945060c09093013592915050565b803561ffff811681146148c257600080fd5b919050565b6000806000606084860312156148dc57600080fd5b833592506148ec602085016148b0565b9150604084013590509250925092565b6000806040838503121561490f57600080fd5b82359150602083013567ffffffffffffffff81111561492d57600080fd5b614939858286016147a4565b9150509250929050565b60006020828403121561495557600080fd5b5035919050565b60005b8381101561497757818101518382015260200161495f565b50506000910152565b6000815180845261499881602086016020860161495c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611cef6020830184614980565b73ffffffffffffffffffffffffffffffffffffffff81168114613dcd57600080fd5b600080600080600080600060e0888a031215614a1a57600080fd5b873596506020880135614a2c816149dd565b95506040880135614a3c81614695565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b60008060408385031215614a7757600080fd5b82359150614a87602084016148b0565b90509250929050565b600060208284031215614aa257600080fd5b8135611cef816149dd565b60008083601f840112614abf57600080fd5b50813567ffffffffffffffff811115614ad757600080fd5b6020830191508360208260051b850101111561179957600080fd5b600080600080600080600060c0888a031215614b0d57600080fd5b873567ffffffffffffffff811115614b2457600080fd5b614b308a828b01614aad565b9098509650506020880135614b4481614695565b96999598509596604081013596506060810135956080820135955060a0909101359350915050565b600080600060608486031215614b8157600080fd5b505081359360208301359350604090920135919050565b60208152614bbf60208201835173ffffffffffffffffffffffffffffffffffffffff169052565b60006020830151614bd8604084018263ffffffff169052565b506040830151610140806060850152614bf5610160850183614980565b91506060850151614c1660808601826bffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015163ffffffff811660e08601525060e0850151610100614c82818701836bffffffffffffffffffffffff169052565b8601519050610120614c978682018315159052565b8601518584037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001838701529050614ccf8382614980565b9695505050505050565b60008060208385031215614cec57600080fd5b823567ffffffffffffffff811115614d0357600080fd5b614d0f85828601614aad565b90969095509350505050565b60008060408385031215614d2e57600080fd5b823567ffffffffffffffff80821115614d4657600080fd5b908401906101008287031215614d5b57600080fd5b90925060208401359080821115614d7157600080fd5b50614939858286016147a4565b8215158152604060208201526000611cec6040830184614980565b60008083601f840112614dab57600080fd5b50813567ffffffffffffffff811115614dc357600080fd5b60208301915083602082850101111561179957600080fd5b60008060208385031215614dee57600080fd5b823567ffffffffffffffff811115614e0557600080fd5b614d0f85828601614d99565b6020808252825182820181905260009190848201906040850190845b81811015614e4957835183529284019291840191600101614e2d565b50909695505050505050565b600067ffffffffffffffff821115614e6f57614e6f6146b6565b5060051b60200190565b60008060408385031215614e8c57600080fd5b823567ffffffffffffffff80821115614ea457600080fd5b818501915085601f830112614eb857600080fd5b81356020614ec86147c383614e55565b82815260059290921b84018101918181019089841115614ee757600080fd5b8286015b84811015614f1f57803586811115614f035760008081fd5b614f118c86838b01016147a4565b845250918301918301614eeb565b5096505086013592505080821115614d7157600080fd5b600080600060408486031215614f4b57600080fd5b833567ffffffffffffffff811115614f6257600080fd5b614f6e86828701614aad565b9094509250506020840135614f82816146a4565b809150509250925092565b60008060408385031215614fa057600080fd5b50508035926020909101359150565b600080600060408486031215614fc457600080fd5b83359250602084013567ffffffffffffffff811115614fe257600080fd5b614fee86828701614d99565b9497909650939450505050565b6000806040838503121561500e57600080fd5b823567ffffffffffffffff8082111561502657600080fd5b615032868387016147a4565b93506020850135915080821115614d7157600080fd5b6000602080838503121561505b57600080fd5b823567ffffffffffffffff8082111561507357600080fd5b818501915085601f83011261508757600080fd5b81356150956147c382614e55565b81815260059190911b830184019084810190888311156150b457600080fd5b8585015b838110156150ec578035858111156150d05760008081fd5b6150de8b89838a01016147a4565b8452509186019186016150b8565b5098975050505050505050565b6000806040838503121561510c57600080fd5b82359150602083013561511e816147fa565b809150509250929050565b60006020828403121561513b57600080fd5b8135611cef81614695565b6000806040838503121561515957600080fd5b82359150602083013561511e816146a4565b6000806040838503121561517e57600080fd5b82359150602083013561511e81614695565b600080600080606085870312156151a657600080fd5b843567ffffffffffffffff8111156151bd57600080fd5b6151c987828801614aad565b90955093505060208501356151dd81614695565b915060408501356151ed81614695565b939692955090935050565b60008060008060008060c0878903121561521157600080fd5b863561521c816149dd565b9550602087013561522c81614695565b95989597505050506040840135936060810135936080820135935060a0909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006bffffffffffffffffffffffff808316818516818304811182151516156152ab576152ab615251565b02949350505050565b805180151581146148c257600080fd5b6000602082840312156152d657600080fd5b611cef826152b4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff821660ff810361532457615324615251565b60010192915050565b828152604060208201526000611cec6040830184614980565b600082601f83011261535757600080fd5b81516153656147c38261475e565b81815284602083860101111561537a57600080fd5b61538b82602083016020870161495c565b949350505050565b6000602082840312156153a557600080fd5b815167ffffffffffffffff8111156153bc57600080fd5b61538b84828501615346565b80516148c2816147fa565b6000602082840312156153e557600080fd5b8151611cef816147fa565b80516148c2816149dd565b6000806040838503121561540e57600080fd5b8251615419816149dd565b6020939093015192949293505050565b60006020828403121561543b57600080fd5b8151611cef816149dd565b60006020828403121561545857600080fd5b8151611cef81614695565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361549457615494615251565b5060010190565b80516148c2816146a4565b805167ffffffffffffffff811681146148c257600080fd5b6000602082840312156154d057600080fd5b815167ffffffffffffffff808211156154e857600080fd5b9083019061014082860312156154fd57600080fd5b6155056146e5565b61550e836153f0565b815261551c6020840161549b565b602082015260408301518281111561553357600080fd5b61553f87828601615346565b604083015250615551606084016153c8565b6060820152615562608084016153f0565b608082015261557360a084016154a6565b60a082015261558460c0840161549b565b60c082015261559560e084016153c8565b60e08201526101006155a88185016152b4565b9082015261012083810151838111156155c057600080fd5b6155cc88828701615346565b918301919091525095945050505050565b8082018082111561154557611545615251565b600061ffff80831681810361560757615607615251565b6001019392505050565b60006020828403121561562357600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261565f57600080fd5b83018035915067ffffffffffffffff82111561567a57600080fd5b6020019150600581901b360382131561179957600080fd5b8181038181111561154557611545615251565b600181811c908216806156b957607f821691505b6020821081036156f2577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000808354615706816156a5565b6001828116801561571e576001811461575157615780565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0084168752821515830287019450615780565b8760005260208060002060005b858110156157775781548a82015290840190820161575e565b50505082870194505b50929695505050505050565b60008154615799816156a5565b8085526020600183811680156157b657600181146157ee5761581c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b890101955061581c565b866000528260002060005b858110156158145781548a82018601529083019084016157f9565b890184019650505b505050505092915050565b60a08152600061583a60a083018861578c565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b838110156158ac577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe087840301855261589a838361578c565b94860194925060019182019101615861565b505086810360408801526158c0818b61578c565b94505050505084606084015282810360808401526158de8185614980565b98975050505050505050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b8381101561595f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa088870301855261594d868351614980565b95509382019390820190600101615913565b5050858403818701525050506159758185614980565b95945050505050565b60008060006060848603121561599357600080fd5b83519250602084015191506040840151614f82816149dd565b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b601f821115612d8457600081815260208120601f850160051c81016020861015615a275750805b601f850160051c820191505b8181101561148657828155600101615a33565b815167ffffffffffffffff811115615a6057615a606146b6565b615a7481615a6e84546156a5565b84615a00565b602080601f831160018114615ac75760008415615a915750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555611486565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015615b1457888601518255948401946001909101908401615af5565b5085821015615b5057878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b60006020808385031215615b7357600080fd5b825167ffffffffffffffff811115615b8a57600080fd5b8301601f81018513615b9b57600080fd5b8051615ba96147c382614e55565b81815260059190911b82018301908381019087831115615bc857600080fd5b928401925b82841015615be657835182529284019290840190615bcd565b979650505050505050565b600063ffffffff80831681810361560757615607615251565b805160208083015191908110156156f2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b6020815260008251610140806020850152615c6b610160850183614980565b915060208501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe080868503016040870152615ca78483614980565b935060408701519150615cd2606087018373ffffffffffffffffffffffffffffffffffffffff169052565b606087015163ffffffff811660808801529150608087015173ffffffffffffffffffffffffffffffffffffffff811660a0880152915060a087015160ff811660c0880152915060c08701519150808685030160e0870152615d338483614980565b935060e08701519150610100818786030181880152615d528584614980565b945080880151925050610120818786030181880152615d718584614980565b94508088015192505050615d94828601826bffffffffffffffffffffffff169052565b5090949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615dd657615dd6615251565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082615e1957615e19615ddb565b500490565b818103600083128015838313168383128216171561453557614535615251565b600082615e4d57615e4d615ddb565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615615ea157615ea1615251565b500590565b8082018281126000831280158216821582161715615ec657615ec6615251565b505092915050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361549457615494615251565b60007f80000000000000000000000000000000000000000000000000000000000000008203615f3057615f30615251565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", } var VerifiableLoadLogTriggerUpkeepABI = VerifiableLoadLogTriggerUpkeepMetaData.ABI diff --git a/core/gethwrappers/generated/verifiable_load_streams_lookup_upkeep_wrapper/verifiable_load_streams_lookup_upkeep_wrapper.go b/core/gethwrappers/generated/verifiable_load_streams_lookup_upkeep_wrapper/verifiable_load_streams_lookup_upkeep_wrapper.go index 1ff616ee12b..e8a10d85dd1 100644 --- a/core/gethwrappers/generated/verifiable_load_streams_lookup_upkeep_wrapper/verifiable_load_streams_lookup_upkeep_wrapper.go +++ b/core/gethwrappers/generated/verifiable_load_streams_lookup_upkeep_wrapper/verifiable_load_streams_lookup_upkeep_wrapper.go @@ -45,7 +45,7 @@ type KeeperRegistryBase21UpkeepInfo struct { var VerifiableLoadStreamsLookupUpkeepMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"_registrar\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_useArb\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"LogEmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"LogEmittedAgain\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"UpkeepTopUp\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BUCKET_SIZE\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"addLinkAmount\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchCancelUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"topic0\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic1\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic2\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic3\",\"type\":\"bytes32\"}],\"name\":\"batchPreparingUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"type\":\"uint8\"}],\"name\":\"batchPreparingUpkeepsSimple\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"number\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"checkGasToBurn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"performGasToBurn\",\"type\":\"uint256\"}],\"name\":\"batchRegisterUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"}],\"name\":\"batchSendLogs\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"interval\",\"type\":\"uint32\"}],\"name\":\"batchSetIntervals\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchUpdatePipelineData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchWithdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"bucketedDelays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"buckets\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"burnPerformGas\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"checkGasToBurns\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"counters\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"delays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"dummyMap\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"eligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emittedAgainSig\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emittedSig\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feedsHex\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"firstPerformBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"gasLimits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveUpkeepIDsDeployedByThisContract\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getAllActiveUpkeepIDsOnRegistry\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"bucket\",\"type\":\"uint16\"}],\"name\":\"getBucketedDelays\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getBucketedDelaysLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getDelays\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getDelaysLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"topic0\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic1\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic2\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic3\",\"type\":\"bytes32\"}],\"name\":\"getLogTriggerConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"logTrigger\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getMinBalanceForUpkeep\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"p\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getPxDelayLastNPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"bucket\",\"type\":\"uint16\"}],\"name\":\"getSumDelayInBucket\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getSumDelayLastNPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getTriggerType\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepInfo\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"maxValidBlocknumber\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"lastPerformedBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"amountSpent\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structKeeperRegistryBase2_1.UpkeepInfo\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepPrivilegeConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepTriggerConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"intervals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"lastTopUpBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkToken\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minBalanceThresholdMultiplier\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"performDataSizes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"performGasToBurns\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"previousPerformBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registrar\",\"outputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registry\",\"outputs\":[{\"internalType\":\"contractIKeeperRegistryMaster\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"}],\"name\":\"sendLog\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"newRegistrar\",\"type\":\"address\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_feeds\",\"type\":\"string[]\"}],\"name\":\"setFeeds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"}],\"name\":\"setInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_timeParamKey\",\"type\":\"string\"}],\"name\":\"setParamKeys\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setPerformDataSize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"cfg\",\"type\":\"bytes\"}],\"name\":\"setUpkeepPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"topUpFund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"topic0\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic1\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic2\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic3\",\"type\":\"bytes32\"}],\"name\":\"updateLogTriggerConfig1\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"cfg\",\"type\":\"bytes\"}],\"name\":\"updateLogTriggerConfig2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"pipelineData\",\"type\":\"bytes\"}],\"name\":\"updateUpkeepPipelineData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepTopUpCheckInterval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbitrumBlockNum\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"withdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x7f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf086080527fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d60a0526005601455601580546001600160681b0319166c140000000002c68af0bb140000179055606460e0526101c0604052604261014081815261010091829190620060c161016039815260200160405180608001604052806042815260200162006103604291399052620000be906016906002620003c7565b506040805180820190915260098152680cccacac892c890caf60bb1b6020820152601790620000ee908262000543565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b602082015260189062000120908262000543565b503480156200012e57600080fd5b506040516200614538038062006145833981016040819052620001519162000625565b81813380600081620001aa5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620001dd57620001dd816200031c565b5050601180546001600160a01b0319166001600160a01b038516908117909155604080516330fe427560e21b815281516000945063c3f909d4926004808401939192918290030181865afa1580156200023a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000260919062000668565b50601380546001600160a01b0319166001600160a01b038381169190911790915560115460408051631b6b6d2360e01b81529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015620002c6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ec919062000699565b601280546001600160a01b0319166001600160a01b039290921691909117905550151560c05250620006c0915050565b336001600160a01b03821603620003765760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620001a1565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b82805482825590600052602060002090810192821562000412579160200282015b8281111562000412578251829062000401908262000543565b5091602001919060010190620003e8565b506200042092915062000424565b5090565b80821115620004205760006200043b828262000445565b5060010162000424565b5080546200045390620004b4565b6000825580601f1062000464575050565b601f01602090049060005260206000209081019062000484919062000487565b50565b5b8082111562000420576000815560010162000488565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620004c957607f821691505b602082108103620004ea57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200053e57600081815260208120601f850160051c81016020861015620005195750805b601f850160051c820191505b818110156200053a5782815560010162000525565b5050505b505050565b81516001600160401b038111156200055f576200055f6200049e565b6200057781620005708454620004b4565b84620004f0565b602080601f831160018114620005af5760008415620005965750858301515b600019600386901b1c1916600185901b1785556200053a565b600085815260208120601f198616915b82811015620005e057888601518255948401946001909101908401620005bf565b5085821015620005ff5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b03811681146200048457600080fd5b600080604083850312156200063957600080fd5b825162000646816200060f565b602084015190925080151581146200065d57600080fd5b809150509250929050565b600080604083850312156200067c57600080fd5b825162000689816200060f565b6020939093015192949293505050565b600060208284031215620006ac57600080fd5b8151620006b9816200060f565b9392505050565b60805160a05160c05160e0516159ab62000716600039600081816105680152611f7a0152600081816109bc0152613c2b0152600081816108270152613679015260008181610d79015261364e01526159ab6000f3fe6080604052600436106104d55760003560e01c806379ea994311610279578063a6b594751161015e578063d6051a72116100d6578063e45530831161008a578063fa333dfb1161006f578063fa333dfb14610f88578063fba7ffa31461103b578063fcdc1f631461106857600080fd5b8063e455308314610f52578063f2fde38b14610f6857600080fd5b8063daee1aeb116100bb578063daee1aeb14610ee5578063dbef701e14610f05578063e0114adb14610f2557600080fd5b8063d6051a7214610ea5578063da6cba4714610ec557600080fd5b8063b657bc9c1161012d578063c041982211610112578063c041982214610e50578063c98f10b014610e70578063d4c2490014610e8557600080fd5b8063b657bc9c14610e10578063becde0e114610e3057600080fd5b8063a6b5947514610d9b578063a72aa27e14610dbb578063af953a4a14610ddb578063afb28d1f14610dfb57600080fd5b8063924ca578116101f15780639b429354116101c05780639d385eaa116101a55780639d385eaa14610d275780639d6f1cc714610d47578063a654824814610d6757600080fd5b80639b42935414610cc95780639b51fb0d14610cf657600080fd5b8063924ca57814610c3f578063948108f714610c5f57806396cebc7c14610c7f5780639ac542eb14610c9f57600080fd5b80638340507c11610248578063873c75861161022d578063873c758614610bc75780638da5cb5b14610be75780638fcb3fba14610c1257600080fd5b80638340507c14610b8757806386e330af14610ba757600080fd5b806379ea994314610afa5780637b10399914610b1a5780637e7a46dc14610b475780638243444a14610b6757600080fd5b806345d2ec17116103ba57806360457ff5116103325780637145f11b116102e657806376721303116102cb5780637672130314610a98578063776898c814610ac557806379ba509714610ae557600080fd5b80637145f11b14610a3b57806373644cce14610a6b57600080fd5b8063642f6cef11610317578063642f6cef146109aa57806369cdbadb146109ee5780636e04ff0d14610a1b57600080fd5b806360457ff514610958578063636092e81461098557600080fd5b80635147cd591161038957806357970e931161036e57806357970e93146108f65780635d4ee7f3146109235780635f17e6161461093857600080fd5b80635147cd59146108a457806351c98be3146108d657600080fd5b806345d2ec17146107e8578063469820931461081557806346e7a63e146108495780634b56a42e1461087657600080fd5b806320e3dbd41161044d5780632a9032d31161041c578063328ffd1111610401578063328ffd111461077b5780633ebe8d6c146107a85780634585e33b146107c857600080fd5b80632a9032d3146107095780632b20e3971461072957600080fd5b806320e3dbd41461067c5780632636aecf1461069c57806328c4b57b146106bc57806329e0a841146106dc57600080fd5b806319d97a94116104a45780631e010439116104895780631e010439146105ea578063206c32e814610627578063207b65161461065c57600080fd5b806319d97a941461059d5780631cdde251146105ca57600080fd5b806306c1cc00146104e1578063077ac621146105035780630b7d33e61461053657806312c550271461055657600080fd5b366104dc57005b600080fd5b3480156104ed57600080fd5b506105016104fc3660046143ad565b611095565b005b34801561050f57600080fd5b5061052361051e366004614460565b6112e4565b6040519081526020015b60405180910390f35b34801561054257600080fd5b50610501610551366004614495565b611322565b34801561056257600080fd5b5061058a7f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff909116815260200161052d565b3480156105a957600080fd5b506105bd6105b83660046144dc565b6113b0565b60405161052d9190614563565b3480156105d657600080fd5b506105016105e5366004614598565b61146d565b3480156105f657600080fd5b5061060a6106053660046144dc565b6115aa565b6040516bffffffffffffffffffffffff909116815260200161052d565b34801561063357600080fd5b506106476106423660046145fd565b61163f565b6040805192835260208301919091520161052d565b34801561066857600080fd5b506105bd6106773660046144dc565b6116c2565b34801561068857600080fd5b50610501610697366004614629565b61171a565b3480156106a857600080fd5b506105016106b736600461468b565b6118e4565b3480156106c857600080fd5b506105236106d7366004614705565b611bad565b3480156106e857600080fd5b506106fc6106f73660046144dc565b611c18565b60405161052d9190614731565b34801561071557600080fd5b50610501610724366004614872565b611d1d565b34801561073557600080fd5b506011546107569073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161052d565b34801561078757600080fd5b506105236107963660046144dc565b60036020526000908152604090205481565b3480156107b457600080fd5b506105236107c33660046144dc565b611dfe565b3480156107d457600080fd5b506105016107e33660046148f6565b611e67565b3480156107f457600080fd5b506108086108033660046145fd565b612086565b60405161052d919061492c565b34801561082157600080fd5b506105237f000000000000000000000000000000000000000000000000000000000000000081565b34801561085557600080fd5b506105236108643660046144dc565b600a6020526000908152604090205481565b34801561088257600080fd5b50610896610891366004614994565b6120f5565b60405161052d929190614a5e565b3480156108b057600080fd5b506108c46108bf3660046144dc565b612149565b60405160ff909116815260200161052d565b3480156108e257600080fd5b506105016108f1366004614a79565b6121dd565b34801561090257600080fd5b506012546107569073ffffffffffffffffffffffffffffffffffffffff1681565b34801561092f57600080fd5b50610501612281565b34801561094457600080fd5b50610501610953366004614ad0565b6123bc565b34801561096457600080fd5b506105236109733660046144dc565b60076020526000908152604090205481565b34801561099157600080fd5b5060155461060a906bffffffffffffffffffffffff1681565b3480156109b657600080fd5b506109de7f000000000000000000000000000000000000000000000000000000000000000081565b604051901515815260200161052d565b3480156109fa57600080fd5b50610523610a093660046144dc565b60086020526000908152604090205481565b348015610a2757600080fd5b50610896610a363660046148f6565b612489565b348015610a4757600080fd5b506109de610a563660046144dc565b600b6020526000908152604090205460ff1681565b348015610a7757600080fd5b50610523610a863660046144dc565b6000908152600c602052604090205490565b348015610aa457600080fd5b50610523610ab33660046144dc565b60046020526000908152604090205481565b348015610ad157600080fd5b506109de610ae03660046144dc565b612636565b348015610af157600080fd5b50610501612688565b348015610b0657600080fd5b50610756610b153660046144dc565b612785565b348015610b2657600080fd5b506013546107569073ffffffffffffffffffffffffffffffffffffffff1681565b348015610b5357600080fd5b50610501610b62366004614af2565b612819565b348015610b7357600080fd5b50610501610b82366004614af2565b6128aa565b348015610b9357600080fd5b50610501610ba2366004614b3e565b612904565b348015610bb357600080fd5b50610501610bc2366004614b8b565b612922565b348015610bd357600080fd5b50610808610be2366004614ad0565b612935565b348015610bf357600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610756565b348015610c1e57600080fd5b50610523610c2d3660046144dc565b60056020526000908152604090205481565b348015610c4b57600080fd5b50610501610c5a366004614ad0565b6129f2565b348015610c6b57600080fd5b50610501610c7a366004614c3c565b612c37565b348015610c8b57600080fd5b50610501610c9a366004614c6c565b612d4f565b348015610cab57600080fd5b506015546108c4906c01000000000000000000000000900460ff1681565b348015610cd557600080fd5b50610501610ce4366004614ad0565b60009182526009602052604090912055565b348015610d0257600080fd5b5061058a610d113660046144dc565b600e6020526000908152604090205461ffff1681565b348015610d3357600080fd5b50610808610d423660046144dc565b612f59565b348015610d5357600080fd5b506105bd610d623660046144dc565b612fbb565b348015610d7357600080fd5b506105237f000000000000000000000000000000000000000000000000000000000000000081565b348015610da757600080fd5b50610501610db6366004614705565b613067565b348015610dc757600080fd5b50610501610dd6366004614c89565b6130d0565b348015610de757600080fd5b50610501610df63660046144dc565b61317b565b348015610e0757600080fd5b506105bd613201565b348015610e1c57600080fd5b5061060a610e2b3660046144dc565b61320e565b348015610e3c57600080fd5b50610501610e4b366004614872565b613266565b348015610e5c57600080fd5b50610808610e6b366004614ad0565b613300565b348015610e7c57600080fd5b506105bd6133fd565b348015610e9157600080fd5b50610501610ea0366004614cae565b61340a565b348015610eb157600080fd5b50610647610ec0366004614ad0565b613489565b348015610ed157600080fd5b50610501610ee0366004614cd3565b6134f2565b348015610ef157600080fd5b50610501610f00366004614872565b613859565b348015610f1157600080fd5b50610523610f20366004614ad0565b613924565b348015610f3157600080fd5b50610523610f403660046144dc565b60096020526000908152604090205481565b348015610f5e57600080fd5b5061052360145481565b348015610f7457600080fd5b50610501610f83366004614629565b613955565b348015610f9457600080fd5b506105bd610fa3366004614d3b565b6040805160c0808201835273ffffffffffffffffffffffffffffffffffffffff9890981680825260ff97881660208084019182528385019889526060808501988952608080860198895260a095860197885286519283019490945291519099168985015296519688019690965293519486019490945290519184019190915251828401528051808303909301835260e0909101905290565b34801561104757600080fd5b506105236110563660046144dc565b60066020526000908152604090205481565b34801561107457600080fd5b506105236110833660046144dc565b60026020526000908152604090205481565b6040805161018081018252600461014082019081527f746573740000000000000000000000000000000000000000000000000000000061016083015281528151602081810184526000808352818401929092523083850181905263ffffffff8b166060850152608084015260ff808a1660a08501528451808301865283815260c085015260e0840189905284519182019094529081526101008201526bffffffffffffffffffffffff8516610120820152601254601154919273ffffffffffffffffffffffffffffffffffffffff9182169263095ea7b392169061117b908c1688614dc3565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526bffffffffffffffffffffffff1660248201526044016020604051808303816000875af11580156111f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121d9190614e07565b5060008860ff1667ffffffffffffffff81111561123c5761123c61424f565b604051908082528060200260200182016040528015611265578160200160208202803683370190505b50905060005b8960ff168160ff1610156112d857600061128484613969565b905080838360ff168151811061129c5761129c614e22565b602090810291909101810191909152600091825260088152604080832088905560079091529020849055806112d081614e51565b91505061126b565b50505050505050505050565b600d602052826000526040600020602052816000526040600020818154811061130c57600080fd5b9060005260206000200160009250925050505481565b6013546040517f0b7d33e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690630b7d33e69061137a9085908590600401614e70565b600060405180830381600087803b15801561139457600080fd5b505af11580156113a8573d6000803e3d6000fd5b505050505050565b6013546040517f19d97a940000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff16906319d97a94906024015b600060405180830381865afa158015611421573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526114679190810190614ed6565b92915050565b6013546040517ffa333dfb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015260ff8816602483015260448201879052606482018690526084820185905260a4820184905290911690634ee88d35908990309063fa333dfb9060c401600060405180830381865afa15801561150c573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526115529190810190614ed6565b6040518363ffffffff1660e01b815260040161156f929190614e70565b600060405180830381600087803b15801561158957600080fd5b505af115801561159d573d6000803e3d6000fd5b5050505050505050505050565b6013546040517f1e0104390000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690631e010439906024015b602060405180830381865afa15801561161b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114679190614f16565b6000828152600d6020908152604080832061ffff8516845282528083208054825181850281018501909352808352849384939291908301828280156116a357602002820191906000526020600020905b81548152602001906001019080831161168f575b505050505090506116b5818251613a37565b92509250505b9250929050565b6013546040517f207b65160000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063207b651690602401611404565b601180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155604080517fc3f909d400000000000000000000000000000000000000000000000000000000815281516000939263c3f909d492600480820193918290030181865afa1580156117b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d49190614f3e565b50601380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691909117909155601154604080517f1b6b6d230000000000000000000000000000000000000000000000000000000081529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015611877573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189b9190614f6c565b601280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555050565b8560005b81811015611ba257600089898381811061190457611904614e22565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc828360405160200161193d91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401611969929190614e70565b600060405180830381600087803b15801561198357600080fd5b505af1158015611997573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015611a0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a319190614f89565b90508060ff16600103611b8d576040517ffa333dfb000000000000000000000000000000000000000000000000000000008152306004820181905260ff8b166024830152604482018a9052606482018890526084820188905260a4820187905260009163fa333dfb9060c401600060405180830381865afa158015611aba573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611b009190810190614ed6565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590611b599086908590600401614e70565b600060405180830381600087803b158015611b7357600080fd5b505af1158015611b87573d6000803e3d6000fd5b50505050505b50508080611b9a90614fa6565b9150506118e8565b505050505050505050565b6000838152600c602090815260408083208054825181850281018501909352808352611c0e93830182828015611c0257602002820191906000526020600020905b815481526020019060010190808311611bee575b50505050508484613abc565b90505b9392505050565b604080516101408101825260008082526020820181905260609282018390528282018190526080820181905260a0820181905260c0820181905260e082018190526101008201526101208101919091526013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c7c3a19a90602401600060405180830381865afa158015611cd7573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526114679190810190615001565b8060005b818160ff161015611df85760135473ffffffffffffffffffffffffffffffffffffffff1663c8048022858560ff8516818110611d5f57611d5f614e22565b905060200201356040518263ffffffff1660e01b8152600401611d8491815260200190565b600060405180830381600087803b158015611d9e57600080fd5b505af1158015611db2573d6000803e3d6000fd5b50505050611de584848360ff16818110611dce57611dce614e22565b90506020020135600f613c1b90919063ffffffff16565b5080611df081614e51565b915050611d21565b50505050565b6000818152600e602052604081205461ffff1681805b8261ffff168161ffff1611611e5f576000858152600d6020908152604080832061ffff85168452909152902054611e4b9083615120565b915080611e5781615133565b915050611e14565b509392505050565b60005a9050600080611e7b84860186614994565b91509150600081806020019051810190611e959190615154565b60008181526005602090815260408083205460049092528220549293509190611ebc613c27565b905082600003611edc576000848152600560205260409020819055612037565b600084815260036020526040812054611ef5848461516d565b611eff919061516d565b6000868152600e6020908152604080832054600d835281842061ffff909116808552908352818420805483518186028101860190945280845295965090949192909190830182828015611f7157602002820191906000526020600020905b815481526020019060010190808311611f5d575b505050505090507f000000000000000000000000000000000000000000000000000000000000000061ffff16815103611fec5781611fae81615133565b6000898152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83161790559250505b506000868152600d6020908152604080832061ffff909416835292815282822080546001818101835591845282842001859055888352600c8252928220805493840181558252902001555b600084815260066020526040812054612051906001615120565b600086815260066020908152604080832084905560049091529020839055905061207b85836129f2565b6112d8858984613067565b6000828152600d6020908152604080832061ffff851684528252918290208054835181840281018401909452808452606093928301828280156120e857602002820191906000526020600020905b8154815260200190600101908083116120d4575b5050505050905092915050565b600060606000848460405160200161210e929190615180565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526001969095509350505050565b6013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690635147cd5990602401602060405180830381865afa1580156121b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114679190614f89565b8160005b8181101561227a5730635f17e61686868481811061220157612201614e22565b90506020020135856040518363ffffffff1660e01b815260040161223592919091825263ffffffff16602082015260400190565b600060405180830381600087803b15801561224f57600080fd5b505af1158015612263573d6000803e3d6000fd5b50505050808061227290614fa6565b9150506121e1565b5050505050565b612289613cc9565b6012546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156122f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061231c9190615154565b6012546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810183905291925073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015612394573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123b89190614e07565b5050565b60008281526003602090815260408083208490556005825280832083905560068252808320839055600c90915281206123f49161414e565b6000828152600e602052604081205461ffff16905b8161ffff168161ffff1611612450576000848152600d6020908152604080832061ffff85168452909152812061243e9161414e565b8061244881615133565b915050612409565b5050506000908152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055565b6000606060005a905060006124a0858701876144dc565b60008181526009602090815260408083205460089092528220549293509190838367ffffffffffffffff8111156124d9576124d961424f565b6040519080825280601f01601f191660200182016040528015612503576020820181803683370190505b50604051602001612515929190614e70565b60405160208183030381529060405290506000612530613c27565b9050600061253d86612636565b90505b835a61254c908961516d565b61255890612710615120565b10156125995781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055612540565b806125b15760008398509850505050505050506116bb565b60176016601884896040516020016125cb91815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527ff055e4a200000000000000000000000000000000000000000000000000000000825261262d9594939291600401615302565b60405180910390fd5b600081815260056020526040812054810361265357506001919050565b600082815260036020908152604080832054600490925290912054612676613c27565b612680919061516d565b101592915050565b60015473ffffffffffffffffffffffffffffffffffffffff163314612709576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161262d565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6013546040517f79ea99430000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff16906379ea994390602401602060405180830381865afa1580156127f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114679190614f6c565b6013546040517fcd7f71b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063cd7f71b590612873908690869086906004016153c5565b600060405180830381600087803b15801561288d57600080fd5b505af11580156128a1573d6000803e3d6000fd5b50505050505050565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690634ee88d3590612873908690869086906004016153c5565b6017612910838261545f565b50601861291d828261545f565b505050565b80516123b890601690602084019061416c565b6013546040517f06e3b632000000000000000000000000000000000000000000000000000000008152600481018490526024810183905260609173ffffffffffffffffffffffffffffffffffffffff16906306e3b63290604401600060405180830381865afa1580156129ac573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611c119190810190615579565b601454600083815260026020526040902054612a0e908361516d565b11156123b8576013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905260009173ffffffffffffffffffffffffffffffffffffffff169063c7c3a19a90602401600060405180830381865afa158015612a84573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612aca9190810190615001565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810186905291925060009173ffffffffffffffffffffffffffffffffffffffff9091169063b657bc9c90602401602060405180830381865afa158015612b3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b639190614f16565b601554909150612b879082906c01000000000000000000000000900460ff16614dc3565b6bffffffffffffffffffffffff1682606001516bffffffffffffffffffffffff161015611df857601554612bca9085906bffffffffffffffffffffffff16612c37565b60008481526002602090815260409182902085905560155482518781526bffffffffffffffffffffffff909116918101919091529081018490527f49d4100ab0124eb4a9a65dc4ea08d6412a43f6f05c49194983f5b322bcc0a5c09060600160405180910390a150505050565b6012546013546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526bffffffffffffffffffffffff8416602482015291169063095ea7b3906044016020604051808303816000875af1158015612cbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ce39190614e07565b506013546040517f948108f7000000000000000000000000000000000000000000000000000000008152600481018490526bffffffffffffffffffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063948108f79060440161137a565b6040517fc04198220000000000000000000000000000000000000000000000000000000081526000600482018190526024820181905290309063c041982290604401600060405180830381865afa158015612dae573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612df49190810190615579565b80519091506000612e03613c27565b905060005b8281101561227a576000848281518110612e2457612e24614e22565b60209081029190910101516013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905291925060009173ffffffffffffffffffffffffffffffffffffffff90911690635147cd5990602401602060405180830381865afa158015612ea4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ec89190614f89565b90508060ff16600103612f44578660ff16600003612f14576040513090859084907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4612f44565b6040513090859084907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a45b50508080612f5190614fa6565b915050612e08565b6000818152600c6020908152604091829020805483518184028101840190945280845260609392830182828015612faf57602002820191906000526020600020905b815481526020019060010190808311612f9b575b50505050509050919050565b60168181548110612fcb57600080fd5b906000526020600020016000915090508054612fe690615214565b80601f016020809104026020016040519081016040528092919081815260200182805461301290615214565b801561305f5780601f106130345761010080835404028352916020019161305f565b820191906000526020600020905b81548152906001019060200180831161304257829003601f168201915b505050505081565b6000838152600760205260409020545b805a613083908561516d565b61308f90612710615120565b1015611df85781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055613077565b6013546040517fa72aa27e0000000000000000000000000000000000000000000000000000000081526004810184905263ffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063a72aa27e90604401600060405180830381600087803b15801561314857600080fd5b505af115801561315c573d6000803e3d6000fd5b505050600092835250600a602052604090912063ffffffff9091169055565b6013546040517f744bfe610000000000000000000000000000000000000000000000000000000081526004810183905230602482015273ffffffffffffffffffffffffffffffffffffffff9091169063744bfe6190604401600060405180830381600087803b1580156131ed57600080fd5b505af115801561227a573d6000803e3d6000fd5b60178054612fe690615214565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff169063b657bc9c906024016115fe565b8060005b818163ffffffff161015611df8573063af953a4a858563ffffffff851681811061329657613296614e22565b905060200201356040518263ffffffff1660e01b81526004016132bb91815260200190565b600060405180830381600087803b1580156132d557600080fd5b505af11580156132e9573d6000803e3d6000fd5b5050505080806132f89061560a565b91505061326a565b6060600061330e600f613d4c565b9050808410613349576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260000361335e5761335b848261516d565b92505b60008367ffffffffffffffff8111156133795761337961424f565b6040519080825280602002602001820160405280156133a2578160200160208202803683370190505b50905060005b848110156133f4576133c56133bd8288615120565b600f90613d56565b8282815181106133d7576133d7614e22565b6020908102919091010152806133ec81614fa6565b9150506133a8565b50949350505050565b60188054612fe690615214565b6000613414613c27565b90508160ff16600003613455576040513090829085907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4505050565b6040513090829085907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a4505050565b6000828152600c602090815260408083208054825181850281018501909352808352849384939291908301828280156134e157602002820191906000526020600020905b8154815260200190600101908083116134cd575b505050505090506116b58185613a37565b8260005b818110156113a857600086868381811061351257613512614e22565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc828360405160200161354b91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401613577929190614e70565b600060405180830381600087803b15801561359157600080fd5b505af11580156135a5573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa15801561361b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061363f9190614f89565b90508060ff16600103613844577f000000000000000000000000000000000000000000000000000000000000000060ff87161561369957507f00000000000000000000000000000000000000000000000000000000000000005b60003073ffffffffffffffffffffffffffffffffffffffff1663fa333dfb308985886040516020016136cd91815260200190565b6040516020818303038152906040526136e590615623565b60405160e086901b7fffffffff0000000000000000000000000000000000000000000000000000000016815273ffffffffffffffffffffffffffffffffffffffff909416600485015260ff90921660248401526044830152606482015260006084820181905260a482015260c401600060405180830381865afa158015613770573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526137b69190810190614ed6565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d359061380f9087908590600401614e70565b600060405180830381600087803b15801561382957600080fd5b505af115801561383d573d6000803e3d6000fd5b5050505050505b5050808061385190614fa6565b9150506134f6565b8060005b81811015611df857600084848381811061387957613879614e22565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc82836040516020016138b291815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016138de929190614e70565b600060405180830381600087803b1580156138f857600080fd5b505af115801561390c573d6000803e3d6000fd5b5050505050808061391c90614fa6565b91505061385d565b600c602052816000526040600020818154811061394057600080fd5b90600052602060002001600091509150505481565b61395d613cc9565b61396681613d62565b50565b6011546040517f3f678e11000000000000000000000000000000000000000000000000000000008152600091829173ffffffffffffffffffffffffffffffffffffffff90911690633f678e11906139c4908690600401615665565b6020604051808303816000875af11580156139e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a079190615154565b9050613a14600f82613e57565b506060909201516000838152600a6020526040902063ffffffff90911690555090565b815160009081908190841580613a4d5750808510155b15613a56578094505b60008092505b85831015613ab257866001613a71858561516d565b613a7b919061516d565b81518110613a8b57613a8b614e22565b602002602001015181613a9e9190615120565b905082613aaa81614fa6565b935050613a5c565b9694955050505050565b82516000908190831580613ad05750808410155b15613ad9578093505b60008467ffffffffffffffff811115613af457613af461424f565b604051908082528060200260200182016040528015613b1d578160200160208202803683370190505b509050600092505b84831015613b8b57866001613b3a858561516d565b613b44919061516d565b81518110613b5457613b54614e22565b6020026020010151818481518110613b6e57613b6e614e22565b602090810291909101015282613b8381614fa6565b935050613b25565b613ba481600060018451613b9f919061516d565b613e63565b85606403613bdd578060018251613bbb919061516d565b81518110613bcb57613bcb614e22565b60200260200101519350505050611c11565b806064825188613bed91906157b7565b613bf79190615823565b81518110613c0757613c07614e22565b602002602001015193505050509392505050565b6000611c118383613fdb565b60007f000000000000000000000000000000000000000000000000000000000000000015613cc457606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613c9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cbf9190615154565b905090565b504390565b60005473ffffffffffffffffffffffffffffffffffffffff163314613d4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161262d565b565b6000611467825490565b6000611c1183836140d5565b3373ffffffffffffffffffffffffffffffffffffffff821603613de1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161262d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611c1183836140ff565b8181808203613e73575050505050565b6000856002613e828787615837565b613e8c9190615857565b613e9690876158bf565b81518110613ea657613ea6614e22565b602002602001015190505b818313613fb5575b80868481518110613ecc57613ecc614e22565b60200260200101511015613eec5782613ee4816158e7565b935050613eb9565b858281518110613efe57613efe614e22565b6020026020010151811015613f1f5781613f1781615918565b925050613eec565b818313613fb057858281518110613f3857613f38614e22565b6020026020010151868481518110613f5257613f52614e22565b6020026020010151878581518110613f6c57613f6c614e22565b60200260200101888581518110613f8557613f85614e22565b60209081029190910101919091525282613f9e816158e7565b9350508180613fac90615918565b9250505b613eb1565b81851215613fc857613fc8868684613e63565b838312156113a8576113a8868486613e63565b600081815260018301602052604081205480156140c4576000613fff60018361516d565b85549091506000906140139060019061516d565b905081811461407857600086600001828154811061403357614033614e22565b906000526020600020015490508087600001848154811061405657614056614e22565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806140895761408961596f565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611467565b6000915050611467565b5092915050565b60008260000182815481106140ec576140ec614e22565b9060005260206000200154905092915050565b600081815260018301602052604081205461414657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611467565b506000611467565b508054600082559060005260206000209081019061396691906141c2565b8280548282559060005260206000209081019282156141b2579160200282015b828111156141b257825182906141a2908261545f565b509160200191906001019061418c565b506141be9291506141d7565b5090565b5b808211156141be57600081556001016141c3565b808211156141be5760006141eb82826141f4565b506001016141d7565b50805461420090615214565b6000825580601f10614210575050565b601f01602090049060005260206000209081019061396691906141c2565b60ff8116811461396657600080fd5b63ffffffff8116811461396657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610140810167ffffffffffffffff811182821017156142a2576142a261424f565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156142ef576142ef61424f565b604052919050565b600067ffffffffffffffff8211156143115761431161424f565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261434e57600080fd5b813561436161435c826142f7565b6142a8565b81815284602083860101111561437657600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff8116811461396657600080fd5b600080600080600080600060e0888a0312156143c857600080fd5b87356143d38161422e565b965060208801356143e38161423d565b955060408801356143f38161422e565b9450606088013567ffffffffffffffff81111561440f57600080fd5b61441b8a828b0161433d565b945050608088013561442c81614393565b9699959850939692959460a0840135945060c09093013592915050565b803561ffff8116811461445b57600080fd5b919050565b60008060006060848603121561447557600080fd5b8335925061448560208501614449565b9150604084013590509250925092565b600080604083850312156144a857600080fd5b82359150602083013567ffffffffffffffff8111156144c657600080fd5b6144d28582860161433d565b9150509250929050565b6000602082840312156144ee57600080fd5b5035919050565b60005b838110156145105781810151838201526020016144f8565b50506000910152565b600081518084526145318160208601602086016144f5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611c116020830184614519565b73ffffffffffffffffffffffffffffffffffffffff8116811461396657600080fd5b600080600080600080600060e0888a0312156145b357600080fd5b8735965060208801356145c581614576565b955060408801356145d58161422e565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b6000806040838503121561461057600080fd5b8235915061462060208401614449565b90509250929050565b60006020828403121561463b57600080fd5b8135611c1181614576565b60008083601f84011261465857600080fd5b50813567ffffffffffffffff81111561467057600080fd5b6020830191508360208260051b85010111156116bb57600080fd5b600080600080600080600060c0888a0312156146a657600080fd5b873567ffffffffffffffff8111156146bd57600080fd5b6146c98a828b01614646565b90985096505060208801356146dd8161422e565b96999598509596604081013596506060810135956080820135955060a0909101359350915050565b60008060006060848603121561471a57600080fd5b505081359360208301359350604090920135919050565b6020815261475860208201835173ffffffffffffffffffffffffffffffffffffffff169052565b60006020830151614771604084018263ffffffff169052565b50604083015161014080606085015261478e610160850183614519565b915060608501516147af60808601826bffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015163ffffffff811660e08601525060e085015161010061481b818701836bffffffffffffffffffffffff169052565b86015190506101206148308682018315159052565b8601518584037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018387015290506148688382614519565b9695505050505050565b6000806020838503121561488557600080fd5b823567ffffffffffffffff81111561489c57600080fd5b6148a885828601614646565b90969095509350505050565b60008083601f8401126148c657600080fd5b50813567ffffffffffffffff8111156148de57600080fd5b6020830191508360208285010111156116bb57600080fd5b6000806020838503121561490957600080fd5b823567ffffffffffffffff81111561492057600080fd5b6148a8858286016148b4565b6020808252825182820181905260009190848201906040850190845b8181101561496457835183529284019291840191600101614948565b50909695505050505050565b600067ffffffffffffffff82111561498a5761498a61424f565b5060051b60200190565b600080604083850312156149a757600080fd5b823567ffffffffffffffff808211156149bf57600080fd5b818501915085601f8301126149d357600080fd5b813560206149e361435c83614970565b82815260059290921b84018101918181019089841115614a0257600080fd5b8286015b84811015614a3a57803586811115614a1e5760008081fd5b614a2c8c86838b010161433d565b845250918301918301614a06565b5096505086013592505080821115614a5157600080fd5b506144d28582860161433d565b8215158152604060208201526000611c0e6040830184614519565b600080600060408486031215614a8e57600080fd5b833567ffffffffffffffff811115614aa557600080fd5b614ab186828701614646565b9094509250506020840135614ac58161423d565b809150509250925092565b60008060408385031215614ae357600080fd5b50508035926020909101359150565b600080600060408486031215614b0757600080fd5b83359250602084013567ffffffffffffffff811115614b2557600080fd5b614b31868287016148b4565b9497909650939450505050565b60008060408385031215614b5157600080fd5b823567ffffffffffffffff80821115614b6957600080fd5b614b758683870161433d565b93506020850135915080821115614a5157600080fd5b60006020808385031215614b9e57600080fd5b823567ffffffffffffffff80821115614bb657600080fd5b818501915085601f830112614bca57600080fd5b8135614bd861435c82614970565b81815260059190911b83018401908481019088831115614bf757600080fd5b8585015b83811015614c2f57803585811115614c135760008081fd5b614c218b89838a010161433d565b845250918601918601614bfb565b5098975050505050505050565b60008060408385031215614c4f57600080fd5b823591506020830135614c6181614393565b809150509250929050565b600060208284031215614c7e57600080fd5b8135611c118161422e565b60008060408385031215614c9c57600080fd5b823591506020830135614c618161423d565b60008060408385031215614cc157600080fd5b823591506020830135614c618161422e565b60008060008060608587031215614ce957600080fd5b843567ffffffffffffffff811115614d0057600080fd5b614d0c87828801614646565b9095509350506020850135614d208161422e565b91506040850135614d308161422e565b939692955090935050565b60008060008060008060c08789031215614d5457600080fd5b8635614d5f81614576565b95506020870135614d6f8161422e565b95989597505050506040840135936060810135936080820135935060a0909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006bffffffffffffffffffffffff80831681851681830481118215151615614dee57614dee614d94565b02949350505050565b8051801515811461445b57600080fd5b600060208284031215614e1957600080fd5b611c1182614df7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff821660ff8103614e6757614e67614d94565b60010192915050565b828152604060208201526000611c0e6040830184614519565b600082601f830112614e9a57600080fd5b8151614ea861435c826142f7565b818152846020838601011115614ebd57600080fd5b614ece8260208301602087016144f5565b949350505050565b600060208284031215614ee857600080fd5b815167ffffffffffffffff811115614eff57600080fd5b614ece84828501614e89565b805161445b81614393565b600060208284031215614f2857600080fd5b8151611c1181614393565b805161445b81614576565b60008060408385031215614f5157600080fd5b8251614f5c81614576565b6020939093015192949293505050565b600060208284031215614f7e57600080fd5b8151611c1181614576565b600060208284031215614f9b57600080fd5b8151611c118161422e565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614fd757614fd7614d94565b5060010190565b805161445b8161423d565b805167ffffffffffffffff8116811461445b57600080fd5b60006020828403121561501357600080fd5b815167ffffffffffffffff8082111561502b57600080fd5b90830190610140828603121561504057600080fd5b61504861427e565b61505183614f33565b815261505f60208401614fde565b602082015260408301518281111561507657600080fd5b61508287828601614e89565b60408301525061509460608401614f0b565b60608201526150a560808401614f33565b60808201526150b660a08401614fe9565b60a08201526150c760c08401614fde565b60c08201526150d860e08401614f0b565b60e08201526101006150eb818501614df7565b90820152610120838101518381111561510357600080fd5b61510f88828701614e89565b918301919091525095945050505050565b8082018082111561146757611467614d94565b600061ffff80831681810361514a5761514a614d94565b6001019392505050565b60006020828403121561516657600080fd5b5051919050565b8181038181111561146757611467614d94565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b838110156151f5577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030185526151e3868351614519565b955093820193908201906001016151a9565b50508584038187015250505061520b8185614519565b95945050505050565b600181811c9082168061522857607f821691505b602082108103615261577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000815461527481615214565b80855260206001838116801561529157600181146152c9576152f7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b89010195506152f7565b866000528260002060005b858110156152ef5781548a82018601529083019084016152d4565b890184019650505b505050505092915050565b60a08152600061531560a0830188615267565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b83811015615387577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030185526153758383615267565b9486019492506001918201910161533c565b5050868103604088015261539b818b615267565b94505050505084606084015282810360808401526153b98185614519565b98975050505050505050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b601f82111561291d57600081815260208120601f850160051c810160208610156154405750805b601f850160051c820191505b818110156113a85782815560010161544c565b815167ffffffffffffffff8111156154795761547961424f565b61548d816154878454615214565b84615419565b602080601f8311600181146154e057600084156154aa5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556113a8565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561552d5788860151825594840194600190910190840161550e565b508582101561556957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b6000602080838503121561558c57600080fd5b825167ffffffffffffffff8111156155a357600080fd5b8301601f810185136155b457600080fd5b80516155c261435c82614970565b81815260059190911b820183019083810190878311156155e157600080fd5b928401925b828410156155ff578351825292840192908401906155e6565b979650505050505050565b600063ffffffff80831681810361514a5761514a614d94565b80516020808301519190811015615261577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b6020815260008251610140806020850152615684610160850183614519565b915060208501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0808685030160408701526156c08483614519565b9350604087015191506156eb606087018373ffffffffffffffffffffffffffffffffffffffff169052565b606087015163ffffffff811660808801529150608087015173ffffffffffffffffffffffffffffffffffffffff811660a0880152915060a087015160ff811660c0880152915060c08701519150808685030160e087015261574c8483614519565b935060e0870151915061010081878603018188015261576b8584614519565b94508088015192505061012081878603018188015261578a8584614519565b945080880151925050506157ad828601826bffffffffffffffffffffffff169052565b5090949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156157ef576157ef614d94565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082615832576158326157f4565b500490565b81810360008312801583831316838312821617156140ce576140ce614d94565b600082615866576158666157f4565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f8000000000000000000000000000000000000000000000000000000000000000831416156158ba576158ba614d94565b500590565b80820182811260008312801582168215821617156158df576158df614d94565b505092915050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614fd757614fd7614d94565b60007f8000000000000000000000000000000000000000000000000000000000000000820361594957615949614d94565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", + Bin: "0x7f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf086080527fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d60a0526005601455601580546001600160681b0319166c140000000002c68af0bb140000179055606460e0526101c0604052604261014081815261010091829190620061d161016039815260200160405180608001604052806042815260200162006213604291399052620000be906016906002620003c7565b506040805180820190915260098152680cccacac892c890caf60bb1b6020820152601790620000ee908262000543565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b602082015260189062000120908262000543565b503480156200012e57600080fd5b506040516200625538038062006255833981016040819052620001519162000625565b81813380600081620001aa5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620001dd57620001dd816200031c565b5050601180546001600160a01b0319166001600160a01b038516908117909155604080516330fe427560e21b815281516000945063c3f909d4926004808401939192918290030181865afa1580156200023a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000260919062000668565b50601380546001600160a01b0319166001600160a01b038381169190911790915560115460408051631b6b6d2360e01b81529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015620002c6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ec919062000699565b601280546001600160a01b0319166001600160a01b039290921691909117905550151560c05250620006c0915050565b336001600160a01b03821603620003765760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620001a1565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b82805482825590600052602060002090810192821562000412579160200282015b8281111562000412578251829062000401908262000543565b5091602001919060010190620003e8565b506200042092915062000424565b5090565b80821115620004205760006200043b828262000445565b5060010162000424565b5080546200045390620004b4565b6000825580601f1062000464575050565b601f01602090049060005260206000209081019062000484919062000487565b50565b5b8082111562000420576000815560010162000488565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620004c957607f821691505b602082108103620004ea57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200053e57600081815260208120601f850160051c81016020861015620005195750805b601f850160051c820191505b818110156200053a5782815560010162000525565b5050505b505050565b81516001600160401b038111156200055f576200055f6200049e565b6200057781620005708454620004b4565b84620004f0565b602080601f831160018114620005af5760008415620005965750858301515b600019600386901b1c1916600185901b1785556200053a565b600085815260208120601f198616915b82811015620005e057888601518255948401946001909101908401620005bf565b5085821015620005ff5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b03811681146200048457600080fd5b600080604083850312156200063957600080fd5b825162000646816200060f565b602084015190925080151581146200065d57600080fd5b809150509250929050565b600080604083850312156200067c57600080fd5b825162000689816200060f565b6020939093015192949293505050565b600060208284031215620006ac57600080fd5b8151620006b9816200060f565b9392505050565b60805160a05160c05160e051615abb62000716600039600081816105680152611f7a0152600081816109bc0152613ca701526000818161082701526136f5015260008181610d7901526136ca0152615abb6000f3fe6080604052600436106104d55760003560e01c806379ea994311610279578063a6b594751161015e578063d6051a72116100d6578063e45530831161008a578063fa333dfb1161006f578063fa333dfb14610f88578063fba7ffa31461103b578063fcdc1f631461106857600080fd5b8063e455308314610f52578063f2fde38b14610f6857600080fd5b8063daee1aeb116100bb578063daee1aeb14610ee5578063dbef701e14610f05578063e0114adb14610f2557600080fd5b8063d6051a7214610ea5578063da6cba4714610ec557600080fd5b8063b657bc9c1161012d578063c041982211610112578063c041982214610e50578063c98f10b014610e70578063d4c2490014610e8557600080fd5b8063b657bc9c14610e10578063becde0e114610e3057600080fd5b8063a6b5947514610d9b578063a72aa27e14610dbb578063af953a4a14610ddb578063afb28d1f14610dfb57600080fd5b8063924ca578116101f15780639b429354116101c05780639d385eaa116101a55780639d385eaa14610d275780639d6f1cc714610d47578063a654824814610d6757600080fd5b80639b42935414610cc95780639b51fb0d14610cf657600080fd5b8063924ca57814610c3f578063948108f714610c5f57806396cebc7c14610c7f5780639ac542eb14610c9f57600080fd5b80638340507c11610248578063873c75861161022d578063873c758614610bc75780638da5cb5b14610be75780638fcb3fba14610c1257600080fd5b80638340507c14610b8757806386e330af14610ba757600080fd5b806379ea994314610afa5780637b10399914610b1a5780637e7a46dc14610b475780638243444a14610b6757600080fd5b806345d2ec17116103ba57806360457ff5116103325780637145f11b116102e657806376721303116102cb5780637672130314610a98578063776898c814610ac557806379ba509714610ae557600080fd5b80637145f11b14610a3b57806373644cce14610a6b57600080fd5b8063642f6cef11610317578063642f6cef146109aa57806369cdbadb146109ee5780636e04ff0d14610a1b57600080fd5b806360457ff514610958578063636092e81461098557600080fd5b80635147cd591161038957806357970e931161036e57806357970e93146108f65780635d4ee7f3146109235780635f17e6161461093857600080fd5b80635147cd59146108a457806351c98be3146108d657600080fd5b806345d2ec17146107e8578063469820931461081557806346e7a63e146108495780634b56a42e1461087657600080fd5b806320e3dbd41161044d5780632a9032d31161041c578063328ffd1111610401578063328ffd111461077b5780633ebe8d6c146107a85780634585e33b146107c857600080fd5b80632a9032d3146107095780632b20e3971461072957600080fd5b806320e3dbd41461067c5780632636aecf1461069c57806328c4b57b146106bc57806329e0a841146106dc57600080fd5b806319d97a94116104a45780631e010439116104895780631e010439146105ea578063206c32e814610627578063207b65161461065c57600080fd5b806319d97a941461059d5780631cdde251146105ca57600080fd5b806306c1cc00146104e1578063077ac621146105035780630b7d33e61461053657806312c550271461055657600080fd5b366104dc57005b600080fd5b3480156104ed57600080fd5b506105016104fc366004614429565b611095565b005b34801561050f57600080fd5b5061052361051e3660046144dc565b6112e4565b6040519081526020015b60405180910390f35b34801561054257600080fd5b50610501610551366004614511565b611322565b34801561056257600080fd5b5061058a7f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff909116815260200161052d565b3480156105a957600080fd5b506105bd6105b8366004614558565b6113b0565b60405161052d91906145df565b3480156105d657600080fd5b506105016105e5366004614614565b61146d565b3480156105f657600080fd5b5061060a610605366004614558565b6115aa565b6040516bffffffffffffffffffffffff909116815260200161052d565b34801561063357600080fd5b50610647610642366004614679565b61163f565b6040805192835260208301919091520161052d565b34801561066857600080fd5b506105bd610677366004614558565b6116c2565b34801561068857600080fd5b506105016106973660046146a5565b61171a565b3480156106a857600080fd5b506105016106b7366004614707565b6118e4565b3480156106c857600080fd5b506105236106d7366004614781565b611bad565b3480156106e857600080fd5b506106fc6106f7366004614558565b611c18565b60405161052d91906147ad565b34801561071557600080fd5b506105016107243660046148ee565b611d1d565b34801561073557600080fd5b506011546107569073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161052d565b34801561078757600080fd5b50610523610796366004614558565b60036020526000908152604090205481565b3480156107b457600080fd5b506105236107c3366004614558565b611dfe565b3480156107d457600080fd5b506105016107e3366004614972565b611e67565b3480156107f457600080fd5b50610808610803366004614679565b612086565b60405161052d91906149a8565b34801561082157600080fd5b506105237f000000000000000000000000000000000000000000000000000000000000000081565b34801561085557600080fd5b50610523610864366004614558565b600a6020526000908152604090205481565b34801561088257600080fd5b50610896610891366004614a10565b6120f5565b60405161052d929190614ada565b3480156108b057600080fd5b506108c46108bf366004614558565b612149565b60405160ff909116815260200161052d565b3480156108e257600080fd5b506105016108f1366004614af5565b6121dd565b34801561090257600080fd5b506012546107569073ffffffffffffffffffffffffffffffffffffffff1681565b34801561092f57600080fd5b50610501612281565b34801561094457600080fd5b50610501610953366004614b4c565b6123bc565b34801561096457600080fd5b50610523610973366004614558565b60076020526000908152604090205481565b34801561099157600080fd5b5060155461060a906bffffffffffffffffffffffff1681565b3480156109b657600080fd5b506109de7f000000000000000000000000000000000000000000000000000000000000000081565b604051901515815260200161052d565b3480156109fa57600080fd5b50610523610a09366004614558565b60086020526000908152604090205481565b348015610a2757600080fd5b50610896610a36366004614972565b612489565b348015610a4757600080fd5b506109de610a56366004614558565b600b6020526000908152604090205460ff1681565b348015610a7757600080fd5b50610523610a86366004614558565b6000908152600c602052604090205490565b348015610aa457600080fd5b50610523610ab3366004614558565b60046020526000908152604090205481565b348015610ad157600080fd5b506109de610ae0366004614558565b6126b2565b348015610af157600080fd5b50610501612704565b348015610b0657600080fd5b50610756610b15366004614558565b612801565b348015610b2657600080fd5b506013546107569073ffffffffffffffffffffffffffffffffffffffff1681565b348015610b5357600080fd5b50610501610b62366004614b6e565b612895565b348015610b7357600080fd5b50610501610b82366004614b6e565b612926565b348015610b9357600080fd5b50610501610ba2366004614bba565b612980565b348015610bb357600080fd5b50610501610bc2366004614c07565b61299e565b348015610bd357600080fd5b50610808610be2366004614b4c565b6129b1565b348015610bf357600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610756565b348015610c1e57600080fd5b50610523610c2d366004614558565b60056020526000908152604090205481565b348015610c4b57600080fd5b50610501610c5a366004614b4c565b612a6e565b348015610c6b57600080fd5b50610501610c7a366004614cb8565b612cb3565b348015610c8b57600080fd5b50610501610c9a366004614ce8565b612dcb565b348015610cab57600080fd5b506015546108c4906c01000000000000000000000000900460ff1681565b348015610cd557600080fd5b50610501610ce4366004614b4c565b60009182526009602052604090912055565b348015610d0257600080fd5b5061058a610d11366004614558565b600e6020526000908152604090205461ffff1681565b348015610d3357600080fd5b50610808610d42366004614558565b612fd5565b348015610d5357600080fd5b506105bd610d62366004614558565b613037565b348015610d7357600080fd5b506105237f000000000000000000000000000000000000000000000000000000000000000081565b348015610da757600080fd5b50610501610db6366004614781565b6130e3565b348015610dc757600080fd5b50610501610dd6366004614d05565b61314c565b348015610de757600080fd5b50610501610df6366004614558565b6131f7565b348015610e0757600080fd5b506105bd61327d565b348015610e1c57600080fd5b5061060a610e2b366004614558565b61328a565b348015610e3c57600080fd5b50610501610e4b3660046148ee565b6132e2565b348015610e5c57600080fd5b50610808610e6b366004614b4c565b61337c565b348015610e7c57600080fd5b506105bd613479565b348015610e9157600080fd5b50610501610ea0366004614d2a565b613486565b348015610eb157600080fd5b50610647610ec0366004614b4c565b613505565b348015610ed157600080fd5b50610501610ee0366004614d4f565b61356e565b348015610ef157600080fd5b50610501610f003660046148ee565b6138d5565b348015610f1157600080fd5b50610523610f20366004614b4c565b6139a0565b348015610f3157600080fd5b50610523610f40366004614558565b60096020526000908152604090205481565b348015610f5e57600080fd5b5061052360145481565b348015610f7457600080fd5b50610501610f833660046146a5565b6139d1565b348015610f9457600080fd5b506105bd610fa3366004614db7565b6040805160c0808201835273ffffffffffffffffffffffffffffffffffffffff9890981680825260ff97881660208084019182528385019889526060808501988952608080860198895260a095860197885286519283019490945291519099168985015296519688019690965293519486019490945290519184019190915251828401528051808303909301835260e0909101905290565b34801561104757600080fd5b50610523611056366004614558565b60066020526000908152604090205481565b34801561107457600080fd5b50610523611083366004614558565b60026020526000908152604090205481565b6040805161018081018252600461014082019081527f746573740000000000000000000000000000000000000000000000000000000061016083015281528151602081810184526000808352818401929092523083850181905263ffffffff8b166060850152608084015260ff808a1660a08501528451808301865283815260c085015260e0840189905284519182019094529081526101008201526bffffffffffffffffffffffff8516610120820152601254601154919273ffffffffffffffffffffffffffffffffffffffff9182169263095ea7b392169061117b908c1688614e3f565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526bffffffffffffffffffffffff1660248201526044016020604051808303816000875af11580156111f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121d9190614e83565b5060008860ff1667ffffffffffffffff81111561123c5761123c6142cb565b604051908082528060200260200182016040528015611265578160200160208202803683370190505b50905060005b8960ff168160ff1610156112d8576000611284846139e5565b905080838360ff168151811061129c5761129c614e9e565b602090810291909101810191909152600091825260088152604080832088905560079091529020849055806112d081614ecd565b91505061126b565b50505050505050505050565b600d602052826000526040600020602052816000526040600020818154811061130c57600080fd5b9060005260206000200160009250925050505481565b6013546040517f0b7d33e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690630b7d33e69061137a9085908590600401614eec565b600060405180830381600087803b15801561139457600080fd5b505af11580156113a8573d6000803e3d6000fd5b505050505050565b6013546040517f19d97a940000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff16906319d97a94906024015b600060405180830381865afa158015611421573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526114679190810190614f52565b92915050565b6013546040517ffa333dfb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015260ff8816602483015260448201879052606482018690526084820185905260a4820184905290911690634ee88d35908990309063fa333dfb9060c401600060405180830381865afa15801561150c573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526115529190810190614f52565b6040518363ffffffff1660e01b815260040161156f929190614eec565b600060405180830381600087803b15801561158957600080fd5b505af115801561159d573d6000803e3d6000fd5b5050505050505050505050565b6013546040517f1e0104390000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690631e010439906024015b602060405180830381865afa15801561161b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114679190614f92565b6000828152600d6020908152604080832061ffff8516845282528083208054825181850281018501909352808352849384939291908301828280156116a357602002820191906000526020600020905b81548152602001906001019080831161168f575b505050505090506116b5818251613ab3565b92509250505b9250929050565b6013546040517f207b65160000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063207b651690602401611404565b601180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155604080517fc3f909d400000000000000000000000000000000000000000000000000000000815281516000939263c3f909d492600480820193918290030181865afa1580156117b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d49190614fba565b50601380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691909117909155601154604080517f1b6b6d230000000000000000000000000000000000000000000000000000000081529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015611877573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189b9190614fe8565b601280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555050565b8560005b81811015611ba257600089898381811061190457611904614e9e565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc828360405160200161193d91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401611969929190614eec565b600060405180830381600087803b15801561198357600080fd5b505af1158015611997573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015611a0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a319190615005565b90508060ff16600103611b8d576040517ffa333dfb000000000000000000000000000000000000000000000000000000008152306004820181905260ff8b166024830152604482018a9052606482018890526084820188905260a4820187905260009163fa333dfb9060c401600060405180830381865afa158015611aba573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611b009190810190614f52565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590611b599086908590600401614eec565b600060405180830381600087803b158015611b7357600080fd5b505af1158015611b87573d6000803e3d6000fd5b50505050505b50508080611b9a90615022565b9150506118e8565b505050505050505050565b6000838152600c602090815260408083208054825181850281018501909352808352611c0e93830182828015611c0257602002820191906000526020600020905b815481526020019060010190808311611bee575b50505050508484613b38565b90505b9392505050565b604080516101408101825260008082526020820181905260609282018390528282018190526080820181905260a0820181905260c0820181905260e082018190526101008201526101208101919091526013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c7c3a19a90602401600060405180830381865afa158015611cd7573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611467919081019061507d565b8060005b818160ff161015611df85760135473ffffffffffffffffffffffffffffffffffffffff1663c8048022858560ff8516818110611d5f57611d5f614e9e565b905060200201356040518263ffffffff1660e01b8152600401611d8491815260200190565b600060405180830381600087803b158015611d9e57600080fd5b505af1158015611db2573d6000803e3d6000fd5b50505050611de584848360ff16818110611dce57611dce614e9e565b90506020020135600f613c9790919063ffffffff16565b5080611df081614ecd565b915050611d21565b50505050565b6000818152600e602052604081205461ffff1681805b8261ffff168161ffff1611611e5f576000858152600d6020908152604080832061ffff85168452909152902054611e4b908361519c565b915080611e57816151af565b915050611e14565b509392505050565b60005a9050600080611e7b84860186614a10565b91509150600081806020019051810190611e9591906151d0565b60008181526005602090815260408083205460049092528220549293509190611ebc613ca3565b905082600003611edc576000848152600560205260409020819055612037565b600084815260036020526040812054611ef584846151e9565b611eff91906151e9565b6000868152600e6020908152604080832054600d835281842061ffff909116808552908352818420805483518186028101860190945280845295965090949192909190830182828015611f7157602002820191906000526020600020905b815481526020019060010190808311611f5d575b505050505090507f000000000000000000000000000000000000000000000000000000000000000061ffff16815103611fec5781611fae816151af565b6000898152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83161790559250505b506000868152600d6020908152604080832061ffff909416835292815282822080546001818101835591845282842001859055888352600c8252928220805493840181558252902001555b60008481526006602052604081205461205190600161519c565b600086815260066020908152604080832084905560049091529020839055905061207b8583612a6e565b6112d88589846130e3565b6000828152600d6020908152604080832061ffff851684528252918290208054835181840281018401909452808452606093928301828280156120e857602002820191906000526020600020905b8154815260200190600101908083116120d4575b5050505050905092915050565b600060606000848460405160200161210e9291906151fc565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526001969095509350505050565b6013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690635147cd5990602401602060405180830381865afa1580156121b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114679190615005565b8160005b8181101561227a5730635f17e61686868481811061220157612201614e9e565b90506020020135856040518363ffffffff1660e01b815260040161223592919091825263ffffffff16602082015260400190565b600060405180830381600087803b15801561224f57600080fd5b505af1158015612263573d6000803e3d6000fd5b50505050808061227290615022565b9150506121e1565b5050505050565b612289613d45565b6012546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156122f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061231c91906151d0565b6012546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810183905291925073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015612394573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123b89190614e83565b5050565b60008281526003602090815260408083208490556005825280832083905560068252808320839055600c90915281206123f4916141ca565b6000828152600e602052604081205461ffff16905b8161ffff168161ffff1611612450576000848152600d6020908152604080832061ffff85168452909152812061243e916141ca565b80612448816151af565b915050612409565b5050506000908152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055565b6000606060005a905060006124a085870187614558565b60008181526009602090815260408083205460089092528220549293509190838367ffffffffffffffff8111156124d9576124d96142cb565b6040519080825280601f01601f191660200182016040528015612503576020820181803683370190505b50604051602001612515929190614eec565b60405160208183030381529060405290506000612530613ca3565b9050600061253d866126b2565b90505b835a61254c90896151e9565b6125589061271061519c565b10156125995781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055612540565b806125b15760008398509850505050505050506116bb565b6040517f6665656449644865780000000000000000000000000000000000000000000000602082015260009060290160405160208183030381529060405280519060200120601760405160200161260891906152e3565b604051602081830303815290604052805190602001200361262a57508161262d565b50425b601760166018838a60405160200161264791815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527ff055e4a20000000000000000000000000000000000000000000000000000000082526126a99594939291600401615412565b60405180910390fd5b60008181526005602052604081205481036126cf57506001919050565b6000828152600360209081526040808320546004909252909120546126f2613ca3565b6126fc91906151e9565b101592915050565b60015473ffffffffffffffffffffffffffffffffffffffff163314612785576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016126a9565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6013546040517f79ea99430000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff16906379ea994390602401602060405180830381865afa158015612871573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114679190614fe8565b6013546040517fcd7f71b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063cd7f71b5906128ef908690869086906004016154d5565b600060405180830381600087803b15801561290957600080fd5b505af115801561291d573d6000803e3d6000fd5b50505050505050565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690634ee88d35906128ef908690869086906004016154d5565b601761298c838261556f565b506018612999828261556f565b505050565b80516123b89060169060208401906141e8565b6013546040517f06e3b632000000000000000000000000000000000000000000000000000000008152600481018490526024810183905260609173ffffffffffffffffffffffffffffffffffffffff16906306e3b63290604401600060405180830381865afa158015612a28573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611c119190810190615689565b601454600083815260026020526040902054612a8a90836151e9565b11156123b8576013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905260009173ffffffffffffffffffffffffffffffffffffffff169063c7c3a19a90602401600060405180830381865afa158015612b00573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612b46919081019061507d565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810186905291925060009173ffffffffffffffffffffffffffffffffffffffff9091169063b657bc9c90602401602060405180830381865afa158015612bbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bdf9190614f92565b601554909150612c039082906c01000000000000000000000000900460ff16614e3f565b6bffffffffffffffffffffffff1682606001516bffffffffffffffffffffffff161015611df857601554612c469085906bffffffffffffffffffffffff16612cb3565b60008481526002602090815260409182902085905560155482518781526bffffffffffffffffffffffff909116918101919091529081018490527f49d4100ab0124eb4a9a65dc4ea08d6412a43f6f05c49194983f5b322bcc0a5c09060600160405180910390a150505050565b6012546013546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526bffffffffffffffffffffffff8416602482015291169063095ea7b3906044016020604051808303816000875af1158015612d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d5f9190614e83565b506013546040517f948108f7000000000000000000000000000000000000000000000000000000008152600481018490526bffffffffffffffffffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063948108f79060440161137a565b6040517fc04198220000000000000000000000000000000000000000000000000000000081526000600482018190526024820181905290309063c041982290604401600060405180830381865afa158015612e2a573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612e709190810190615689565b80519091506000612e7f613ca3565b905060005b8281101561227a576000848281518110612ea057612ea0614e9e565b60209081029190910101516013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905291925060009173ffffffffffffffffffffffffffffffffffffffff90911690635147cd5990602401602060405180830381865afa158015612f20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f449190615005565b90508060ff16600103612fc0578660ff16600003612f90576040513090859084907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4612fc0565b6040513090859084907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a45b50508080612fcd90615022565b915050612e84565b6000818152600c602090815260409182902080548351818402810184019094528084526060939283018282801561302b57602002820191906000526020600020905b815481526020019060010190808311613017575b50505050509050919050565b6016818154811061304757600080fd5b90600052602060002001600091509050805461306290615290565b80601f016020809104026020016040519081016040528092919081815260200182805461308e90615290565b80156130db5780601f106130b0576101008083540402835291602001916130db565b820191906000526020600020905b8154815290600101906020018083116130be57829003601f168201915b505050505081565b6000838152600760205260409020545b805a6130ff90856151e9565b61310b9061271061519c565b1015611df85781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556130f3565b6013546040517fa72aa27e0000000000000000000000000000000000000000000000000000000081526004810184905263ffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063a72aa27e90604401600060405180830381600087803b1580156131c457600080fd5b505af11580156131d8573d6000803e3d6000fd5b505050600092835250600a602052604090912063ffffffff9091169055565b6013546040517f744bfe610000000000000000000000000000000000000000000000000000000081526004810183905230602482015273ffffffffffffffffffffffffffffffffffffffff9091169063744bfe6190604401600060405180830381600087803b15801561326957600080fd5b505af115801561227a573d6000803e3d6000fd5b6017805461306290615290565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff169063b657bc9c906024016115fe565b8060005b818163ffffffff161015611df8573063af953a4a858563ffffffff851681811061331257613312614e9e565b905060200201356040518263ffffffff1660e01b815260040161333791815260200190565b600060405180830381600087803b15801561335157600080fd5b505af1158015613365573d6000803e3d6000fd5b5050505080806133749061571a565b9150506132e6565b6060600061338a600f613dc8565b90508084106133c5576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826000036133da576133d784826151e9565b92505b60008367ffffffffffffffff8111156133f5576133f56142cb565b60405190808252806020026020018201604052801561341e578160200160208202803683370190505b50905060005b8481101561347057613441613439828861519c565b600f90613dd2565b82828151811061345357613453614e9e565b60209081029190910101528061346881615022565b915050613424565b50949350505050565b6018805461306290615290565b6000613490613ca3565b90508160ff166000036134d1576040513090829085907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4505050565b6040513090829085907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a4505050565b6000828152600c6020908152604080832080548251818502810185019093528083528493849392919083018282801561355d57602002820191906000526020600020905b815481526020019060010190808311613549575b505050505090506116b58185613ab3565b8260005b818110156113a857600086868381811061358e5761358e614e9e565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc82836040516020016135c791815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016135f3929190614eec565b600060405180830381600087803b15801561360d57600080fd5b505af1158015613621573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015613697573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136bb9190615005565b90508060ff166001036138c0577f000000000000000000000000000000000000000000000000000000000000000060ff87161561371557507f00000000000000000000000000000000000000000000000000000000000000005b60003073ffffffffffffffffffffffffffffffffffffffff1663fa333dfb3089858860405160200161374991815260200190565b60405160208183030381529060405261376190615733565b60405160e086901b7fffffffff0000000000000000000000000000000000000000000000000000000016815273ffffffffffffffffffffffffffffffffffffffff909416600485015260ff90921660248401526044830152606482015260006084820181905260a482015260c401600060405180830381865afa1580156137ec573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526138329190810190614f52565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d359061388b9087908590600401614eec565b600060405180830381600087803b1580156138a557600080fd5b505af11580156138b9573d6000803e3d6000fd5b5050505050505b505080806138cd90615022565b915050613572565b8060005b81811015611df85760008484838181106138f5576138f5614e9e565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc828360405160200161392e91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b815260040161395a929190614eec565b600060405180830381600087803b15801561397457600080fd5b505af1158015613988573d6000803e3d6000fd5b5050505050808061399890615022565b9150506138d9565b600c60205281600052604060002081815481106139bc57600080fd5b90600052602060002001600091509150505481565b6139d9613d45565b6139e281613dde565b50565b6011546040517f3f678e11000000000000000000000000000000000000000000000000000000008152600091829173ffffffffffffffffffffffffffffffffffffffff90911690633f678e1190613a40908690600401615775565b6020604051808303816000875af1158015613a5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a8391906151d0565b9050613a90600f82613ed3565b506060909201516000838152600a6020526040902063ffffffff90911690555090565b815160009081908190841580613ac95750808510155b15613ad2578094505b60008092505b85831015613b2e57866001613aed85856151e9565b613af791906151e9565b81518110613b0757613b07614e9e565b602002602001015181613b1a919061519c565b905082613b2681615022565b935050613ad8565b9694955050505050565b82516000908190831580613b4c5750808410155b15613b55578093505b60008467ffffffffffffffff811115613b7057613b706142cb565b604051908082528060200260200182016040528015613b99578160200160208202803683370190505b509050600092505b84831015613c0757866001613bb685856151e9565b613bc091906151e9565b81518110613bd057613bd0614e9e565b6020026020010151818481518110613bea57613bea614e9e565b602090810291909101015282613bff81615022565b935050613ba1565b613c2081600060018451613c1b91906151e9565b613edf565b85606403613c59578060018251613c3791906151e9565b81518110613c4757613c47614e9e565b60200260200101519350505050611c11565b806064825188613c6991906158c7565b613c739190615933565b81518110613c8357613c83614e9e565b602002602001015193505050509392505050565b6000611c118383614057565b60007f000000000000000000000000000000000000000000000000000000000000000015613d4057606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d3b91906151d0565b905090565b504390565b60005473ffffffffffffffffffffffffffffffffffffffff163314613dc6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016126a9565b565b6000611467825490565b6000611c118383614151565b3373ffffffffffffffffffffffffffffffffffffffff821603613e5d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016126a9565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611c11838361417b565b8181808203613eef575050505050565b6000856002613efe8787615947565b613f089190615967565b613f1290876159cf565b81518110613f2257613f22614e9e565b602002602001015190505b818313614031575b80868481518110613f4857613f48614e9e565b60200260200101511015613f685782613f60816159f7565b935050613f35565b858281518110613f7a57613f7a614e9e565b6020026020010151811015613f9b5781613f9381615a28565b925050613f68565b81831361402c57858281518110613fb457613fb4614e9e565b6020026020010151868481518110613fce57613fce614e9e565b6020026020010151878581518110613fe857613fe8614e9e565b6020026020010188858151811061400157614001614e9e565b6020908102919091010191909152528261401a816159f7565b935050818061402890615a28565b9250505b613f2d565b8185121561404457614044868684613edf565b838312156113a8576113a8868486613edf565b6000818152600183016020526040812054801561414057600061407b6001836151e9565b855490915060009061408f906001906151e9565b90508181146140f45760008660000182815481106140af576140af614e9e565b90600052602060002001549050808760000184815481106140d2576140d2614e9e565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061410557614105615a7f565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611467565b6000915050611467565b5092915050565b600082600001828154811061416857614168614e9e565b9060005260206000200154905092915050565b60008181526001830160205260408120546141c257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611467565b506000611467565b50805460008255906000526020600020908101906139e2919061423e565b82805482825590600052602060002090810192821561422e579160200282015b8281111561422e578251829061421e908261556f565b5091602001919060010190614208565b5061423a929150614253565b5090565b5b8082111561423a576000815560010161423f565b8082111561423a5760006142678282614270565b50600101614253565b50805461427c90615290565b6000825580601f1061428c575050565b601f0160209004906000526020600020908101906139e2919061423e565b60ff811681146139e257600080fd5b63ffffffff811681146139e257600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610140810167ffffffffffffffff8111828210171561431e5761431e6142cb565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561436b5761436b6142cb565b604052919050565b600067ffffffffffffffff82111561438d5761438d6142cb565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f8301126143ca57600080fd5b81356143dd6143d882614373565b614324565b8181528460208386010111156143f257600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff811681146139e257600080fd5b600080600080600080600060e0888a03121561444457600080fd5b873561444f816142aa565b9650602088013561445f816142b9565b9550604088013561446f816142aa565b9450606088013567ffffffffffffffff81111561448b57600080fd5b6144978a828b016143b9565b94505060808801356144a88161440f565b9699959850939692959460a0840135945060c09093013592915050565b803561ffff811681146144d757600080fd5b919050565b6000806000606084860312156144f157600080fd5b83359250614501602085016144c5565b9150604084013590509250925092565b6000806040838503121561452457600080fd5b82359150602083013567ffffffffffffffff81111561454257600080fd5b61454e858286016143b9565b9150509250929050565b60006020828403121561456a57600080fd5b5035919050565b60005b8381101561458c578181015183820152602001614574565b50506000910152565b600081518084526145ad816020860160208601614571565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611c116020830184614595565b73ffffffffffffffffffffffffffffffffffffffff811681146139e257600080fd5b600080600080600080600060e0888a03121561462f57600080fd5b873596506020880135614641816145f2565b95506040880135614651816142aa565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b6000806040838503121561468c57600080fd5b8235915061469c602084016144c5565b90509250929050565b6000602082840312156146b757600080fd5b8135611c11816145f2565b60008083601f8401126146d457600080fd5b50813567ffffffffffffffff8111156146ec57600080fd5b6020830191508360208260051b85010111156116bb57600080fd5b600080600080600080600060c0888a03121561472257600080fd5b873567ffffffffffffffff81111561473957600080fd5b6147458a828b016146c2565b9098509650506020880135614759816142aa565b96999598509596604081013596506060810135956080820135955060a0909101359350915050565b60008060006060848603121561479657600080fd5b505081359360208301359350604090920135919050565b602081526147d460208201835173ffffffffffffffffffffffffffffffffffffffff169052565b600060208301516147ed604084018263ffffffff169052565b50604083015161014080606085015261480a610160850183614595565b9150606085015161482b60808601826bffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015163ffffffff811660e08601525060e0850151610100614897818701836bffffffffffffffffffffffff169052565b86015190506101206148ac8682018315159052565b8601518584037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018387015290506148e48382614595565b9695505050505050565b6000806020838503121561490157600080fd5b823567ffffffffffffffff81111561491857600080fd5b614924858286016146c2565b90969095509350505050565b60008083601f84011261494257600080fd5b50813567ffffffffffffffff81111561495a57600080fd5b6020830191508360208285010111156116bb57600080fd5b6000806020838503121561498557600080fd5b823567ffffffffffffffff81111561499c57600080fd5b61492485828601614930565b6020808252825182820181905260009190848201906040850190845b818110156149e0578351835292840192918401916001016149c4565b50909695505050505050565b600067ffffffffffffffff821115614a0657614a066142cb565b5060051b60200190565b60008060408385031215614a2357600080fd5b823567ffffffffffffffff80821115614a3b57600080fd5b818501915085601f830112614a4f57600080fd5b81356020614a5f6143d8836149ec565b82815260059290921b84018101918181019089841115614a7e57600080fd5b8286015b84811015614ab657803586811115614a9a5760008081fd5b614aa88c86838b01016143b9565b845250918301918301614a82565b5096505086013592505080821115614acd57600080fd5b5061454e858286016143b9565b8215158152604060208201526000611c0e6040830184614595565b600080600060408486031215614b0a57600080fd5b833567ffffffffffffffff811115614b2157600080fd5b614b2d868287016146c2565b9094509250506020840135614b41816142b9565b809150509250925092565b60008060408385031215614b5f57600080fd5b50508035926020909101359150565b600080600060408486031215614b8357600080fd5b83359250602084013567ffffffffffffffff811115614ba157600080fd5b614bad86828701614930565b9497909650939450505050565b60008060408385031215614bcd57600080fd5b823567ffffffffffffffff80821115614be557600080fd5b614bf1868387016143b9565b93506020850135915080821115614acd57600080fd5b60006020808385031215614c1a57600080fd5b823567ffffffffffffffff80821115614c3257600080fd5b818501915085601f830112614c4657600080fd5b8135614c546143d8826149ec565b81815260059190911b83018401908481019088831115614c7357600080fd5b8585015b83811015614cab57803585811115614c8f5760008081fd5b614c9d8b89838a01016143b9565b845250918601918601614c77565b5098975050505050505050565b60008060408385031215614ccb57600080fd5b823591506020830135614cdd8161440f565b809150509250929050565b600060208284031215614cfa57600080fd5b8135611c11816142aa565b60008060408385031215614d1857600080fd5b823591506020830135614cdd816142b9565b60008060408385031215614d3d57600080fd5b823591506020830135614cdd816142aa565b60008060008060608587031215614d6557600080fd5b843567ffffffffffffffff811115614d7c57600080fd5b614d88878288016146c2565b9095509350506020850135614d9c816142aa565b91506040850135614dac816142aa565b939692955090935050565b60008060008060008060c08789031215614dd057600080fd5b8635614ddb816145f2565b95506020870135614deb816142aa565b95989597505050506040840135936060810135936080820135935060a0909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006bffffffffffffffffffffffff80831681851681830481118215151615614e6a57614e6a614e10565b02949350505050565b805180151581146144d757600080fd5b600060208284031215614e9557600080fd5b611c1182614e73565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff821660ff8103614ee357614ee3614e10565b60010192915050565b828152604060208201526000611c0e6040830184614595565b600082601f830112614f1657600080fd5b8151614f246143d882614373565b818152846020838601011115614f3957600080fd5b614f4a826020830160208701614571565b949350505050565b600060208284031215614f6457600080fd5b815167ffffffffffffffff811115614f7b57600080fd5b614f4a84828501614f05565b80516144d78161440f565b600060208284031215614fa457600080fd5b8151611c118161440f565b80516144d7816145f2565b60008060408385031215614fcd57600080fd5b8251614fd8816145f2565b6020939093015192949293505050565b600060208284031215614ffa57600080fd5b8151611c11816145f2565b60006020828403121561501757600080fd5b8151611c11816142aa565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361505357615053614e10565b5060010190565b80516144d7816142b9565b805167ffffffffffffffff811681146144d757600080fd5b60006020828403121561508f57600080fd5b815167ffffffffffffffff808211156150a757600080fd5b9083019061014082860312156150bc57600080fd5b6150c46142fa565b6150cd83614faf565b81526150db6020840161505a565b60208201526040830151828111156150f257600080fd5b6150fe87828601614f05565b60408301525061511060608401614f87565b606082015261512160808401614faf565b608082015261513260a08401615065565b60a082015261514360c0840161505a565b60c082015261515460e08401614f87565b60e0820152610100615167818501614e73565b90820152610120838101518381111561517f57600080fd5b61518b88828701614f05565b918301919091525095945050505050565b8082018082111561146757611467614e10565b600061ffff8083168181036151c6576151c6614e10565b6001019392505050565b6000602082840312156151e257600080fd5b5051919050565b8181038181111561146757611467614e10565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015615271577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa088870301855261525f868351614595565b95509382019390820190600101615225565b5050858403818701525050506152878185614595565b95945050505050565b600181811c908216806152a457607f821691505b6020821081036152dd577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60008083546152f181615290565b60018281168015615309576001811461533c5761536b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008416875282151583028701945061536b565b8760005260208060002060005b858110156153625781548a820152908401908201615349565b50505082870194505b50929695505050505050565b6000815461538481615290565b8085526020600183811680156153a157600181146153d957615407565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b8901019550615407565b866000528260002060005b858110156153ff5781548a82018601529083019084016153e4565b890184019650505b505050505092915050565b60a08152600061542560a0830188615377565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b83811015615497577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030185526154858383615377565b9486019492506001918201910161544c565b505086810360408801526154ab818b615377565b94505050505084606084015282810360808401526154c98185614595565b98975050505050505050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b601f82111561299957600081815260208120601f850160051c810160208610156155505750805b601f850160051c820191505b818110156113a85782815560010161555c565b815167ffffffffffffffff811115615589576155896142cb565b61559d816155978454615290565b84615529565b602080601f8311600181146155f057600084156155ba5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556113a8565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561563d5788860151825594840194600190910190840161561e565b508582101561567957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b6000602080838503121561569c57600080fd5b825167ffffffffffffffff8111156156b357600080fd5b8301601f810185136156c457600080fd5b80516156d26143d8826149ec565b81815260059190911b820183019083810190878311156156f157600080fd5b928401925b8284101561570f578351825292840192908401906156f6565b979650505050505050565b600063ffffffff8083168181036151c6576151c6614e10565b805160208083015191908110156152dd577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b6020815260008251610140806020850152615794610160850183614595565b915060208501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0808685030160408701526157d08483614595565b9350604087015191506157fb606087018373ffffffffffffffffffffffffffffffffffffffff169052565b606087015163ffffffff811660808801529150608087015173ffffffffffffffffffffffffffffffffffffffff811660a0880152915060a087015160ff811660c0880152915060c08701519150808685030160e087015261585c8483614595565b935060e0870151915061010081878603018188015261587b8584614595565b94508088015192505061012081878603018188015261589a8584614595565b945080880151925050506158bd828601826bffffffffffffffffffffffff169052565b5090949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156158ff576158ff614e10565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261594257615942615904565b500490565b818103600083128015838313168383128216171561414a5761414a614e10565b60008261597657615976615904565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f8000000000000000000000000000000000000000000000000000000000000000831416156159ca576159ca614e10565b500590565b80820182811260008312801582168215821617156159ef576159ef614e10565b505092915050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361505357615053614e10565b60007f80000000000000000000000000000000000000000000000000000000000000008203615a5957615a59614e10565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", } var VerifiableLoadStreamsLookupUpkeepABI = VerifiableLoadStreamsLookupUpkeepMetaData.ABI diff --git a/core/gethwrappers/generated/vrf_coordinator_v2/vrf_coordinator_v2.go b/core/gethwrappers/generated/vrf_coordinator_v2/vrf_coordinator_v2.go index 3c6eff6b6ba..51021b789e7 100644 --- a/core/gethwrappers/generated/vrf_coordinator_v2/vrf_coordinator_v2.go +++ b/core/gethwrappers/generated/vrf_coordinator_v2/vrf_coordinator_v2.go @@ -64,7 +64,7 @@ type VRFProof struct { var VRFCoordinatorV2MetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"blockhashStore\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkEthFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"internalBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"externalBalance\",\"type\":\"uint256\"}],\"name\":\"BalanceInvariantViolated\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"BlockhashNotInStore\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"have\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"want\",\"type\":\"uint256\"}],\"name\":\"InsufficientGasForConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"have\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"min\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"max\",\"type\":\"uint16\"}],\"name\":\"InvalidRequestConfirmations\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeRequestedOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoCorrespondingRequest\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"NoSuchProvingKey\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"NumWordsTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PendingRequestExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"ProvingKeyAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Reentrant\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier1\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier2\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier3\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier4\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier5\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier2\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier3\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier4\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier5\",\"type\":\"uint24\"}],\"indexed\":false,\"internalType\":\"structVRFCoordinatorV2.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"name\":\"ProvingKeyDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"name\":\"ProvingKeyRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"RandomWordsFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"preSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RandomWordsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BLOCKHASH_STORE\",\"outputs\":[{\"internalType\":\"contractBlockhashStoreInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_ETH_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CONSUMERS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_NUM_WORDS\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_REQUEST_CONFIRMATIONS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"deregisterProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"pk\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"gamma\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"s\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"uWitness\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"cGammaWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"sHashWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"zInv\",\"type\":\"uint256\"}],\"internalType\":\"structVRF.Proof\",\"name\":\"proof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"internalType\":\"structVRFCoordinatorV2.RequestCommitment\",\"name\":\"rc\",\"type\":\"tuple\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"name\":\"getCommitment\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentSubId\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFallbackWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFeeConfig\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier1\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier2\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier3\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier4\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier5\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier2\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier3\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier4\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier5\",\"type\":\"uint24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"}],\"name\":\"getFeeTier\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRequestConfig\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"}],\"name\":\"getSubscription\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTotalBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicKey\",\"type\":\"uint256[2]\"}],\"name\":\"hashOfKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"registerProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"requestSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier1\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier2\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier3\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier4\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier5\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier2\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier3\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier4\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier5\",\"type\":\"uint24\"}],\"internalType\":\"structVRFCoordinatorV2.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", - Bin: "0x60e06040523480156200001157600080fd5b50604051620059b4380380620059b48339810160408190526200003491620001b1565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000e8565b5050506001600160601b0319606093841b811660805290831b811660a052911b1660c052620001fb565b6001600160a01b038116331415620001435760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001ac57600080fd5b919050565b600080600060608486031215620001c757600080fd5b620001d28462000194565b9250620001e26020850162000194565b9150620001f26040850162000194565b90509250925092565b60805160601c60a05160601c60c05160601c61574f620002656000396000818161051901526138f00152600081816106030152613dfb01526000818161036d015281816114da0152818161237701528181612dae01528181612eea015261350f015261574f6000f3fe608060405234801561001057600080fd5b506004361061025b5760003560e01c80636f64f03f11610145578063ad178361116100bd578063d2f9f9a71161008c578063e72f6e3011610071578063e72f6e30146106e0578063e82ad7d4146106f3578063f2fde38b1461071657600080fd5b8063d2f9f9a7146106ba578063d7ae1d30146106cd57600080fd5b8063ad178361146105fe578063af198b9714610625578063c3f909d414610655578063caf70c4a146106a757600080fd5b80638da5cb5b11610114578063a21a23e4116100f9578063a21a23e4146105c0578063a47c7696146105c8578063a4c0ed36146105eb57600080fd5b80638da5cb5b1461059c5780639f87fad7146105ad57600080fd5b80636f64f03f1461055b5780637341c10c1461056e57806379ba509714610581578063823597401461058957600080fd5b8063356dac71116101d85780635fbbc0d2116101a757806366316d8d1161018c57806366316d8d14610501578063689c45171461051457806369bcdb7d1461053b57600080fd5b80635fbbc0d2146103f357806364d51a2a146104f957600080fd5b8063356dac71146103a757806340d6bb82146103af5780634cb48a54146103cd5780635d3b1d30146103e057600080fd5b806308821d581161022f57806315c48b841161021457806315c48b841461030e578063181f5a77146103295780631b6b6d231461036857600080fd5b806308821d58146102cf57806312b58349146102e257600080fd5b80620122911461026057806302bcc5b61461028057806304c357cb1461029557806306bfa637146102a8575b600080fd5b610268610729565b60405161027793929190615299565b60405180910390f35b61029361028e3660046150e5565b6107a5565b005b6102936102a3366004615100565b610837565b60055467ffffffffffffffff165b60405167ffffffffffffffff9091168152602001610277565b6102936102dd366004614df6565b6109eb565b6005546801000000000000000090046bffffffffffffffffffffffff165b604051908152602001610277565b61031660c881565b60405161ffff9091168152602001610277565b604080518082018252601681527f565246436f6f7264696e61746f72563220312e302e3000000000000000000000602082015290516102779190615244565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610277565b600a54610300565b6103b86101f481565b60405163ffffffff9091168152602001610277565b6102936103db366004614f8f565b610bb0565b6103006103ee366004614e69565b610fa7565b600c546040805163ffffffff80841682526401000000008404811660208301526801000000000000000084048116928201929092526c010000000000000000000000008304821660608201527001000000000000000000000000000000008304909116608082015262ffffff740100000000000000000000000000000000000000008304811660a0830152770100000000000000000000000000000000000000000000008304811660c08301527a0100000000000000000000000000000000000000000000000000008304811660e08301527d01000000000000000000000000000000000000000000000000000000000090920490911661010082015261012001610277565b610316606481565b61029361050f366004614dae565b611385565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b6103006105493660046150cc565b60009081526009602052604090205490565b610293610569366004614cf3565b6115d4565b61029361057c366004615100565b611704565b610293611951565b6102936105973660046150e5565b611a1a565b6000546001600160a01b031661038f565b6102936105bb366004615100565b611be0565b6102b661201f565b6105db6105d63660046150e5565b612202565b6040516102779493929190615437565b6102936105f9366004614d27565b612325565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b610638610633366004614ec7565b61257c565b6040516bffffffffffffffffffffffff9091168152602001610277565b600b546040805161ffff8316815263ffffffff6201000084048116602083015267010000000000000084048116928201929092526b010000000000000000000000909204166060820152608001610277565b6103006106b5366004614e12565b612a16565b6103b86106c83660046150e5565b612a46565b6102936106db366004615100565b612c3b565b6102936106ee366004614cd8565b612d75565b6107066107013660046150e5565b612fb2565b6040519015158152602001610277565b610293610724366004614cd8565b6131d5565b600b546007805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff1693919283919083018282801561079357602002820191906000526020600020905b81548152602001906001019080831161077f575b50505050509050925092509250909192565b6107ad6131e6565b67ffffffffffffffff81166000908152600360205260409020546001600160a01b0316610806576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020546108349082906001600160a01b0316613242565b50565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680610893576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b038216146108e5576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024015b60405180910390fd5b600b546601000000000000900460ff161561092c576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff84166000908152600360205260409020600101546001600160a01b038481169116146109e55767ffffffffffffffff841660008181526003602090815260409182902060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0388169081179091558251338152918201527f69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be91015b60405180910390a25b50505050565b6109f36131e6565b604080518082018252600091610a22919084906002908390839080828437600092019190915250612a16915050565b6000818152600660205260409020549091506001600160a01b031680610a77576040517f77f5b84c000000000000000000000000000000000000000000000000000000008152600481018390526024016108dc565b600082815260066020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b600754811015610b67578260078281548110610aca57610aca6156e4565b90600052602060002001541415610b55576007805460009190610aef9060019061559e565b81548110610aff57610aff6156e4565b906000526020600020015490508060078381548110610b2057610b206156e4565b6000918252602090912001556007805480610b3d57610b3d6156b5565b60019003818190600052602060002001600090559055505b80610b5f816155e2565b915050610aac565b50806001600160a01b03167f72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d83604051610ba391815260200190565b60405180910390a2505050565b610bb86131e6565b60c861ffff87161115610c0b576040517fa738697600000000000000000000000000000000000000000000000000000000815261ffff871660048201819052602482015260c860448201526064016108dc565b60008213610c48576040517f43d4cf66000000000000000000000000000000000000000000000000000000008152600481018390526024016108dc565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000001690971762010000909502949094177fffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff166701000000000000009092027fffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffff16919091176b010000000000000000000000909302929092179093558651600c80549489015189890151938a0151978a0151968a015160c08b015160e08c01516101008d01519588167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009099169890981764010000000093881693909302929092177fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff1668010000000000000000958716959095027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff16949094176c0100000000000000000000000098861698909802979097177fffffffffffffffffff00000000000000ffffffffffffffffffffffffffffffff1670010000000000000000000000000000000096909416959095027fffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffff16929092177401000000000000000000000000000000000000000062ffffff92831602177fffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffff1677010000000000000000000000000000000000000000000000958216959095027fffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffff16949094177a01000000000000000000000000000000000000000000000000000092851692909202919091177cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d0100000000000000000000000000000000000000000000000000000000009390911692909202919091178155600a84905590517fc21e3bd2e0b339d2848f0dd956947a88966c242c0c0c582a33137a5c1ceb5cb291610f979189918991899189918991906152f8565b60405180910390a1505050505050565b600b546000906601000000000000900460ff1615610ff1576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff85166000908152600360205260409020546001600160a01b031661104a576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260026020908152604080832067ffffffffffffffff808a16855292529091205416806110ba576040517ff0019fe600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff871660048201523360248201526044016108dc565b600b5461ffff90811690861610806110d6575060c861ffff8616115b1561112657600b546040517fa738697600000000000000000000000000000000000000000000000000000000815261ffff8088166004830152909116602482015260c860448201526064016108dc565b600b5463ffffffff620100009091048116908516111561118d57600b546040517ff5d7e01e00000000000000000000000000000000000000000000000000000000815263ffffffff80871660048301526201000090920490911660248201526044016108dc565b6101f463ffffffff841611156111df576040517f47386bec00000000000000000000000000000000000000000000000000000000815263ffffffff841660048201526101f460248201526044016108dc565b60006111ec8260016154fa565b6040805160208082018c9052338284015267ffffffffffffffff808c16606084015284166080808401919091528351808403909101815260a08301845280519082012060c083018d905260e080840182905284518085039091018152610100909301909352815191012091925081611262613667565b60408051602081019390935282015267ffffffffffffffff8a16606082015263ffffffff8089166080830152871660a08201523360c082015260e00160408051808303601f19018152828252805160209182012060008681526009835283902055848352820183905261ffff8a169082015263ffffffff808916606083015287166080820152339067ffffffffffffffff8b16908c907f63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a97729060a00160405180910390a45033600090815260026020908152604080832067ffffffffffffffff808d16855292529091208054919093167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009091161790915591505095945050505050565b600b546601000000000000900460ff16156113cc576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600860205260409020546bffffffffffffffffffffffff80831691161015611426576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260086020526040812080548392906114539084906bffffffffffffffffffffffff166155b5565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080600560088282829054906101000a90046bffffffffffffffffffffffff166114aa91906155b5565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb83836040518363ffffffff1660e01b81526004016115489291906001600160a01b039290921682526bffffffffffffffffffffffff16602082015260400190565b602060405180830381600087803b15801561156257600080fd5b505af1158015611576573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159a9190614e2e565b6115d0576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b6115dc6131e6565b60408051808201825260009161160b919084906002908390839080828437600092019190915250612a16915050565b6000818152600660205260409020549091506001600160a01b031615611660576040517f4a0b8fa7000000000000000000000000000000000000000000000000000000008152600481018290526024016108dc565b600081815260066020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0388169081179091556007805460018101825594527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b89101610ba3565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680611760576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b038216146117ad576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff16156117f4576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff84166000908152600360205260409020600201546064141561184b576040517f05a48e0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316600090815260026020908152604080832067ffffffffffffffff80891685529252909120541615611885576109e5565b6001600160a01b038316600081815260026020818152604080842067ffffffffffffffff8a1680865290835281852080547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001908117909155600384528286209094018054948501815585529382902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001685179055905192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e091016109dc565b6001546001600160a01b031633146119ab5760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016108dc565b60008054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600b546601000000000000900460ff1615611a61576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020546001600160a01b0316611aba576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020600101546001600160a01b03163314611b425767ffffffffffffffff8116600090815260036020526040908190206001015490517fd084e9750000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016108dc565b67ffffffffffffffff81166000818152600360209081526040918290208054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001909301805490931690925583516001600160a01b03909116808252928101919091529092917f6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f0910160405180910390a25050565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680611c3c576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b03821614611c89576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff1615611cd0576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611cd984612fb2565b15611d10576040517fb42f66e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316600090815260026020908152604080832067ffffffffffffffff808916855292529091205416611d91576040517ff0019fe600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff851660048201526001600160a01b03841660248201526044016108dc565b67ffffffffffffffff8416600090815260036020908152604080832060020180548251818502810185019093528083529192909190830182828015611dff57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611de1575b50505050509050600060018251611e16919061559e565b905060005b8251811015611f8e57856001600160a01b0316838281518110611e4057611e406156e4565b60200260200101516001600160a01b03161415611f7c576000838381518110611e6b57611e6b6156e4565b6020026020010151905080600360008a67ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000206002018381548110611eb157611eb16156e4565b600091825260208083209190910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03949094169390931790925567ffffffffffffffff8a168152600390915260409020600201805480611f1e57611f1e6156b5565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611f8e565b80611f86816155e2565b915050611e1b565b506001600160a01b038516600081815260026020908152604080832067ffffffffffffffff8b168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690555192835290917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b91015b60405180910390a2505050505050565b600b546000906601000000000000900460ff1615612069576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805467ffffffffffffffff169060006120838361561b565b82546101009290920a67ffffffffffffffff8181021990931691831602179091556005541690506000806040519080825280602002602001820160405280156120d6578160200160208202803683370190505b506040805180820182526000808252602080830182815267ffffffffffffffff888116808552600484528685209551865493516bffffffffffffffffffffffff9091167fffffffffffffffffffffffff0000000000000000000000000000000000000000948516176c01000000000000000000000000919093160291909117909455845160608101865233815280830184815281870188815295855260038452959093208351815483166001600160a01b03918216178255955160018201805490931696169590951790559151805194955090936121ba9260028501920190614a32565b505060405133815267ffffffffffffffff841691507f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf9060200160405180910390a250905090565b67ffffffffffffffff8116600090815260036020526040812054819081906060906001600160a01b0316612262576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff80861660009081526004602090815260408083205460038352928190208054600290910180548351818602810186019094528084526bffffffffffffffffffffffff8616966c01000000000000000000000000909604909516946001600160a01b0390921693909291839183018282801561230f57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116122f1575b5050505050905093509350935093509193509193565b600b546601000000000000900460ff161561236c576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146123ce576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208114612408576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612416828401846150e5565b67ffffffffffffffff81166000908152600360205260409020549091506001600160a01b0316612472576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8116600090815260046020526040812080546bffffffffffffffffffffffff16918691906124a98385615526565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555084600560088282829054906101000a90046bffffffffffffffffffffffff166125009190615526565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508167ffffffffffffffff167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f882878461256791906154e2565b6040805192835260208301919091520161200f565b600b546000906601000000000000900460ff16156125c6576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005a905060008060006125da8787613700565b9250925092506000866060015163ffffffff1667ffffffffffffffff81111561260557612605615713565b60405190808252806020026020018201604052801561262e578160200160208202803683370190505b50905060005b876060015163ffffffff168110156126a25760408051602081018590529081018290526060016040516020818303038152906040528051906020012060001c828281518110612685576126856156e4565b60209081029190910101528061269a816155e2565b915050612634565b506000838152600960205260408082208290555181907f1fe543e300000000000000000000000000000000000000000000000000000000906126ea90879086906024016153e9565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252600b80547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff166601000000000000179055908a015160808b015191925060009161279a9163ffffffff169084613a0e565b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff1690556020808c01805167ffffffffffffffff9081166000908152600490935260408084205492518216845290922080549394506c01000000000000000000000000918290048316936001939192600c9261281e9286929004166154fa565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060006128758a600b600001600b9054906101000a900463ffffffff1663ffffffff1661286f85612a46565b3a613a5c565b6020808e015167ffffffffffffffff166000908152600490915260409020549091506bffffffffffffffffffffffff808316911610156128e1576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808d015167ffffffffffffffff166000908152600490915260408120805483929061291d9084906bffffffffffffffffffffffff166155b5565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008b8152600660209081526040808320546001600160a01b03168352600890915281208054859450909261297991859116615526565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550877f7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e48883866040516129fc939291909283526bffffffffffffffffffffffff9190911660208301521515604082015260600190565b60405180910390a299505050505050505050505b92915050565b600081604051602001612a299190615236565b604051602081830303815290604052805190602001209050919050565b6040805161012081018252600c5463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c010000000000000000000000008104831660608301527001000000000000000000000000000000008104909216608082015262ffffff740100000000000000000000000000000000000000008304811660a08301819052770100000000000000000000000000000000000000000000008404821660c08401527a0100000000000000000000000000000000000000000000000000008404821660e08401527d0100000000000000000000000000000000000000000000000000000000009093041661010082015260009167ffffffffffffffff841611612b64575192915050565b8267ffffffffffffffff168160a0015162ffffff16108015612b9957508060c0015162ffffff168367ffffffffffffffff1611155b15612ba8576020015192915050565b8267ffffffffffffffff168160c0015162ffffff16108015612bdd57508060e0015162ffffff168367ffffffffffffffff1611155b15612bec576040015192915050565b8267ffffffffffffffff168160e0015162ffffff16108015612c22575080610100015162ffffff168367ffffffffffffffff1611155b15612c31576060015192915050565b6080015192915050565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680612c97576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b03821614612ce4576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff1615612d2b576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612d3484612fb2565b15612d6b576040517fb42f66e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109e58484613242565b612d7d6131e6565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612df857600080fd5b505afa158015612e0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e309190614e50565b6005549091506801000000000000000090046bffffffffffffffffffffffff1681811115612e94576040517fa99da30200000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016108dc565b81811015612fad576000612ea8828461559e565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152602482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb90604401602060405180830381600087803b158015612f3057600080fd5b505af1158015612f44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f689190614e2e565b50604080516001600160a01b0386168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a1505b505050565b67ffffffffffffffff81166000908152600360209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561304757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613029575b505050505081525050905060005b8160400151518110156131cb5760005b6007548110156131b857600061318160078381548110613087576130876156e4565b9060005260206000200154856040015185815181106130a8576130a86156e4565b60200260200101518860026000896040015189815181106130cb576130cb6156e4565b6020908102919091018101516001600160a01b03168252818101929092526040908101600090812067ffffffffffffffff808f16835293522054166040805160208082018790526001600160a01b03959095168183015267ffffffffffffffff9384166060820152919092166080808301919091528251808303909101815260a08201835280519084012060c082019490945260e080820185905282518083039091018152610100909101909152805191012091565b50600081815260096020526040902054909150156131a55750600195945050505050565b50806131b0816155e2565b915050613065565b50806131c3816155e2565b915050613055565b5060009392505050565b6131dd6131e6565b61083481613b7c565b6000546001600160a01b031633146132405760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016108dc565b565b600b546601000000000000900460ff1615613289576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff82166000908152600360209081526040808320815160608101835281546001600160a01b0390811682526001830154168185015260028201805484518187028101870186528181529295939486019383018282801561331a57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116132fc575b5050509190925250505067ffffffffffffffff80851660009081526004602090815260408083208151808301909252546bffffffffffffffffffffffff81168083526c01000000000000000000000000909104909416918101919091529293505b8360400151518110156134145760026000856040015183815181106133a2576133a26156e4565b6020908102919091018101516001600160a01b03168252818101929092526040908101600090812067ffffffffffffffff8a168252909252902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690558061340c816155e2565b91505061337b565b5067ffffffffffffffff8516600090815260036020526040812080547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116825560018201805490911690559061346f6002830182614aaf565b505067ffffffffffffffff8516600090815260046020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600580548291906008906134df9084906801000000000000000090046bffffffffffffffffffffffff166155b5565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb85836bffffffffffffffffffffffff166040518363ffffffff1660e01b815260040161357d9291906001600160a01b03929092168252602082015260400190565b602060405180830381600087803b15801561359757600080fd5b505af11580156135ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135cf9190614e2e565b613605576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516001600160a01b03861681526bffffffffffffffffffffffff8316602082015267ffffffffffffffff8716917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815910160405180910390a25050505050565b60004661a4b181148061367c575062066eed81145b156136f95760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156136bb57600080fd5b505afa1580156136cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136f39190614e50565b91505090565b4391505090565b60008060006137128560000151612a16565b6000818152600660205260409020549093506001600160a01b031680613767576040517f77f5b84c000000000000000000000000000000000000000000000000000000008152600481018590526024016108dc565b6080860151604051613786918691602001918252602082015260400190565b60408051601f19818403018152918152815160209283012060008181526009909352912054909350806137e5576040517f3688124a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85516020808801516040808a015160608b015160808c01519251613851968b96909594910195865267ffffffffffffffff948516602087015292909316604085015263ffffffff90811660608501529190911660808301526001600160a01b031660a082015260c00190565b60405160208183030381529060405280519060200120811461389f576040517fd529142c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006138ae8760000151613c3e565b9050806139ba5786516040517fe9413d3800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e9413d389060240160206040518083038186803b15801561393a57600080fd5b505afa15801561394e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139729190614e50565b9050806139ba5786516040517f175dadad00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016108dc565b60008860800151826040516020016139dc929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c9050613a018982613d45565b9450505050509250925092565b60005a611388811015613a2057600080fd5b611388810390508460408204820311613a3857600080fd5b50823b613a4457600080fd5b60008083516020850160008789f190505b9392505050565b600080613a67613db0565b905060008113613aa6576040517f43d4cf66000000000000000000000000000000000000000000000000000000008152600481018290526024016108dc565b6000613ab0613eb7565b9050600082825a613ac18b8b6154e2565b613acb919061559e565b613ad59088615561565b613adf91906154e2565b613af190670de0b6b3a7640000615561565b613afb919061554d565b90506000613b1463ffffffff881664e8d4a51000615561565b9050613b2c816b033b2e3c9fd0803ce800000061559e565b821115613b65576040517fe80fa38100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613b6f81836154e2565b9998505050505050505050565b6001600160a01b038116331415613bd55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016108dc565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60004661a4b1811480613c53575062066eed81145b15613d35576101008367ffffffffffffffff16613c6e613667565b613c78919061559e565b1180613c955750613c87613667565b8367ffffffffffffffff1610155b15613ca35750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152606490632b407a829060240160206040518083038186803b158015613cfd57600080fd5b505afa158015613d11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a559190614e50565b505067ffffffffffffffff164090565b6000613d798360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151613f13565b60038360200151604051602001613d919291906153d5565b60408051601f1981840301815291905280516020909101209392505050565b600b54604080517ffeaf968c0000000000000000000000000000000000000000000000000000000081529051600092670100000000000000900463ffffffff169182151591849182917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b158015613e4957600080fd5b505afa158015613e5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e81919061512a565b509450909250849150508015613ea55750613e9c824261559e565b8463ffffffff16105b15613eaf5750600a545b949350505050565b60004661a4b1811480613ecc575062066eed81145b15613f0b57606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156136bb57600080fd5b600091505090565b613f1c8961414e565b613f685760405162461bcd60e51b815260206004820152601a60248201527f7075626c6963206b6579206973206e6f74206f6e20637572766500000000000060448201526064016108dc565b613f718861414e565b613fbd5760405162461bcd60e51b815260206004820152601560248201527f67616d6d61206973206e6f74206f6e206375727665000000000000000000000060448201526064016108dc565b613fc68361414e565b6140125760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e20637572766500000060448201526064016108dc565b61401b8261414e565b6140675760405162461bcd60e51b815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e2063757276650000000060448201526064016108dc565b614073878a8887614227565b6140bf5760405162461bcd60e51b815260206004820152601960248201527f6164647228632a706b2b732a6729213d5f755769746e6573730000000000000060448201526064016108dc565b60006140cb8a87614378565b905060006140de898b878b8689896143dc565b905060006140ef838d8d8a86614508565b9050808a146141405760405162461bcd60e51b815260206004820152600d60248201527f696e76616c69642070726f6f660000000000000000000000000000000000000060448201526064016108dc565b505050505050505050505050565b80516000906401000003d019116141a75760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420782d6f7264696e617465000000000000000000000000000060448201526064016108dc565b60208201516401000003d019116142005760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420792d6f7264696e617465000000000000000000000000000060448201526064016108dc565b60208201516401000003d0199080096142208360005b6020020151614548565b1492915050565b60006001600160a01b03821661427f5760405162461bcd60e51b815260206004820152600b60248201527f626164207769746e65737300000000000000000000000000000000000000000060448201526064016108dc565b60208401516000906001161561429657601c614299565b601b5b905060007ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418587600060200201510986517ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa158015614350573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b614380614acd565b6143ad6001848460405160200161439993929190615215565b60405160208183030381529060405261456c565b90505b6143b98161414e565b612a105780516040805160208101929092526143d59101614399565b90506143b0565b6143e4614acd565b825186516401000003d01990819006910614156144435760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e6374000060448201526064016108dc565b61444e8789886145bb565b61449a5760405162461bcd60e51b815260206004820152601660248201527f4669727374206d756c20636865636b206661696c65640000000000000000000060448201526064016108dc565b6144a58486856145bb565b6144f15760405162461bcd60e51b815260206004820152601760248201527f5365636f6e64206d756c20636865636b206661696c656400000000000000000060448201526064016108dc565b6144fc868484614703565b98975050505050505050565b600060028686868587604051602001614526969594939291906151a3565b60408051601f1981840301815291905280516020909101209695505050505050565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614574614acd565b61457d826147ca565b815261459261458d826000614216565b614805565b6020820181905260029006600114156145b6576020810180516401000003d0190390525b919050565b60008261460a5760405162461bcd60e51b815260206004820152600b60248201527f7a65726f207363616c617200000000000000000000000000000000000000000060448201526064016108dc565b8351602085015160009061462090600290615643565b1561462c57601c61462f565b601b5b905060007ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa1580156146af573d6000803e3d6000fd5b5050506020604051035190506000866040516020016146ce9190615191565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b61470b614acd565b83516020808601518551918601516000938493849361472c93909190614825565b919450925090506401000003d01985820960011461478c5760405162461bcd60e51b815260206004820152601960248201527f696e765a206d75737420626520696e7665727365206f66207a0000000000000060448201526064016108dc565b60405180604001604052806401000003d019806147ab576147ab615686565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d01981106145b6576040805160208082019390935281518082038401815290820190915280519101206147d2565b6000612a1082600261481e6401000003d01960016154e2565b901c614905565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614865838385856149c5565b909850905061487688828e886149e9565b909850905061488788828c876149e9565b9098509050600061489a8d878b856149e9565b90985090506148ab888286866149c5565b90985090506148bc88828e896149e9565b90985090508181146148f1576401000003d019818a0998506401000003d01982890997506401000003d01981830996506148f5565b8196505b5050505050509450945094915050565b600080614910614aeb565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a0820152614942614b09565b60208160c08460057ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa9250826149bb5760405162461bcd60e51b815260206004820152601260248201527f6269674d6f64457870206661696c75726521000000000000000000000000000060448201526064016108dc565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b828054828255906000526020600020908101928215614a9f579160200282015b82811115614a9f57825182547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909116178255602090920191600190910190614a52565b50614aab929150614b27565b5090565b50805460008255906000526020600020908101906108349190614b27565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b80821115614aab5760008155600101614b28565b80356001600160a01b03811681146145b657600080fd5b8060408101831015612a1057600080fd5b600082601f830112614b7557600080fd5b6040516040810181811067ffffffffffffffff82111715614b9857614b98615713565b8060405250808385604086011115614baf57600080fd5b60005b6002811015614bd1578135835260209283019290910190600101614bb2565b509195945050505050565b600060a08284031215614bee57600080fd5b60405160a0810181811067ffffffffffffffff82111715614c1157614c11615713565b604052905080614c2083614ca6565b8152614c2e60208401614ca6565b6020820152614c3f60408401614c92565b6040820152614c5060608401614c92565b6060820152614c6160808401614b3c565b60808201525092915050565b803561ffff811681146145b657600080fd5b803562ffffff811681146145b657600080fd5b803563ffffffff811681146145b657600080fd5b803567ffffffffffffffff811681146145b657600080fd5b805169ffffffffffffffffffff811681146145b657600080fd5b600060208284031215614cea57600080fd5b613a5582614b3c565b60008060608385031215614d0657600080fd5b614d0f83614b3c565b9150614d1e8460208501614b53565b90509250929050565b60008060008060608587031215614d3d57600080fd5b614d4685614b3c565b935060208501359250604085013567ffffffffffffffff80821115614d6a57600080fd5b818701915087601f830112614d7e57600080fd5b813581811115614d8d57600080fd5b886020828501011115614d9f57600080fd5b95989497505060200194505050565b60008060408385031215614dc157600080fd5b614dca83614b3c565b915060208301356bffffffffffffffffffffffff81168114614deb57600080fd5b809150509250929050565b600060408284031215614e0857600080fd5b613a558383614b53565b600060408284031215614e2457600080fd5b613a558383614b64565b600060208284031215614e4057600080fd5b81518015158114613a5557600080fd5b600060208284031215614e6257600080fd5b5051919050565b600080600080600060a08688031215614e8157600080fd5b85359450614e9160208701614ca6565b9350614e9f60408701614c6d565b9250614ead60608701614c92565b9150614ebb60808701614c92565b90509295509295909350565b600080828403610240811215614edc57600080fd5b6101a080821215614eec57600080fd5b614ef46154b8565b9150614f008686614b64565b8252614f0f8660408701614b64565b60208301526080850135604083015260a0850135606083015260c08501356080830152614f3e60e08601614b3c565b60a0830152610100614f5287828801614b64565b60c0840152614f65876101408801614b64565b60e08401526101808601358184015250819350614f8486828701614bdc565b925050509250929050565b6000806000806000808688036101c0811215614faa57600080fd5b614fb388614c6d565b9650614fc160208901614c92565b9550614fcf60408901614c92565b9450614fdd60608901614c92565b935060808801359250610120807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608301121561501857600080fd5b6150206154b8565b915061502e60a08a01614c92565b825261503c60c08a01614c92565b602083015261504d60e08a01614c92565b6040830152610100615060818b01614c92565b6060840152615070828b01614c92565b60808401526150826101408b01614c7f565b60a08401526150946101608b01614c7f565b60c08401526150a66101808b01614c7f565b60e08401526150b86101a08b01614c7f565b818401525050809150509295509295509295565b6000602082840312156150de57600080fd5b5035919050565b6000602082840312156150f757600080fd5b613a5582614ca6565b6000806040838503121561511357600080fd5b61511c83614ca6565b9150614d1e60208401614b3c565b600080600080600060a0868803121561514257600080fd5b61514b86614cbe565b9450602086015193506040860151925060608601519150614ebb60808701614cbe565b8060005b60028110156109e5578151845260209384019390910190600101615172565b61519b818361516e565b604001919050565b8681526151b3602082018761516e565b6151c0606082018661516e565b6151cd60a082018561516e565b6151da60e082018461516e565b60609190911b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166101208201526101340195945050505050565b838152615225602082018461516e565b606081019190915260800192915050565b60408101612a10828461516e565b600060208083528351808285015260005b8181101561527157858101830151858201604001528201615255565b81811115615283576000604083870101525b50601f01601f1916929092016040019392505050565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b818110156152ea578451835293830193918301916001016152ce565b509098975050505050505050565b60006101c08201905061ffff8816825263ffffffff808816602084015280871660408401528086166060840152846080840152835481811660a085015261534c60c08501838360201c1663ffffffff169052565b61536360e08501838360401c1663ffffffff169052565b61537b6101008501838360601c1663ffffffff169052565b6153936101208501838360801c1663ffffffff169052565b62ffffff60a082901c811661014086015260b882901c811661016086015260d082901c1661018085015260e81c6101a090930192909252979650505050505050565b82815260608101613a55602083018461516e565b6000604082018483526020604081850152818551808452606086019150828701935060005b8181101561542a5784518352938301939183019160010161540e565b5090979650505050505050565b6000608082016bffffffffffffffffffffffff87168352602067ffffffffffffffff8716818501526001600160a01b0380871660408601526080606086015282865180855260a087019150838801945060005b818110156154a857855184168352948401949184019160010161548a565b50909a9950505050505050505050565b604051610120810167ffffffffffffffff811182821017156154dc576154dc615713565b60405290565b600082198211156154f5576154f5615657565b500190565b600067ffffffffffffffff80831681851680830382111561551d5761551d615657565b01949350505050565b60006bffffffffffffffffffffffff80831681851680830382111561551d5761551d615657565b60008261555c5761555c615686565b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561559957615599615657565b500290565b6000828210156155b0576155b0615657565b500390565b60006bffffffffffffffffffffffff838116908316818110156155da576155da615657565b039392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561561457615614615657565b5060010190565b600067ffffffffffffffff8083168181141561563957615639615657565b6001019392505050565b60008261565257615652615686565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x60e06040523480156200001157600080fd5b50604051620059c1380380620059c18339810160408190526200003491620001b1565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000e8565b5050506001600160601b0319606093841b811660805290831b811660a052911b1660c052620001fb565b6001600160a01b038116331415620001435760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001ac57600080fd5b919050565b600080600060608486031215620001c757600080fd5b620001d28462000194565b9250620001e26020850162000194565b9150620001f26040850162000194565b90509250925092565b60805160601c60a05160601c60c05160601c61575c620002656000396000818161051901526138f00152600081816106030152613e0801526000818161036d015281816114da0152818161237701528181612dae01528181612eea015261350f015261575c6000f3fe608060405234801561001057600080fd5b506004361061025b5760003560e01c80636f64f03f11610145578063ad178361116100bd578063d2f9f9a71161008c578063e72f6e3011610071578063e72f6e30146106e0578063e82ad7d4146106f3578063f2fde38b1461071657600080fd5b8063d2f9f9a7146106ba578063d7ae1d30146106cd57600080fd5b8063ad178361146105fe578063af198b9714610625578063c3f909d414610655578063caf70c4a146106a757600080fd5b80638da5cb5b11610114578063a21a23e4116100f9578063a21a23e4146105c0578063a47c7696146105c8578063a4c0ed36146105eb57600080fd5b80638da5cb5b1461059c5780639f87fad7146105ad57600080fd5b80636f64f03f1461055b5780637341c10c1461056e57806379ba509714610581578063823597401461058957600080fd5b8063356dac71116101d85780635fbbc0d2116101a757806366316d8d1161018c57806366316d8d14610501578063689c45171461051457806369bcdb7d1461053b57600080fd5b80635fbbc0d2146103f357806364d51a2a146104f957600080fd5b8063356dac71146103a757806340d6bb82146103af5780634cb48a54146103cd5780635d3b1d30146103e057600080fd5b806308821d581161022f57806315c48b841161021457806315c48b841461030e578063181f5a77146103295780631b6b6d231461036857600080fd5b806308821d58146102cf57806312b58349146102e257600080fd5b80620122911461026057806302bcc5b61461028057806304c357cb1461029557806306bfa637146102a8575b600080fd5b610268610729565b604051610277939291906152a6565b60405180910390f35b61029361028e3660046150f2565b6107a5565b005b6102936102a336600461510d565b610837565b60055467ffffffffffffffff165b60405167ffffffffffffffff9091168152602001610277565b6102936102dd366004614e03565b6109eb565b6005546801000000000000000090046bffffffffffffffffffffffff165b604051908152602001610277565b61031660c881565b60405161ffff9091168152602001610277565b604080518082018252601681527f565246436f6f7264696e61746f72563220312e302e3000000000000000000000602082015290516102779190615251565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610277565b600a54610300565b6103b86101f481565b60405163ffffffff9091168152602001610277565b6102936103db366004614f9c565b610bb0565b6103006103ee366004614e76565b610fa7565b600c546040805163ffffffff80841682526401000000008404811660208301526801000000000000000084048116928201929092526c010000000000000000000000008304821660608201527001000000000000000000000000000000008304909116608082015262ffffff740100000000000000000000000000000000000000008304811660a0830152770100000000000000000000000000000000000000000000008304811660c08301527a0100000000000000000000000000000000000000000000000000008304811660e08301527d01000000000000000000000000000000000000000000000000000000000090920490911661010082015261012001610277565b610316606481565b61029361050f366004614dbb565b611385565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b6103006105493660046150d9565b60009081526009602052604090205490565b610293610569366004614d00565b6115d4565b61029361057c36600461510d565b611704565b610293611951565b6102936105973660046150f2565b611a1a565b6000546001600160a01b031661038f565b6102936105bb36600461510d565b611be0565b6102b661201f565b6105db6105d63660046150f2565b612202565b6040516102779493929190615444565b6102936105f9366004614d34565b612325565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b610638610633366004614ed4565b61257c565b6040516bffffffffffffffffffffffff9091168152602001610277565b600b546040805161ffff8316815263ffffffff6201000084048116602083015267010000000000000084048116928201929092526b010000000000000000000000909204166060820152608001610277565b6103006106b5366004614e1f565b612a16565b6103b86106c83660046150f2565b612a46565b6102936106db36600461510d565b612c3b565b6102936106ee366004614ce5565b612d75565b6107066107013660046150f2565b612fb2565b6040519015158152602001610277565b610293610724366004614ce5565b6131d5565b600b546007805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff1693919283919083018282801561079357602002820191906000526020600020905b81548152602001906001019080831161077f575b50505050509050925092509250909192565b6107ad6131e6565b67ffffffffffffffff81166000908152600360205260409020546001600160a01b0316610806576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020546108349082906001600160a01b0316613242565b50565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680610893576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b038216146108e5576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024015b60405180910390fd5b600b546601000000000000900460ff161561092c576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff84166000908152600360205260409020600101546001600160a01b038481169116146109e55767ffffffffffffffff841660008181526003602090815260409182902060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0388169081179091558251338152918201527f69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be91015b60405180910390a25b50505050565b6109f36131e6565b604080518082018252600091610a22919084906002908390839080828437600092019190915250612a16915050565b6000818152600660205260409020549091506001600160a01b031680610a77576040517f77f5b84c000000000000000000000000000000000000000000000000000000008152600481018390526024016108dc565b600082815260066020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b600754811015610b67578260078281548110610aca57610aca6156f1565b90600052602060002001541415610b55576007805460009190610aef906001906155ab565b81548110610aff57610aff6156f1565b906000526020600020015490508060078381548110610b2057610b206156f1565b6000918252602090912001556007805480610b3d57610b3d6156c2565b60019003818190600052602060002001600090559055505b80610b5f816155ef565b915050610aac565b50806001600160a01b03167f72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d83604051610ba391815260200190565b60405180910390a2505050565b610bb86131e6565b60c861ffff87161115610c0b576040517fa738697600000000000000000000000000000000000000000000000000000000815261ffff871660048201819052602482015260c860448201526064016108dc565b60008213610c48576040517f43d4cf66000000000000000000000000000000000000000000000000000000008152600481018390526024016108dc565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000001690971762010000909502949094177fffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff166701000000000000009092027fffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffff16919091176b010000000000000000000000909302929092179093558651600c80549489015189890151938a0151978a0151968a015160c08b015160e08c01516101008d01519588167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009099169890981764010000000093881693909302929092177fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff1668010000000000000000958716959095027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff16949094176c0100000000000000000000000098861698909802979097177fffffffffffffffffff00000000000000ffffffffffffffffffffffffffffffff1670010000000000000000000000000000000096909416959095027fffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffff16929092177401000000000000000000000000000000000000000062ffffff92831602177fffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffff1677010000000000000000000000000000000000000000000000958216959095027fffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffff16949094177a01000000000000000000000000000000000000000000000000000092851692909202919091177cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d0100000000000000000000000000000000000000000000000000000000009390911692909202919091178155600a84905590517fc21e3bd2e0b339d2848f0dd956947a88966c242c0c0c582a33137a5c1ceb5cb291610f97918991899189918991899190615305565b60405180910390a1505050505050565b600b546000906601000000000000900460ff1615610ff1576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff85166000908152600360205260409020546001600160a01b031661104a576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260026020908152604080832067ffffffffffffffff808a16855292529091205416806110ba576040517ff0019fe600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff871660048201523360248201526044016108dc565b600b5461ffff90811690861610806110d6575060c861ffff8616115b1561112657600b546040517fa738697600000000000000000000000000000000000000000000000000000000815261ffff8088166004830152909116602482015260c860448201526064016108dc565b600b5463ffffffff620100009091048116908516111561118d57600b546040517ff5d7e01e00000000000000000000000000000000000000000000000000000000815263ffffffff80871660048301526201000090920490911660248201526044016108dc565b6101f463ffffffff841611156111df576040517f47386bec00000000000000000000000000000000000000000000000000000000815263ffffffff841660048201526101f460248201526044016108dc565b60006111ec826001615507565b6040805160208082018c9052338284015267ffffffffffffffff808c16606084015284166080808401919091528351808403909101815260a08301845280519082012060c083018d905260e080840182905284518085039091018152610100909301909352815191012091925081611262613667565b60408051602081019390935282015267ffffffffffffffff8a16606082015263ffffffff8089166080830152871660a08201523360c082015260e00160408051808303601f19018152828252805160209182012060008681526009835283902055848352820183905261ffff8a169082015263ffffffff808916606083015287166080820152339067ffffffffffffffff8b16908c907f63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a97729060a00160405180910390a45033600090815260026020908152604080832067ffffffffffffffff808d16855292529091208054919093167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009091161790915591505095945050505050565b600b546601000000000000900460ff16156113cc576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600860205260409020546bffffffffffffffffffffffff80831691161015611426576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260086020526040812080548392906114539084906bffffffffffffffffffffffff166155c2565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080600560088282829054906101000a90046bffffffffffffffffffffffff166114aa91906155c2565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb83836040518363ffffffff1660e01b81526004016115489291906001600160a01b039290921682526bffffffffffffffffffffffff16602082015260400190565b602060405180830381600087803b15801561156257600080fd5b505af1158015611576573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159a9190614e3b565b6115d0576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b6115dc6131e6565b60408051808201825260009161160b919084906002908390839080828437600092019190915250612a16915050565b6000818152600660205260409020549091506001600160a01b031615611660576040517f4a0b8fa7000000000000000000000000000000000000000000000000000000008152600481018290526024016108dc565b600081815260066020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0388169081179091556007805460018101825594527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b89101610ba3565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680611760576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b038216146117ad576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff16156117f4576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff84166000908152600360205260409020600201546064141561184b576040517f05a48e0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316600090815260026020908152604080832067ffffffffffffffff80891685529252909120541615611885576109e5565b6001600160a01b038316600081815260026020818152604080842067ffffffffffffffff8a1680865290835281852080547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001908117909155600384528286209094018054948501815585529382902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001685179055905192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e091016109dc565b6001546001600160a01b031633146119ab5760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016108dc565b60008054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600b546601000000000000900460ff1615611a61576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020546001600160a01b0316611aba576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020600101546001600160a01b03163314611b425767ffffffffffffffff8116600090815260036020526040908190206001015490517fd084e9750000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016108dc565b67ffffffffffffffff81166000818152600360209081526040918290208054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001909301805490931690925583516001600160a01b03909116808252928101919091529092917f6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f0910160405180910390a25050565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680611c3c576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b03821614611c89576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff1615611cd0576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611cd984612fb2565b15611d10576040517fb42f66e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316600090815260026020908152604080832067ffffffffffffffff808916855292529091205416611d91576040517ff0019fe600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff851660048201526001600160a01b03841660248201526044016108dc565b67ffffffffffffffff8416600090815260036020908152604080832060020180548251818502810185019093528083529192909190830182828015611dff57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611de1575b50505050509050600060018251611e1691906155ab565b905060005b8251811015611f8e57856001600160a01b0316838281518110611e4057611e406156f1565b60200260200101516001600160a01b03161415611f7c576000838381518110611e6b57611e6b6156f1565b6020026020010151905080600360008a67ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000206002018381548110611eb157611eb16156f1565b600091825260208083209190910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03949094169390931790925567ffffffffffffffff8a168152600390915260409020600201805480611f1e57611f1e6156c2565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611f8e565b80611f86816155ef565b915050611e1b565b506001600160a01b038516600081815260026020908152604080832067ffffffffffffffff8b168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690555192835290917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b91015b60405180910390a2505050505050565b600b546000906601000000000000900460ff1615612069576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805467ffffffffffffffff1690600061208383615628565b82546101009290920a67ffffffffffffffff8181021990931691831602179091556005541690506000806040519080825280602002602001820160405280156120d6578160200160208202803683370190505b506040805180820182526000808252602080830182815267ffffffffffffffff888116808552600484528685209551865493516bffffffffffffffffffffffff9091167fffffffffffffffffffffffff0000000000000000000000000000000000000000948516176c01000000000000000000000000919093160291909117909455845160608101865233815280830184815281870188815295855260038452959093208351815483166001600160a01b03918216178255955160018201805490931696169590951790559151805194955090936121ba9260028501920190614a3f565b505060405133815267ffffffffffffffff841691507f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf9060200160405180910390a250905090565b67ffffffffffffffff8116600090815260036020526040812054819081906060906001600160a01b0316612262576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff80861660009081526004602090815260408083205460038352928190208054600290910180548351818602810186019094528084526bffffffffffffffffffffffff8616966c01000000000000000000000000909604909516946001600160a01b0390921693909291839183018282801561230f57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116122f1575b5050505050905093509350935093509193509193565b600b546601000000000000900460ff161561236c576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146123ce576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208114612408576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612416828401846150f2565b67ffffffffffffffff81166000908152600360205260409020549091506001600160a01b0316612472576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8116600090815260046020526040812080546bffffffffffffffffffffffff16918691906124a98385615533565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555084600560088282829054906101000a90046bffffffffffffffffffffffff166125009190615533565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508167ffffffffffffffff167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f882878461256791906154ef565b6040805192835260208301919091520161200f565b600b546000906601000000000000900460ff16156125c6576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005a905060008060006125da8787613700565b9250925092506000866060015163ffffffff1667ffffffffffffffff81111561260557612605615720565b60405190808252806020026020018201604052801561262e578160200160208202803683370190505b50905060005b876060015163ffffffff168110156126a25760408051602081018590529081018290526060016040516020818303038152906040528051906020012060001c828281518110612685576126856156f1565b60209081029190910101528061269a816155ef565b915050612634565b506000838152600960205260408082208290555181907f1fe543e300000000000000000000000000000000000000000000000000000000906126ea90879086906024016153f6565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252600b80547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff166601000000000000179055908a015160808b015191925060009161279a9163ffffffff169084613a0e565b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff1690556020808c01805167ffffffffffffffff9081166000908152600490935260408084205492518216845290922080549394506c01000000000000000000000000918290048316936001939192600c9261281e928692900416615507565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060006128758a600b600001600b9054906101000a900463ffffffff1663ffffffff1661286f85612a46565b3a613a5c565b6020808e015167ffffffffffffffff166000908152600490915260409020549091506bffffffffffffffffffffffff808316911610156128e1576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808d015167ffffffffffffffff166000908152600490915260408120805483929061291d9084906bffffffffffffffffffffffff166155c2565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008b8152600660209081526040808320546001600160a01b03168352600890915281208054859450909261297991859116615533565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550877f7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e48883866040516129fc939291909283526bffffffffffffffffffffffff9190911660208301521515604082015260600190565b60405180910390a299505050505050505050505b92915050565b600081604051602001612a299190615243565b604051602081830303815290604052805190602001209050919050565b6040805161012081018252600c5463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c010000000000000000000000008104831660608301527001000000000000000000000000000000008104909216608082015262ffffff740100000000000000000000000000000000000000008304811660a08301819052770100000000000000000000000000000000000000000000008404821660c08401527a0100000000000000000000000000000000000000000000000000008404821660e08401527d0100000000000000000000000000000000000000000000000000000000009093041661010082015260009167ffffffffffffffff841611612b64575192915050565b8267ffffffffffffffff168160a0015162ffffff16108015612b9957508060c0015162ffffff168367ffffffffffffffff1611155b15612ba8576020015192915050565b8267ffffffffffffffff168160c0015162ffffff16108015612bdd57508060e0015162ffffff168367ffffffffffffffff1611155b15612bec576040015192915050565b8267ffffffffffffffff168160e0015162ffffff16108015612c22575080610100015162ffffff168367ffffffffffffffff1611155b15612c31576060015192915050565b6080015192915050565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680612c97576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b03821614612ce4576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff1615612d2b576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612d3484612fb2565b15612d6b576040517fb42f66e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109e58484613242565b612d7d6131e6565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612df857600080fd5b505afa158015612e0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e309190614e5d565b6005549091506801000000000000000090046bffffffffffffffffffffffff1681811115612e94576040517fa99da30200000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016108dc565b81811015612fad576000612ea882846155ab565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152602482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb90604401602060405180830381600087803b158015612f3057600080fd5b505af1158015612f44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f689190614e3b565b50604080516001600160a01b0386168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a1505b505050565b67ffffffffffffffff81166000908152600360209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561304757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613029575b505050505081525050905060005b8160400151518110156131cb5760005b6007548110156131b857600061318160078381548110613087576130876156f1565b9060005260206000200154856040015185815181106130a8576130a86156f1565b60200260200101518860026000896040015189815181106130cb576130cb6156f1565b6020908102919091018101516001600160a01b03168252818101929092526040908101600090812067ffffffffffffffff808f16835293522054166040805160208082018790526001600160a01b03959095168183015267ffffffffffffffff9384166060820152919092166080808301919091528251808303909101815260a08201835280519084012060c082019490945260e080820185905282518083039091018152610100909101909152805191012091565b50600081815260096020526040902054909150156131a55750600195945050505050565b50806131b0816155ef565b915050613065565b50806131c3816155ef565b915050613055565b5060009392505050565b6131dd6131e6565b61083481613b7c565b6000546001600160a01b031633146132405760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016108dc565b565b600b546601000000000000900460ff1615613289576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff82166000908152600360209081526040808320815160608101835281546001600160a01b0390811682526001830154168185015260028201805484518187028101870186528181529295939486019383018282801561331a57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116132fc575b5050509190925250505067ffffffffffffffff80851660009081526004602090815260408083208151808301909252546bffffffffffffffffffffffff81168083526c01000000000000000000000000909104909416918101919091529293505b8360400151518110156134145760026000856040015183815181106133a2576133a26156f1565b6020908102919091018101516001600160a01b03168252818101929092526040908101600090812067ffffffffffffffff8a168252909252902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690558061340c816155ef565b91505061337b565b5067ffffffffffffffff8516600090815260036020526040812080547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116825560018201805490911690559061346f6002830182614abc565b505067ffffffffffffffff8516600090815260046020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600580548291906008906134df9084906801000000000000000090046bffffffffffffffffffffffff166155c2565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb85836bffffffffffffffffffffffff166040518363ffffffff1660e01b815260040161357d9291906001600160a01b03929092168252602082015260400190565b602060405180830381600087803b15801561359757600080fd5b505af11580156135ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135cf9190614e3b565b613605576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516001600160a01b03861681526bffffffffffffffffffffffff8316602082015267ffffffffffffffff8716917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815910160405180910390a25050505050565b60004661a4b181148061367c575062066eed81145b156136f95760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156136bb57600080fd5b505afa1580156136cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136f39190614e5d565b91505090565b4391505090565b60008060006137128560000151612a16565b6000818152600660205260409020549093506001600160a01b031680613767576040517f77f5b84c000000000000000000000000000000000000000000000000000000008152600481018590526024016108dc565b6080860151604051613786918691602001918252602082015260400190565b60408051601f19818403018152918152815160209283012060008181526009909352912054909350806137e5576040517f3688124a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85516020808801516040808a015160608b015160808c01519251613851968b96909594910195865267ffffffffffffffff948516602087015292909316604085015263ffffffff90811660608501529190911660808301526001600160a01b031660a082015260c00190565b60405160208183030381529060405280519060200120811461389f576040517fd529142c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006138ae8760000151613c3e565b9050806139ba5786516040517fe9413d3800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e9413d389060240160206040518083038186803b15801561393a57600080fd5b505afa15801561394e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139729190614e5d565b9050806139ba5786516040517f175dadad00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016108dc565b60008860800151826040516020016139dc929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c9050613a018982613d52565b9450505050509250925092565b60005a611388811015613a2057600080fd5b611388810390508460408204820311613a3857600080fd5b50823b613a4457600080fd5b60008083516020850160008789f190505b9392505050565b600080613a67613dbd565b905060008113613aa6576040517f43d4cf66000000000000000000000000000000000000000000000000000000008152600481018290526024016108dc565b6000613ab0613ec4565b9050600082825a613ac18b8b6154ef565b613acb91906155ab565b613ad5908861556e565b613adf91906154ef565b613af190670de0b6b3a764000061556e565b613afb919061555a565b90506000613b1463ffffffff881664e8d4a5100061556e565b9050613b2c816b033b2e3c9fd0803ce80000006155ab565b821115613b65576040517fe80fa38100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613b6f81836154ef565b9998505050505050505050565b6001600160a01b038116331415613bd55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016108dc565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60004661a4b1811480613c53575062066eed81145b80613c60575062066eee81145b15613d42576101008367ffffffffffffffff16613c7b613667565b613c8591906155ab565b1180613ca25750613c94613667565b8367ffffffffffffffff1610155b15613cb05750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152606490632b407a829060240160206040518083038186803b158015613d0a57600080fd5b505afa158015613d1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a559190614e5d565b505067ffffffffffffffff164090565b6000613d868360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151613f20565b60038360200151604051602001613d9e9291906153e2565b60408051601f1981840301815291905280516020909101209392505050565b600b54604080517ffeaf968c0000000000000000000000000000000000000000000000000000000081529051600092670100000000000000900463ffffffff169182151591849182917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b158015613e5657600080fd5b505afa158015613e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e8e9190615137565b509450909250849150508015613eb25750613ea982426155ab565b8463ffffffff16105b15613ebc5750600a545b949350505050565b60004661a4b1811480613ed9575062066eed81145b15613f1857606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156136bb57600080fd5b600091505090565b613f298961415b565b613f755760405162461bcd60e51b815260206004820152601a60248201527f7075626c6963206b6579206973206e6f74206f6e20637572766500000000000060448201526064016108dc565b613f7e8861415b565b613fca5760405162461bcd60e51b815260206004820152601560248201527f67616d6d61206973206e6f74206f6e206375727665000000000000000000000060448201526064016108dc565b613fd38361415b565b61401f5760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e20637572766500000060448201526064016108dc565b6140288261415b565b6140745760405162461bcd60e51b815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e2063757276650000000060448201526064016108dc565b614080878a8887614234565b6140cc5760405162461bcd60e51b815260206004820152601960248201527f6164647228632a706b2b732a6729213d5f755769746e6573730000000000000060448201526064016108dc565b60006140d88a87614385565b905060006140eb898b878b8689896143e9565b905060006140fc838d8d8a86614515565b9050808a1461414d5760405162461bcd60e51b815260206004820152600d60248201527f696e76616c69642070726f6f660000000000000000000000000000000000000060448201526064016108dc565b505050505050505050505050565b80516000906401000003d019116141b45760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420782d6f7264696e617465000000000000000000000000000060448201526064016108dc565b60208201516401000003d0191161420d5760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420792d6f7264696e617465000000000000000000000000000060448201526064016108dc565b60208201516401000003d01990800961422d8360005b6020020151614555565b1492915050565b60006001600160a01b03821661428c5760405162461bcd60e51b815260206004820152600b60248201527f626164207769746e65737300000000000000000000000000000000000000000060448201526064016108dc565b6020840151600090600116156142a357601c6142a6565b601b5b905060007ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418587600060200201510986517ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa15801561435d573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b61438d614ada565b6143ba600184846040516020016143a693929190615222565b604051602081830303815290604052614579565b90505b6143c68161415b565b612a105780516040805160208101929092526143e291016143a6565b90506143bd565b6143f1614ada565b825186516401000003d01990819006910614156144505760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e6374000060448201526064016108dc565b61445b8789886145c8565b6144a75760405162461bcd60e51b815260206004820152601660248201527f4669727374206d756c20636865636b206661696c65640000000000000000000060448201526064016108dc565b6144b28486856145c8565b6144fe5760405162461bcd60e51b815260206004820152601760248201527f5365636f6e64206d756c20636865636b206661696c656400000000000000000060448201526064016108dc565b614509868484614710565b98975050505050505050565b600060028686868587604051602001614533969594939291906151b0565b60408051601f1981840301815291905280516020909101209695505050505050565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614581614ada565b61458a826147d7565b815261459f61459a826000614223565b614812565b6020820181905260029006600114156145c3576020810180516401000003d0190390525b919050565b6000826146175760405162461bcd60e51b815260206004820152600b60248201527f7a65726f207363616c617200000000000000000000000000000000000000000060448201526064016108dc565b8351602085015160009061462d90600290615650565b1561463957601c61463c565b601b5b905060007ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa1580156146bc573d6000803e3d6000fd5b5050506020604051035190506000866040516020016146db919061519e565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614718614ada565b83516020808601518551918601516000938493849361473993909190614832565b919450925090506401000003d0198582096001146147995760405162461bcd60e51b815260206004820152601960248201527f696e765a206d75737420626520696e7665727365206f66207a0000000000000060448201526064016108dc565b60405180604001604052806401000003d019806147b8576147b8615693565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d01981106145c3576040805160208082019390935281518082038401815290820190915280519101206147df565b6000612a1082600261482b6401000003d01960016154ef565b901c614912565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614872838385856149d2565b909850905061488388828e886149f6565b909850905061489488828c876149f6565b909850905060006148a78d878b856149f6565b90985090506148b8888286866149d2565b90985090506148c988828e896149f6565b90985090508181146148fe576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614902565b8196505b5050505050509450945094915050565b60008061491d614af8565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a082015261494f614b16565b60208160c08460057ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa9250826149c85760405162461bcd60e51b815260206004820152601260248201527f6269674d6f64457870206661696c75726521000000000000000000000000000060448201526064016108dc565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b828054828255906000526020600020908101928215614aac579160200282015b82811115614aac57825182547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909116178255602090920191600190910190614a5f565b50614ab8929150614b34565b5090565b50805460008255906000526020600020908101906108349190614b34565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b80821115614ab85760008155600101614b35565b80356001600160a01b03811681146145c357600080fd5b8060408101831015612a1057600080fd5b600082601f830112614b8257600080fd5b6040516040810181811067ffffffffffffffff82111715614ba557614ba5615720565b8060405250808385604086011115614bbc57600080fd5b60005b6002811015614bde578135835260209283019290910190600101614bbf565b509195945050505050565b600060a08284031215614bfb57600080fd5b60405160a0810181811067ffffffffffffffff82111715614c1e57614c1e615720565b604052905080614c2d83614cb3565b8152614c3b60208401614cb3565b6020820152614c4c60408401614c9f565b6040820152614c5d60608401614c9f565b6060820152614c6e60808401614b49565b60808201525092915050565b803561ffff811681146145c357600080fd5b803562ffffff811681146145c357600080fd5b803563ffffffff811681146145c357600080fd5b803567ffffffffffffffff811681146145c357600080fd5b805169ffffffffffffffffffff811681146145c357600080fd5b600060208284031215614cf757600080fd5b613a5582614b49565b60008060608385031215614d1357600080fd5b614d1c83614b49565b9150614d2b8460208501614b60565b90509250929050565b60008060008060608587031215614d4a57600080fd5b614d5385614b49565b935060208501359250604085013567ffffffffffffffff80821115614d7757600080fd5b818701915087601f830112614d8b57600080fd5b813581811115614d9a57600080fd5b886020828501011115614dac57600080fd5b95989497505060200194505050565b60008060408385031215614dce57600080fd5b614dd783614b49565b915060208301356bffffffffffffffffffffffff81168114614df857600080fd5b809150509250929050565b600060408284031215614e1557600080fd5b613a558383614b60565b600060408284031215614e3157600080fd5b613a558383614b71565b600060208284031215614e4d57600080fd5b81518015158114613a5557600080fd5b600060208284031215614e6f57600080fd5b5051919050565b600080600080600060a08688031215614e8e57600080fd5b85359450614e9e60208701614cb3565b9350614eac60408701614c7a565b9250614eba60608701614c9f565b9150614ec860808701614c9f565b90509295509295909350565b600080828403610240811215614ee957600080fd5b6101a080821215614ef957600080fd5b614f016154c5565b9150614f0d8686614b71565b8252614f1c8660408701614b71565b60208301526080850135604083015260a0850135606083015260c08501356080830152614f4b60e08601614b49565b60a0830152610100614f5f87828801614b71565b60c0840152614f72876101408801614b71565b60e08401526101808601358184015250819350614f9186828701614be9565b925050509250929050565b6000806000806000808688036101c0811215614fb757600080fd5b614fc088614c7a565b9650614fce60208901614c9f565b9550614fdc60408901614c9f565b9450614fea60608901614c9f565b935060808801359250610120807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608301121561502557600080fd5b61502d6154c5565b915061503b60a08a01614c9f565b825261504960c08a01614c9f565b602083015261505a60e08a01614c9f565b604083015261010061506d818b01614c9f565b606084015261507d828b01614c9f565b608084015261508f6101408b01614c8c565b60a08401526150a16101608b01614c8c565b60c08401526150b36101808b01614c8c565b60e08401526150c56101a08b01614c8c565b818401525050809150509295509295509295565b6000602082840312156150eb57600080fd5b5035919050565b60006020828403121561510457600080fd5b613a5582614cb3565b6000806040838503121561512057600080fd5b61512983614cb3565b9150614d2b60208401614b49565b600080600080600060a0868803121561514f57600080fd5b61515886614ccb565b9450602086015193506040860151925060608601519150614ec860808701614ccb565b8060005b60028110156109e557815184526020938401939091019060010161517f565b6151a8818361517b565b604001919050565b8681526151c0602082018761517b565b6151cd606082018661517b565b6151da60a082018561517b565b6151e760e082018461517b565b60609190911b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166101208201526101340195945050505050565b838152615232602082018461517b565b606081019190915260800192915050565b60408101612a10828461517b565b600060208083528351808285015260005b8181101561527e57858101830151858201604001528201615262565b81811115615290576000604083870101525b50601f01601f1916929092016040019392505050565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b818110156152f7578451835293830193918301916001016152db565b509098975050505050505050565b60006101c08201905061ffff8816825263ffffffff808816602084015280871660408401528086166060840152846080840152835481811660a085015261535960c08501838360201c1663ffffffff169052565b61537060e08501838360401c1663ffffffff169052565b6153886101008501838360601c1663ffffffff169052565b6153a06101208501838360801c1663ffffffff169052565b62ffffff60a082901c811661014086015260b882901c811661016086015260d082901c1661018085015260e81c6101a090930192909252979650505050505050565b82815260608101613a55602083018461517b565b6000604082018483526020604081850152818551808452606086019150828701935060005b818110156154375784518352938301939183019160010161541b565b5090979650505050505050565b6000608082016bffffffffffffffffffffffff87168352602067ffffffffffffffff8716818501526001600160a01b0380871660408601526080606086015282865180855260a087019150838801945060005b818110156154b5578551841683529484019491840191600101615497565b50909a9950505050505050505050565b604051610120810167ffffffffffffffff811182821017156154e9576154e9615720565b60405290565b6000821982111561550257615502615664565b500190565b600067ffffffffffffffff80831681851680830382111561552a5761552a615664565b01949350505050565b60006bffffffffffffffffffffffff80831681851680830382111561552a5761552a615664565b60008261556957615569615693565b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156155a6576155a6615664565b500290565b6000828210156155bd576155bd615664565b500390565b60006bffffffffffffffffffffffff838116908316818110156155e7576155e7615664565b039392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561562157615621615664565b5060010190565b600067ffffffffffffffff8083168181141561564657615646615664565b6001019392505050565b60008261565f5761565f615693565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", } var VRFCoordinatorV2ABI = VRFCoordinatorV2MetaData.ABI diff --git a/core/gethwrappers/generated/vrf_coordinator_v2plus/vrf_coordinator_v2plus.go b/core/gethwrappers/generated/vrf_coordinator_v2plus/vrf_coordinator_v2plus.go index 53dab6a4788..a57ed02b815 100644 --- a/core/gethwrappers/generated/vrf_coordinator_v2plus/vrf_coordinator_v2plus.go +++ b/core/gethwrappers/generated/vrf_coordinator_v2plus/vrf_coordinator_v2plus.go @@ -67,7 +67,7 @@ type VRFV2PlusClientRandomWordsRequest struct { var VRFCoordinatorV2PlusMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"blockhashStore\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"internalBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"externalBalance\",\"type\":\"uint256\"}],\"name\":\"BalanceInvariantViolated\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"BlockhashNotInStore\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorNotRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToSendEther\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"have\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"want\",\"type\":\"uint256\"}],\"name\":\"InsufficientGasForConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"have\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"min\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"max\",\"type\":\"uint16\"}],\"name\":\"InvalidRequestConfirmations\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkNotSet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeRequestedOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoCorrespondingRequest\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"NoSuchProvingKey\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"NumWordsTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PendingRequestExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"ProvingKeyAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Reentrant\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeEthPPM\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structVRFCoordinatorV2Plus.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"EthFundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"MigrationCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"name\":\"ProvingKeyDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"name\":\"ProvingKeyRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"RandomWordsFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"preSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RandomWordsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountLink\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountEth\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldEthBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newEthBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFundedWithEth\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BLOCKHASH_STORE\",\"outputs\":[{\"internalType\":\"contractBlockhashStoreInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_ETH_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CONSUMERS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_NUM_WORDS\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_REQUEST_CONFIRMATIONS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"deregisterMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"deregisterProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"pk\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"gamma\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"s\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"uWitness\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"cGammaWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"sHashWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"zInv\",\"type\":\"uint256\"}],\"internalType\":\"structVRF.Proof\",\"name\":\"proof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFCoordinatorV2Plus.RequestCommitment\",\"name\":\"rc\",\"type\":\"tuple\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"fundSubscriptionWithEth\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveSubscriptionIds\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRequestConfig\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"getSubscription\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"ethBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicKey\",\"type\":\"uint256[2]\"}],\"name\":\"hashOfKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"}],\"name\":\"migrate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"migrationVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdrawEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverEthFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"registerMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"registerProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFV2PlusClient.RandomWordsRequest\",\"name\":\"req\",\"type\":\"tuple\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"requestSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_config\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"reentrancyLock\",\"type\":\"bool\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_currentSubNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fallbackWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_feeConfig\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeEthPPM\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_provingKeyHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_provingKeys\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requestCommitments\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalEthBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeEthPPM\",\"type\":\"uint32\"}],\"internalType\":\"structVRFCoordinatorV2Plus.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkEthFeed\",\"type\":\"address\"}],\"name\":\"setLINKAndLINKETHFeed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b506040516200614c3803806200614c833981016040819052620000349162000183565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d7565b50505060601b6001600160601b031916608052620001b5565b6001600160a01b038116331415620001325760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019657600080fd5b81516001600160a01b0381168114620001ae57600080fd5b9392505050565b60805160601c615f71620001db600039600081816105ee0152613a860152615f716000f3fe6080604052600436106102dc5760003560e01c80638da5cb5b1161017f578063bec4c08c116100e1578063dc311dd31161008a578063e95704bd11610064578063e95704bd1461095d578063ee9d2d3814610984578063f2fde38b146109b157600080fd5b8063dc311dd3146108f9578063e72f6e301461092a578063e8509bff1461094a57600080fd5b8063d98e620e116100bb578063d98e620e14610883578063da2f2610146108a3578063dac83d29146108d957600080fd5b8063bec4c08c14610823578063caf70c4a14610843578063cb6317971461086357600080fd5b8063a8cb447b11610143578063aefb212f1161011d578063aefb212f146107b6578063b08c8795146107e3578063b2a7cac51461080357600080fd5b8063a8cb447b14610756578063aa433aff14610776578063ad1783611461079657600080fd5b80638da5cb5b146106ab5780639b1c385e146106c95780639d40a6fd146106e9578063a21a23e414610721578063a4c0ed361461073657600080fd5b806340d6bb821161024357806366316d8d116101ec5780636f64f03f116101c65780636f64f03f1461065657806379ba50971461067657806386fe91c71461068b57600080fd5b806366316d8d146105bc578063689c4517146105dc5780636b6feccc1461061057600080fd5b806357133e641161021d57806357133e64146105675780635d06b4ab1461058757806364d51a2a146105a757600080fd5b806340d6bb82146104ec57806341af6c871461051757806346d8d4861461054757600080fd5b80630ae09540116102a5578063294daa491161027f578063294daa4914610478578063330987b314610494578063405b84fa146104cc57600080fd5b80630ae09540146103f857806315c48b84146104185780631b6b6d231461044057600080fd5b8062012291146102e157806304104edb1461030e578063043bd6ae14610330578063088070f51461035457806308821d58146103d8575b600080fd5b3480156102ed57600080fd5b506102f66109d1565b60405161030593929190615ad5565b60405180910390f35b34801561031a57600080fd5b5061032e610329366004615422565b610a4d565b005b34801561033c57600080fd5b5061034660115481565b604051908152602001610305565b34801561036057600080fd5b50600d546103a09061ffff81169063ffffffff62010000820481169160ff600160301b820416916701000000000000008204811691600160581b90041685565b6040805161ffff909616865263ffffffff9485166020870152921515928501929092528216606084015216608082015260a001610305565b3480156103e457600080fd5b5061032e6103f3366004615562565b610c0f565b34801561040457600080fd5b5061032e610413366004615804565b610da3565b34801561042457600080fd5b5061042d60c881565b60405161ffff9091168152602001610305565b34801561044c57600080fd5b50600254610460906001600160a01b031681565b6040516001600160a01b039091168152602001610305565b34801561048457600080fd5b5060405160018152602001610305565b3480156104a057600080fd5b506104b46104af366004615634565b610e71565b6040516001600160601b039091168152602001610305565b3480156104d857600080fd5b5061032e6104e7366004615804565b61135b565b3480156104f857600080fd5b506105026101f481565b60405163ffffffff9091168152602001610305565b34801561052357600080fd5b506105376105323660046155b7565b611782565b6040519015158152602001610305565b34801561055357600080fd5b5061032e61056236600461543f565b611983565b34801561057357600080fd5b5061032e610582366004615474565b611b00565b34801561059357600080fd5b5061032e6105a2366004615422565b611b60565b3480156105b357600080fd5b5061042d606481565b3480156105c857600080fd5b5061032e6105d736600461543f565b611c1e565b3480156105e857600080fd5b506104607f000000000000000000000000000000000000000000000000000000000000000081565b34801561061c57600080fd5b506012546106399063ffffffff8082169164010000000090041682565b6040805163ffffffff938416815292909116602083015201610305565b34801561066257600080fd5b5061032e6106713660046154ad565b611de6565b34801561068257600080fd5b5061032e611ee5565b34801561069757600080fd5b50600a546104b4906001600160601b031681565b3480156106b757600080fd5b506000546001600160a01b0316610460565b3480156106d557600080fd5b506103466106e4366004615711565b611f96565b3480156106f557600080fd5b50600754610709906001600160401b031681565b6040516001600160401b039091168152602001610305565b34801561072d57600080fd5b5061034661238b565b34801561074257600080fd5b5061032e6107513660046154da565b6125db565b34801561076257600080fd5b5061032e610771366004615422565b61277b565b34801561078257600080fd5b5061032e6107913660046155b7565b612896565b3480156107a257600080fd5b50600354610460906001600160a01b031681565b3480156107c257600080fd5b506107d66107d1366004615829565b6128f6565b6040516103059190615a3a565b3480156107ef57600080fd5b5061032e6107fe366004615766565b6129f7565b34801561080f57600080fd5b5061032e61081e3660046155b7565b612b8b565b34801561082f57600080fd5b5061032e61083e366004615804565b612cc1565b34801561084f57600080fd5b5061034661085e36600461557e565b612e5d565b34801561086f57600080fd5b5061032e61087e366004615804565b612e8d565b34801561088f57600080fd5b5061034661089e3660046155b7565b613190565b3480156108af57600080fd5b506104606108be3660046155b7565b600e602052600090815260409020546001600160a01b031681565b3480156108e557600080fd5b5061032e6108f4366004615804565b6131b1565b34801561090557600080fd5b506109196109143660046155b7565b6132d0565b604051610305959493929190615c3d565b34801561093657600080fd5b5061032e610945366004615422565b6133cb565b61032e6109583660046155b7565b6135b3565b34801561096957600080fd5b50600a546104b490600160601b90046001600160601b031681565b34801561099057600080fd5b5061034661099f3660046155b7565b60106020526000908152604090205481565b3480156109bd57600080fd5b5061032e6109cc366004615422565b6136f2565b600d54600f805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff16939192839190830182828015610a3b57602002820191906000526020600020905b815481526020019060010190808311610a27575b50505050509050925092509250909192565b610a55613703565b60135460005b81811015610be257826001600160a01b031660138281548110610a8057610a80615f15565b6000918252602090912001546001600160a01b03161415610bd0576013610aa8600184615e0e565b81548110610ab857610ab8615f15565b600091825260209091200154601380546001600160a01b039092169183908110610ae457610ae4615f15565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055826013610b1b600185615e0e565b81548110610b2b57610b2b615f15565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506013805480610b6a57610b6a615eff565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03851681527ff80a1a97fd42251f3c33cda98635e7399253033a6774fe37cd3f650b5282af37910160405180910390a1505050565b80610bda81615e7d565b915050610a5b565b50604051635428d44960e01b81526001600160a01b03831660048201526024015b60405180910390fd5b50565b610c17613703565b604080518082018252600091610c46919084906002908390839080828437600092019190915250612e5d915050565b6000818152600e60205260409020549091506001600160a01b031680610c8257604051631dfd6e1360e21b815260048101839052602401610c03565b6000828152600e6020526040812080546001600160a01b03191690555b600f54811015610d5a5782600f8281548110610cbd57610cbd615f15565b90600052602060002001541415610d4857600f805460009190610ce290600190615e0e565b81548110610cf257610cf2615f15565b9060005260206000200154905080600f8381548110610d1357610d13615f15565b600091825260209091200155600f805480610d3057610d30615eff565b60019003818190600052602060002001600090559055505b80610d5281615e7d565b915050610c9f565b50806001600160a01b03167f72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d83604051610d9691815260200190565b60405180910390a2505050565b60008281526005602052604090205482906001600160a01b031680610ddb57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614610e0f57604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff1615610e3a5760405163769dd35360e11b815260040160405180910390fd5b610e4384611782565b15610e6157604051631685ecdd60e31b815260040160405180910390fd5b610e6b848461375f565b50505050565b600d54600090600160301b900460ff1615610e9f5760405163769dd35360e11b815260040160405180910390fd5b60005a90506000610eb0858561391b565b90506000846060015163ffffffff166001600160401b03811115610ed657610ed6615f2b565b604051908082528060200260200182016040528015610eff578160200160208202803683370190505b50905060005b856060015163ffffffff16811015610f7f57826040015181604051602001610f37929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c828281518110610f6257610f62615f15565b602090810291909101015280610f7781615e7d565b915050610f05565b5060208083018051600090815260109092526040808320839055905190518291631fe543e360e01b91610fb791908690602401615b48565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600d805466ff0000000000001916600160301b17905590880151608089015191925060009161101f9163ffffffff169084613ba8565b600d805466ff00000000000019169055602089810151600090815260069091526040902054909150600160c01b90046001600160401b0316611062816001615d8e565b6020808b0151600090815260069091526040812080546001600160401b0393909316600160c01b026001600160c01b039093169290921790915560a08a015180516110af90600190615e0e565b815181106110bf576110bf615f15565b602091010151600d5460f89190911c60011491506000906110f0908a90600160581b900463ffffffff163a85613bf6565b905081156111f9576020808c01516000908152600690915260409020546001600160601b03808316600160601b90920416101561114057604051631e9acf1760e31b815260040160405180910390fd5b60208b81015160009081526006909152604090208054829190600c90611177908490600160601b90046001600160601b0316615e25565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600c9091528120805485945090926111d091859116615db9565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506112e5565b6020808c01516000908152600690915260409020546001600160601b038083169116101561123a57604051631e9acf1760e31b815260040160405180910390fd5b6020808c0151600090815260069091526040812080548392906112679084906001600160601b0316615e25565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600b9091528120805485945090926112c091859116615db9565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b8a6020015188602001517f49580fdfd9497e1ed5c1b1cec0495087ae8e3f1267470ec2fb015db32e3d6aa78a604001518488604051611342939291909283526001600160601b039190911660208301521515604082015260600190565b60405180910390a3985050505050505050505b92915050565b600d54600160301b900460ff16156113865760405163769dd35360e11b815260040160405180910390fd5b61138f81613c46565b6113b757604051635428d44960e01b81526001600160a01b0382166004820152602401610c03565b6000806000806113c6866132d0565b945094505093509350336001600160a01b0316826001600160a01b0316146114305760405162461bcd60e51b815260206004820152601660248201527f4e6f7420737562736372697074696f6e206f776e6572000000000000000000006044820152606401610c03565b61143986611782565b156114865760405162461bcd60e51b815260206004820152601660248201527f50656e64696e67207265717565737420657869737473000000000000000000006044820152606401610c03565b60006040518060c0016040528061149b600190565b60ff168152602001888152602001846001600160a01b03168152602001838152602001866001600160601b03168152602001856001600160601b031681525090506000816040516020016114ef9190615a60565b604051602081830303815290604052905061150988613cb0565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b03881690611542908590600401615a4d565b6000604051808303818588803b15801561155b57600080fd5b505af115801561156f573d6000803e3d6000fd5b50506002546001600160a01b031615801593509150611598905057506001600160601b03861615155b156116775760025460405163a9059cbb60e01b81526001600160a01b0389811660048301526001600160601b03891660248301529091169063a9059cbb90604401602060405180830381600087803b1580156115f357600080fd5b505af1158015611607573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162b919061559a565b6116775760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742066756e647300000000000000000000000000006044820152606401610c03565b600d805466ff0000000000001916600160301b17905560005b8351811015611725578381815181106116ab576116ab615f15565b6020908102919091010151604051638ea9811760e01b81526001600160a01b038a8116600483015290911690638ea9811790602401600060405180830381600087803b1580156116fa57600080fd5b505af115801561170e573d6000803e3d6000fd5b50505050808061171d90615e7d565b915050611690565b50600d805466ff00000000000019169055604080516001600160a01b0389168152602081018a90527fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be4187910160405180910390a15050505050505050565b6000818152600560209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561180c57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116117ee575b505050505081525050905060005b8160400151518110156119795760005b600f5481101561196657600061192f600f838154811061184c5761184c615f15565b90600052602060002001548560400151858151811061186d5761186d615f15565b602002602001015188600460008960400151898151811061189057611890615f15565b6020908102919091018101516001600160a01b03908116835282820193909352604091820160009081208e82528252829020548251808301889052959093168583015260608501939093526001600160401b039091166080808501919091528151808503909101815260a08401825280519083012060c084019490945260e0808401859052815180850390910181526101009093019052815191012091565b50600081815260106020526040902054909150156119535750600195945050505050565b508061195e81615e7d565b91505061182a565b508061197181615e7d565b91505061181a565b5060009392505050565b600d54600160301b900460ff16156119ae5760405163769dd35360e11b815260040160405180910390fd5b336000908152600c60205260409020546001600160601b03808316911610156119ea57604051631e9acf1760e31b815260040160405180910390fd5b336000908152600c602052604081208054839290611a129084906001600160601b0316615e25565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b0316611a5a9190615e25565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114611ad4576040519150601f19603f3d011682016040523d82523d6000602084013e611ad9565b606091505b5050905080611afb57604051630dcf35db60e41b815260040160405180910390fd5b505050565b611b08613703565b6002546001600160a01b031615611b3257604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b611b68613703565b611b7181613c46565b15611b9a5760405163ac8a27ef60e01b81526001600160a01b0382166004820152602401610c03565b601380546001810182556000919091527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180546001600160a01b0319166001600160a01b0383169081179091556040519081527fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af016259060200160405180910390a150565b600d54600160301b900460ff1615611c495760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b0316611c725760405163c1f0c0a160e01b815260040160405180910390fd5b336000908152600b60205260409020546001600160601b0380831691161015611cae57604051631e9acf1760e31b815260040160405180910390fd5b336000908152600b602052604081208054839290611cd69084906001600160601b0316615e25565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b0316611d1e9190615e25565b82546101009290920a6001600160601b0381810219909316918316021790915560025460405163a9059cbb60e01b81526001600160a01b03868116600483015292851660248201529116915063a9059cbb90604401602060405180830381600087803b158015611d8d57600080fd5b505af1158015611da1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dc5919061559a565b611de257604051631e9acf1760e31b815260040160405180910390fd5b5050565b611dee613703565b604080518082018252600091611e1d919084906002908390839080828437600092019190915250612e5d915050565b6000818152600e60205260409020549091506001600160a01b031615611e5957604051634a0b8fa760e01b815260048101829052602401610c03565b6000818152600e6020908152604080832080546001600160a01b0319166001600160a01b038816908117909155600f805460018101825594527f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac802909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b89101610d96565b6001546001600160a01b03163314611f3f5760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610c03565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600d54600090600160301b900460ff1615611fc45760405163769dd35360e11b815260040160405180910390fd5b6020808301356000908152600590915260409020546001600160a01b0316611fff57604051630fb532db60e11b815260040160405180910390fd5b3360009081526004602090815260408083208583013584529091529020546001600160401b031680612050576040516379bfd40160e01b815260208401356004820152336024820152604401610c03565b600d5461ffff16612067606085016040860161574b565b61ffff16108061208a575060c8612084606085016040860161574b565b61ffff16115b156120d05761209f606084016040850161574b565b600d5460405163539c34bb60e11b815261ffff92831660048201529116602482015260c86044820152606401610c03565b600d5462010000900463ffffffff166120ef608085016060860161584b565b63ffffffff16111561213f5761210b608084016060850161584b565b600d54604051637aebf00f60e11b815263ffffffff9283166004820152620100009091049091166024820152604401610c03565b6101f461215260a085016080860161584b565b63ffffffff1611156121985761216e60a084016080850161584b565b6040516311ce1afb60e21b815263ffffffff90911660048201526101f46024820152604401610c03565b60006121a5826001615d8e565b604080518635602080830182905233838501528089013560608401526001600160401b0385166080808501919091528451808503909101815260a0808501865281519183019190912060c085019390935260e0808501849052855180860390910181526101009094019094528251920191909120929350906000906122359061223090890189615c92565b613eff565b9050600061224282613f7c565b90508361224d613fed565b60208a013561226260808c0160608d0161584b565b61227260a08d0160808e0161584b565b338660405160200161228a9796959493929190615ba0565b604051602081830303815290604052805190602001206010600086815260200190815260200160002081905550336001600160a01b0316886020013589600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e87878d6040016020810190612301919061574b565b8e6060016020810190612314919061584b565b8f6080016020810190612327919061584b565b8960405161233a96959493929190615b61565b60405180910390a450503360009081526004602090815260408083208983013584529091529020805467ffffffffffffffff19166001600160401b039490941693909317909255925050505b919050565b600d54600090600160301b900460ff16156123b95760405163769dd35360e11b815260040160405180910390fd5b6000336123c7600143615e0e565b600754604051606093841b6bffffffffffffffffffffffff199081166020830152924060348201523090931b909116605483015260c01b6001600160c01b031916606882015260700160408051601f198184030181529190528051602090910120600780549192506001600160401b0390911690600061244683615e98565b91906101000a8154816001600160401b0302191690836001600160401b03160217905550506000806001600160401b0381111561248557612485615f2b565b6040519080825280602002602001820160405280156124ae578160200160208202803683370190505b506040805160608082018352600080835260208084018281528486018381528984526006835286842095518654925191516001600160601b039182166001600160c01b031990941693909317600160601b9190921602176001600160c01b0316600160c01b6001600160401b039092169190910217909355835191820184523382528183018181528285018681528883526005855294909120825181546001600160a01b03199081166001600160a01b03928316178355925160018301805490941691161790915592518051949550909361258f9260028501920190615138565b5061259f91506008905083614086565b5060405133815282907f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d9060200160405180910390a250905090565b600d54600160301b900460ff16156126065760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b03163314612631576040516344b0e3c360e01b815260040160405180910390fd5b6020811461265257604051638129bbcd60e01b815260040160405180910390fd5b6000612660828401846155b7565b6000818152600560205260409020549091506001600160a01b031661269857604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b0316918691906126bf8385615db9565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b03166127079190615db9565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a82878461275a9190615d76565b604080519283526020830191909152015b60405180910390a2505050505050565b612783613703565b600a544790600160601b90046001600160601b0316818111156127c3576040516354ced18160e11b81526004810182905260248101839052604401610c03565b81811015611afb5760006127d78284615e0e565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114612826576040519150601f19603f3d011682016040523d82523d6000602084013e61282b565b606091505b505090508061284d57604051630dcf35db60e41b815260040160405180910390fd5b604080516001600160a01b0387168152602081018490527f879c9ea2b9d5345b84ccd12610b032602808517cebdb795007f3dcb4df377317910160405180910390a15050505050565b61289e613703565b6000818152600560205260409020546001600160a01b03166128d357604051630fb532db60e11b815260040160405180910390fd5b600081815260056020526040902054610c0c9082906001600160a01b031661375f565b606060006129046008614092565b905080841061292657604051631390f2a160e01b815260040160405180910390fd5b60006129328486615d76565b905081811180612940575083155b61294a578061294c565b815b9050600061295a8683615e0e565b6001600160401b0381111561297157612971615f2b565b60405190808252806020026020018201604052801561299a578160200160208202803683370190505b50905060005b81518110156129ed576129be6129b68883615d76565b60089061409c565b8282815181106129d0576129d0615f15565b6020908102919091010152806129e581615e7d565b9150506129a0565b5095945050505050565b6129ff613703565b60c861ffff87161115612a395760405163539c34bb60e11b815261ffff871660048201819052602482015260c86044820152606401610c03565b60008213612a5d576040516321ea67b360e11b815260048101839052602401610c03565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600d805465ffffffffffff19168817620100008702176effffffffffffffffff000000000000191667010000000000000085026effffffff0000000000000000000000191617600160581b83021790558a51601280548d87015192891667ffffffffffffffff199091161764010000000092891692909202919091179081905560118d90558a519788528785019590955298860191909152840196909652938201879052838116928201929092529190921c90911660c08201527f777357bb93f63d088f18112d3dba38457aec633eb8f1341e1d418380ad328e789060e00160405180910390a1505050505050565b600d54600160301b900460ff1615612bb65760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b0316612beb57604051630fb532db60e11b815260040160405180910390fd5b6000818152600560205260409020600101546001600160a01b03163314612c44576000818152600560205260409081902060010154905163d084e97560e01b81526001600160a01b039091166004820152602401610c03565b6000818152600560209081526040918290208054336001600160a01b0319808316821784556001909301805490931690925583516001600160a01b0390911680825292810191909152909183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c938691015b60405180910390a25050565b60008281526005602052604090205482906001600160a01b031680612cf957604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612d2d57604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff1615612d585760405163769dd35360e11b815260040160405180910390fd5b60008481526005602052604090206002015460641415612d8b576040516305a48e0f60e01b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b031615612dc257610e6b565b6001600160a01b03831660008181526004602090815260408083208884528252808320805467ffffffffffffffff19166001908117909155600583528184206002018054918201815584529282902090920180546001600160a01b03191684179055905191825285917f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e191015b60405180910390a250505050565b600081604051602001612e709190615a2c565b604051602081830303815290604052805190602001209050919050565b60008281526005602052604090205482906001600160a01b031680612ec557604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612ef957604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff1615612f245760405163769dd35360e11b815260040160405180910390fd5b612f2d84611782565b15612f4b57604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b0316612fa7576040516379bfd40160e01b8152600481018590526001600160a01b0384166024820152604401610c03565b60008481526005602090815260408083206002018054825181850281018501909352808352919290919083018282801561300a57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612fec575b505050505090506000600182516130219190615e0e565b905060005b825181101561312d57856001600160a01b031683828151811061304b5761304b615f15565b60200260200101516001600160a01b0316141561311b57600083838151811061307657613076615f15565b6020026020010151905080600560008a815260200190815260200160002060020183815481106130a8576130a8615f15565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394909416939093179092558981526005909152604090206002018054806130f3576130f3615eff565b600082815260209020810160001990810180546001600160a01b03191690550190555061312d565b8061312581615e7d565b915050613026565b506001600160a01b03851660008181526004602090815260408083208a8452825291829020805467ffffffffffffffff19169055905191825287917f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a7910161276b565b600f81815481106131a057600080fd5b600091825260209091200154905081565b60008281526005602052604090205482906001600160a01b0316806131e957604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b0382161461321d57604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff16156132485760405163769dd35360e11b815260040160405180910390fd5b6000848152600560205260409020600101546001600160a01b03848116911614610e6b5760008481526005602090815260409182902060010180546001600160a01b0319166001600160a01b03871690811790915582513381529182015285917f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a19101612e4f565b6000818152600560205260408120548190819081906060906001600160a01b031661330e57604051630fb532db60e11b815260040160405180910390fd5b60008681526006602090815260408083205460058352928190208054600290910180548351818602810186019094528084526001600160601b0380871696600160601b810490911695600160c01b9091046001600160401b0316946001600160a01b03909416939183918301828280156133b157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613393575b505050505090509450945094509450945091939590929450565b6133d3613703565b6002546001600160a01b03166133fc5760405163c1f0c0a160e01b815260040160405180910390fd5b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b15801561344057600080fd5b505afa158015613454573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061347891906155d0565b600a549091506001600160601b0316818111156134b2576040516354ced18160e11b81526004810182905260248101839052604401610c03565b81811015611afb5760006134c68284615e0e565b60025460405163a9059cbb60e01b81526001600160a01b0387811660048301526024820184905292935091169063a9059cbb90604401602060405180830381600087803b15801561351657600080fd5b505af115801561352a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061354e919061559a565b61356b57604051631f01ff1360e21b815260040160405180910390fd5b604080516001600160a01b0386168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a150505050565b600d54600160301b900460ff16156135de5760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b031661361357604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c6136428385615db9565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b031661368a9190615db9565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f3f1ddc3ab1bdb39001ad76ca51a0e6f57ce6627c69f251d1de41622847721cde8234846136dd9190615d76565b60408051928352602083019190915201612cb5565b6136fa613703565b610c0c816140a8565b6000546001600160a01b0316331461375d5760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610c03565b565b60008061376b84613cb0565b60025491935091506001600160a01b03161580159061379257506001600160601b03821615155b156138425760025460405163a9059cbb60e01b81526001600160a01b0385811660048301526001600160601b03851660248301529091169063a9059cbb90604401602060405180830381600087803b1580156137ed57600080fd5b505af1158015613801573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613825919061559a565b61384257604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114613898576040519150601f19603f3d011682016040523d82523d6000602084013e61389d565b606091505b50509050806138bf57604051630dcf35db60e41b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b038581166020830152841681830152905186917f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c4919081900360600190a25050505050565b604080516060810182526000808252602082018190529181019190915260006139478460000151612e5d565b6000818152600e60205260409020549091506001600160a01b03168061398357604051631dfd6e1360e21b815260048101839052602401610c03565b60008286608001516040516020016139a5929190918252602082015260400190565b60408051601f19818403018152918152815160209283012060008181526010909352912054909150806139eb57604051631b44092560e11b815260040160405180910390fd5b85516020808801516040808a015160608b015160808c015160a08d01519351613a1a978a979096959101615bea565b604051602081830303815290604052805190602001208114613a4f5760405163354a450b60e21b815260040160405180910390fd5b6000613a5e8760000151614152565b905080613b36578651604051631d2827a760e31b81526001600160401b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e9413d389060240160206040518083038186803b158015613ad057600080fd5b505afa158015613ae4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b0891906155d0565b905080613b3657865160405163175dadad60e01b81526001600160401b039091166004820152602401610c03565b6000886080015182604051602001613b58929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c90506000613b7f8a8361423c565b604080516060810182529889526020890196909652948701949094525093979650505050505050565b60005a611388811015613bba57600080fd5b611388810390508460408204820311613bd257600080fd5b50823b613bde57600080fd5b60008083516020850160008789f190505b9392505050565b60008115613c2457601254613c1d9086908690640100000000900463ffffffff16866142a7565b9050613c3e565b601254613c3b908690869063ffffffff1686614311565b90505b949350505050565b6000805b601354811015613ca757826001600160a01b031660138281548110613c7157613c71615f15565b6000918252602090912001546001600160a01b03161415613c955750600192915050565b80613c9f81615e7d565b915050613c4a565b50600092915050565b6000818152600560209081526040808320815160608101835281546001600160a01b03908116825260018301541681850152600282018054845181870281018701865281815287968796949594860193919290830182828015613d3c57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613d1e575b505050919092525050506000858152600660209081526040808320815160608101835290546001600160601b03808216808452600160601b8304909116948301859052600160c01b9091046001600160401b0316928201929092529096509094509192505b826040015151811015613e19576004600084604001518381518110613dc857613dc8615f15565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208982529092529020805467ffffffffffffffff1916905580613e1181615e7d565b915050613da1565b50600085815260056020526040812080546001600160a01b03199081168255600182018054909116905590613e51600283018261519d565b5050600085815260066020526040812055613e6d6008866143ff565b50600a8054859190600090613e8c9084906001600160601b0316615e25565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555082600a600c8282829054906101000a90046001600160601b0316613ed49190615e25565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505050915091565b60408051602081019091526000815281613f285750604080516020810190915260008152611355565b63125fa26760e31b613f3a8385615e4d565b6001600160e01b03191614613f6257604051632923fee760e11b815260040160405180910390fd5b613f6f8260048186615d4c565b810190613bef91906155e9565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401613fb591511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b60004661a4b1811480614002575062066eed81145b1561407f5760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561404157600080fd5b505afa158015614055573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061407991906155d0565b91505090565b4391505090565b6000613bef838361440b565b6000611355825490565b6000613bef838361445a565b6001600160a01b0381163314156141015760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610c03565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60004661a4b1811480614167575062066eed81145b1561422d57610100836001600160401b0316614181613fed565b61418b9190615e0e565b11806141a7575061419a613fed565b836001600160401b031610155b156141b55750600092915050565b6040516315a03d4160e11b81526001600160401b0384166004820152606490632b407a829060240160206040518083038186803b1580156141f557600080fd5b505afa158015614209573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bef91906155d0565b50506001600160401b03164090565b60006142708360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151614484565b60038360200151604051602001614288929190615b34565b60408051601f1981840301815291905280516020909101209392505050565b6000806142b26146af565b905060005a6142c18888615d76565b6142cb9190615e0e565b6142d59085615def565b905060006142ee63ffffffff871664e8d4a51000615def565b9050826142fb8284615d76565b6143059190615d76565b98975050505050505050565b60008061431c61470b565b905060008113614342576040516321ea67b360e11b815260048101829052602401610c03565b600061434c6146af565b9050600082825a61435d8b8b615d76565b6143679190615e0e565b6143719088615def565b61437b9190615d76565b61438d90670de0b6b3a7640000615def565b6143979190615ddb565b905060006143b063ffffffff881664e8d4a51000615def565b90506143c8816b033b2e3c9fd0803ce8000000615e0e565b8211156143e85760405163e80fa38160e01b815260040160405180910390fd5b6143f28183615d76565b9998505050505050505050565b6000613bef83836147da565b600081815260018301602052604081205461445257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611355565b506000611355565b600082600001828154811061447157614471615f15565b9060005260206000200154905092915050565b61448d896148cd565b6144d95760405162461bcd60e51b815260206004820152601a60248201527f7075626c6963206b6579206973206e6f74206f6e2063757276650000000000006044820152606401610c03565b6144e2886148cd565b61452e5760405162461bcd60e51b815260206004820152601560248201527f67616d6d61206973206e6f74206f6e20637572766500000000000000000000006044820152606401610c03565b614537836148cd565b6145835760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e2063757276650000006044820152606401610c03565b61458c826148cd565b6145d85760405162461bcd60e51b815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e206375727665000000006044820152606401610c03565b6145e4878a88876149a6565b6146305760405162461bcd60e51b815260206004820152601960248201527f6164647228632a706b2b732a6729213d5f755769746e657373000000000000006044820152606401610c03565b600061463c8a87614ac9565b9050600061464f898b878b868989614b2d565b90506000614660838d8d8a86614c4d565b9050808a146146a15760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610c03565b505050505050505050505050565b60004661a4b18114806146c4575062066eed81145b1561470357606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561404157600080fd5b600091505090565b600d5460035460408051633fabe5a360e21b81529051600093670100000000000000900463ffffffff169283151592859283926001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b15801561476d57600080fd5b505afa158015614781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147a59190615866565b5094509092508491505080156147c957506147c08242615e0e565b8463ffffffff16105b15613c3e5750601154949350505050565b600081815260018301602052604081205480156148c35760006147fe600183615e0e565b855490915060009061481290600190615e0e565b905081811461487757600086600001828154811061483257614832615f15565b906000526020600020015490508087600001848154811061485557614855615f15565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061488857614888615eff565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611355565b6000915050611355565b80516000906401000003d019116149265760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420782d6f7264696e61746500000000000000000000000000006044820152606401610c03565b60208201516401000003d0191161497f5760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420792d6f7264696e61746500000000000000000000000000006044820152606401610c03565b60208201516401000003d01990800961499f8360005b6020020151614c8d565b1492915050565b60006001600160a01b0382166149ec5760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b6044820152606401610c03565b602084015160009060011615614a0357601c614a06565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe19918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa158015614aa1573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b614ad16151bb565b614afe60018484604051602001614aea93929190615a0b565b604051602081830303815290604052614cb1565b90505b614b0a816148cd565b611355578051604080516020810192909252614b269101614aea565b9050614b01565b614b356151bb565b825186516401000003d0199081900691061415614b945760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e637400006044820152606401610c03565b614b9f878988614cff565b614beb5760405162461bcd60e51b815260206004820152601660248201527f4669727374206d756c20636865636b206661696c6564000000000000000000006044820152606401610c03565b614bf6848685614cff565b614c425760405162461bcd60e51b815260206004820152601760248201527f5365636f6e64206d756c20636865636b206661696c65640000000000000000006044820152606401610c03565b614305868484614e27565b600060028686868587604051602001614c6b969594939291906159ac565b60408051601f1981840301815291905280516020909101209695505050505050565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614cb96151bb565b614cc282614eee565b8152614cd7614cd2826000614995565b614f29565b602082018190526002900660011415612386576020810180516401000003d019039052919050565b600082614d3c5760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b6044820152606401610c03565b83516020850151600090614d5290600290615ebf565b15614d5e57601c614d61565b601b5b9050600070014551231950b75fc4402da1732fc9bebe198387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa158015614dd3573d6000803e3d6000fd5b505050602060405103519050600086604051602001614df2919061599a565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614e2f6151bb565b835160208086015185519186015160009384938493614e5093909190614f49565b919450925090506401000003d019858209600114614eb05760405162461bcd60e51b815260206004820152601960248201527f696e765a206d75737420626520696e7665727365206f66207a000000000000006044820152606401610c03565b60405180604001604052806401000003d01980614ecf57614ecf615ee9565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d019811061238657604080516020808201939093528151808203840181529082019091528051910120614ef6565b6000611355826002614f426401000003d0196001615d76565b901c615029565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614f89838385856150cb565b9098509050614f9a88828e886150ef565b9098509050614fab88828c876150ef565b90985090506000614fbe8d878b856150ef565b9098509050614fcf888286866150cb565b9098509050614fe088828e896150ef565b9098509050818114615015576401000003d019818a0998506401000003d01982890997506401000003d0198183099650615019565b8196505b5050505050509450945094915050565b6000806150346151d9565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a08201526150666151f7565b60208160c0846005600019fa9250826150c15760405162461bcd60e51b815260206004820152601260248201527f6269674d6f64457870206661696c7572652100000000000000000000000000006044820152606401610c03565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b82805482825590600052602060002090810192821561518d579160200282015b8281111561518d57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190615158565b50615199929150615215565b5090565b5080546000825590600052602060002090810190610c0c9190615215565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b808211156151995760008155600101615216565b803561238681615f41565b806040810183101561135557600080fd5b600082601f83011261525757600080fd5b61525f615cdf565b80838560408601111561527157600080fd5b60005b6002811015615293578135845260209384019390910190600101615274565b509095945050505050565b600082601f8301126152af57600080fd5b81356001600160401b03808211156152c9576152c9615f2b565b604051601f8301601f19908116603f011681019082821181831017156152f1576152f1615f2b565b8160405283815286602085880101111561530a57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060c0828403121561533c57600080fd5b615344615d07565b905081356001600160401b03808216821461535e57600080fd5b81835260208401356020840152615377604085016153dd565b6040840152615388606085016153dd565b60608401526153996080850161522a565b608084015260a08401359150808211156153b257600080fd5b506153bf8482850161529e565b60a08301525092915050565b803561ffff8116811461238657600080fd5b803563ffffffff8116811461238657600080fd5b805169ffffffffffffffffffff8116811461238657600080fd5b80356001600160601b038116811461238657600080fd5b60006020828403121561543457600080fd5b8135613bef81615f41565b6000806040838503121561545257600080fd5b823561545d81615f41565b915061546b6020840161540b565b90509250929050565b6000806040838503121561548757600080fd5b823561549281615f41565b915060208301356154a281615f41565b809150509250929050565b600080606083850312156154c057600080fd5b82356154cb81615f41565b915061546b8460208501615235565b600080600080606085870312156154f057600080fd5b84356154fb81615f41565b93506020850135925060408501356001600160401b038082111561551e57600080fd5b818701915087601f83011261553257600080fd5b81358181111561554157600080fd5b88602082850101111561555357600080fd5b95989497505060200194505050565b60006040828403121561557457600080fd5b613bef8383615235565b60006040828403121561559057600080fd5b613bef8383615246565b6000602082840312156155ac57600080fd5b8151613bef81615f56565b6000602082840312156155c957600080fd5b5035919050565b6000602082840312156155e257600080fd5b5051919050565b6000602082840312156155fb57600080fd5b604051602081018181106001600160401b038211171561561d5761561d615f2b565b604052823561562b81615f56565b81529392505050565b6000808284036101c081121561564957600080fd5b6101a08082121561565957600080fd5b615661615d29565b915061566d8686615246565b825261567c8660408701615246565b60208301526080850135604083015260a0850135606083015260c085013560808301526156ab60e0860161522a565b60a08301526101006156bf87828801615246565b60c08401526156d2876101408801615246565b60e0840152610180860135908301529092508301356001600160401b038111156156fb57600080fd5b6157078582860161532a565b9150509250929050565b60006020828403121561572357600080fd5b81356001600160401b0381111561573957600080fd5b820160c08185031215613bef57600080fd5b60006020828403121561575d57600080fd5b613bef826153cb565b60008060008060008086880360e081121561578057600080fd5b615789886153cb565b9650615797602089016153dd565b95506157a5604089016153dd565b94506157b3606089016153dd565b9350608088013592506040609f19820112156157ce57600080fd5b506157d7615cdf565b6157e360a089016153dd565b81526157f160c089016153dd565b6020820152809150509295509295509295565b6000806040838503121561581757600080fd5b8235915060208301356154a281615f41565b6000806040838503121561583c57600080fd5b50508035926020909101359150565b60006020828403121561585d57600080fd5b613bef826153dd565b600080600080600060a0868803121561587e57600080fd5b615887866153f1565b94506020860151935060408601519250606086015191506158aa608087016153f1565b90509295509295909350565b600081518084526020808501945080840160005b838110156158ef5781516001600160a01b0316875295820195908201906001016158ca565b509495945050505050565b8060005b6002811015610e6b5781518452602093840193909101906001016158fe565b600081518084526020808501945080840160005b838110156158ef57815187529582019590820190600101615931565b6000815180845260005b8181101561597357602081850181015186830182015201615957565b81811115615985576000602083870101525b50601f01601f19169290920160200192915050565b6159a481836158fa565b604001919050565b8681526159bc60208201876158fa565b6159c960608201866158fa565b6159d660a08201856158fa565b6159e360e08201846158fa565b60609190911b6bffffffffffffffffffffffff19166101208201526101340195945050505050565b838152615a1b60208201846158fa565b606081019190915260800192915050565b6040810161135582846158fa565b602081526000613bef602083018461591d565b602081526000613bef602083018461594d565b6020815260ff8251166020820152602082015160408201526001600160a01b0360408301511660608201526000606083015160c06080840152615aa660e08401826158b6565b905060808401516001600160601b0380821660a08601528060a08701511660c086015250508091505092915050565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b81811015615b2657845183529383019391830191600101615b0a565b509098975050505050505050565b82815260608101613bef60208301846158fa565b828152604060208201526000613c3e604083018461591d565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a083015261430560c083018461594d565b878152866020820152856040820152600063ffffffff80871660608401528086166080840152506001600160a01b03841660a083015260e060c08301526143f260e083018461594d565b8781526001600160401b0387166020820152856040820152600063ffffffff80871660608401528086166080840152506001600160a01b03841660a083015260e060c08301526143f260e083018461594d565b60006001600160601b0380881683528087166020840152506001600160401b03851660408301526001600160a01b038416606083015260a06080830152615c8760a08301846158b6565b979650505050505050565b6000808335601e19843603018112615ca957600080fd5b8301803591506001600160401b03821115615cc357600080fd5b602001915036819003821315615cd857600080fd5b9250929050565b604080519081016001600160401b0381118282101715615d0157615d01615f2b565b60405290565b60405160c081016001600160401b0381118282101715615d0157615d01615f2b565b60405161012081016001600160401b0381118282101715615d0157615d01615f2b565b60008085851115615d5c57600080fd5b83861115615d6957600080fd5b5050820193919092039150565b60008219821115615d8957615d89615ed3565b500190565b60006001600160401b03808316818516808303821115615db057615db0615ed3565b01949350505050565b60006001600160601b03808316818516808303821115615db057615db0615ed3565b600082615dea57615dea615ee9565b500490565b6000816000190483118215151615615e0957615e09615ed3565b500290565b600082821015615e2057615e20615ed3565b500390565b60006001600160601b0383811690831681811015615e4557615e45615ed3565b039392505050565b6001600160e01b03198135818116916004851015615e755780818660040360031b1b83161692505b505092915050565b6000600019821415615e9157615e91615ed3565b5060010190565b60006001600160401b0380831681811415615eb557615eb5615ed3565b6001019392505050565b600082615ece57615ece615ee9565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610c0c57600080fd5b8015158114610c0c57600080fdfea164736f6c6343000806000a", + Bin: "0x60a06040523480156200001157600080fd5b506040516200615938038062006159833981016040819052620000349162000183565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d7565b50505060601b6001600160601b031916608052620001b5565b6001600160a01b038116331415620001325760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019657600080fd5b81516001600160a01b0381168114620001ae57600080fd5b9392505050565b60805160601c615f7e620001db600039600081816105ee0152613a860152615f7e6000f3fe6080604052600436106102dc5760003560e01c80638da5cb5b1161017f578063bec4c08c116100e1578063dc311dd31161008a578063e95704bd11610064578063e95704bd1461095d578063ee9d2d3814610984578063f2fde38b146109b157600080fd5b8063dc311dd3146108f9578063e72f6e301461092a578063e8509bff1461094a57600080fd5b8063d98e620e116100bb578063d98e620e14610883578063da2f2610146108a3578063dac83d29146108d957600080fd5b8063bec4c08c14610823578063caf70c4a14610843578063cb6317971461086357600080fd5b8063a8cb447b11610143578063aefb212f1161011d578063aefb212f146107b6578063b08c8795146107e3578063b2a7cac51461080357600080fd5b8063a8cb447b14610756578063aa433aff14610776578063ad1783611461079657600080fd5b80638da5cb5b146106ab5780639b1c385e146106c95780639d40a6fd146106e9578063a21a23e414610721578063a4c0ed361461073657600080fd5b806340d6bb821161024357806366316d8d116101ec5780636f64f03f116101c65780636f64f03f1461065657806379ba50971461067657806386fe91c71461068b57600080fd5b806366316d8d146105bc578063689c4517146105dc5780636b6feccc1461061057600080fd5b806357133e641161021d57806357133e64146105675780635d06b4ab1461058757806364d51a2a146105a757600080fd5b806340d6bb82146104ec57806341af6c871461051757806346d8d4861461054757600080fd5b80630ae09540116102a5578063294daa491161027f578063294daa4914610478578063330987b314610494578063405b84fa146104cc57600080fd5b80630ae09540146103f857806315c48b84146104185780631b6b6d231461044057600080fd5b8062012291146102e157806304104edb1461030e578063043bd6ae14610330578063088070f51461035457806308821d58146103d8575b600080fd5b3480156102ed57600080fd5b506102f66109d1565b60405161030593929190615ae2565b60405180910390f35b34801561031a57600080fd5b5061032e61032936600461542f565b610a4d565b005b34801561033c57600080fd5b5061034660115481565b604051908152602001610305565b34801561036057600080fd5b50600d546103a09061ffff81169063ffffffff62010000820481169160ff600160301b820416916701000000000000008204811691600160581b90041685565b6040805161ffff909616865263ffffffff9485166020870152921515928501929092528216606084015216608082015260a001610305565b3480156103e457600080fd5b5061032e6103f336600461556f565b610c0f565b34801561040457600080fd5b5061032e610413366004615811565b610da3565b34801561042457600080fd5b5061042d60c881565b60405161ffff9091168152602001610305565b34801561044c57600080fd5b50600254610460906001600160a01b031681565b6040516001600160a01b039091168152602001610305565b34801561048457600080fd5b5060405160018152602001610305565b3480156104a057600080fd5b506104b46104af366004615641565b610e71565b6040516001600160601b039091168152602001610305565b3480156104d857600080fd5b5061032e6104e7366004615811565b61135b565b3480156104f857600080fd5b506105026101f481565b60405163ffffffff9091168152602001610305565b34801561052357600080fd5b506105376105323660046155c4565b611782565b6040519015158152602001610305565b34801561055357600080fd5b5061032e61056236600461544c565b611983565b34801561057357600080fd5b5061032e610582366004615481565b611b00565b34801561059357600080fd5b5061032e6105a236600461542f565b611b60565b3480156105b357600080fd5b5061042d606481565b3480156105c857600080fd5b5061032e6105d736600461544c565b611c1e565b3480156105e857600080fd5b506104607f000000000000000000000000000000000000000000000000000000000000000081565b34801561061c57600080fd5b506012546106399063ffffffff8082169164010000000090041682565b6040805163ffffffff938416815292909116602083015201610305565b34801561066257600080fd5b5061032e6106713660046154ba565b611de6565b34801561068257600080fd5b5061032e611ee5565b34801561069757600080fd5b50600a546104b4906001600160601b031681565b3480156106b757600080fd5b506000546001600160a01b0316610460565b3480156106d557600080fd5b506103466106e436600461571e565b611f96565b3480156106f557600080fd5b50600754610709906001600160401b031681565b6040516001600160401b039091168152602001610305565b34801561072d57600080fd5b5061034661238b565b34801561074257600080fd5b5061032e6107513660046154e7565b6125db565b34801561076257600080fd5b5061032e61077136600461542f565b61277b565b34801561078257600080fd5b5061032e6107913660046155c4565b612896565b3480156107a257600080fd5b50600354610460906001600160a01b031681565b3480156107c257600080fd5b506107d66107d1366004615836565b6128f6565b6040516103059190615a47565b3480156107ef57600080fd5b5061032e6107fe366004615773565b6129f7565b34801561080f57600080fd5b5061032e61081e3660046155c4565b612b8b565b34801561082f57600080fd5b5061032e61083e366004615811565b612cc1565b34801561084f57600080fd5b5061034661085e36600461558b565b612e5d565b34801561086f57600080fd5b5061032e61087e366004615811565b612e8d565b34801561088f57600080fd5b5061034661089e3660046155c4565b613190565b3480156108af57600080fd5b506104606108be3660046155c4565b600e602052600090815260409020546001600160a01b031681565b3480156108e557600080fd5b5061032e6108f4366004615811565b6131b1565b34801561090557600080fd5b506109196109143660046155c4565b6132d0565b604051610305959493929190615c4a565b34801561093657600080fd5b5061032e61094536600461542f565b6133cb565b61032e6109583660046155c4565b6135b3565b34801561096957600080fd5b50600a546104b490600160601b90046001600160601b031681565b34801561099057600080fd5b5061034661099f3660046155c4565b60106020526000908152604090205481565b3480156109bd57600080fd5b5061032e6109cc36600461542f565b6136f2565b600d54600f805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff16939192839190830182828015610a3b57602002820191906000526020600020905b815481526020019060010190808311610a27575b50505050509050925092509250909192565b610a55613703565b60135460005b81811015610be257826001600160a01b031660138281548110610a8057610a80615f22565b6000918252602090912001546001600160a01b03161415610bd0576013610aa8600184615e1b565b81548110610ab857610ab8615f22565b600091825260209091200154601380546001600160a01b039092169183908110610ae457610ae4615f22565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055826013610b1b600185615e1b565b81548110610b2b57610b2b615f22565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506013805480610b6a57610b6a615f0c565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03851681527ff80a1a97fd42251f3c33cda98635e7399253033a6774fe37cd3f650b5282af37910160405180910390a1505050565b80610bda81615e8a565b915050610a5b565b50604051635428d44960e01b81526001600160a01b03831660048201526024015b60405180910390fd5b50565b610c17613703565b604080518082018252600091610c46919084906002908390839080828437600092019190915250612e5d915050565b6000818152600e60205260409020549091506001600160a01b031680610c8257604051631dfd6e1360e21b815260048101839052602401610c03565b6000828152600e6020526040812080546001600160a01b03191690555b600f54811015610d5a5782600f8281548110610cbd57610cbd615f22565b90600052602060002001541415610d4857600f805460009190610ce290600190615e1b565b81548110610cf257610cf2615f22565b9060005260206000200154905080600f8381548110610d1357610d13615f22565b600091825260209091200155600f805480610d3057610d30615f0c565b60019003818190600052602060002001600090559055505b80610d5281615e8a565b915050610c9f565b50806001600160a01b03167f72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d83604051610d9691815260200190565b60405180910390a2505050565b60008281526005602052604090205482906001600160a01b031680610ddb57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614610e0f57604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff1615610e3a5760405163769dd35360e11b815260040160405180910390fd5b610e4384611782565b15610e6157604051631685ecdd60e31b815260040160405180910390fd5b610e6b848461375f565b50505050565b600d54600090600160301b900460ff1615610e9f5760405163769dd35360e11b815260040160405180910390fd5b60005a90506000610eb0858561391b565b90506000846060015163ffffffff166001600160401b03811115610ed657610ed6615f38565b604051908082528060200260200182016040528015610eff578160200160208202803683370190505b50905060005b856060015163ffffffff16811015610f7f57826040015181604051602001610f37929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c828281518110610f6257610f62615f22565b602090810291909101015280610f7781615e8a565b915050610f05565b5060208083018051600090815260109092526040808320839055905190518291631fe543e360e01b91610fb791908690602401615b55565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600d805466ff0000000000001916600160301b17905590880151608089015191925060009161101f9163ffffffff169084613ba8565b600d805466ff00000000000019169055602089810151600090815260069091526040902054909150600160c01b90046001600160401b0316611062816001615d9b565b6020808b0151600090815260069091526040812080546001600160401b0393909316600160c01b026001600160c01b039093169290921790915560a08a015180516110af90600190615e1b565b815181106110bf576110bf615f22565b602091010151600d5460f89190911c60011491506000906110f0908a90600160581b900463ffffffff163a85613bf6565b905081156111f9576020808c01516000908152600690915260409020546001600160601b03808316600160601b90920416101561114057604051631e9acf1760e31b815260040160405180910390fd5b60208b81015160009081526006909152604090208054829190600c90611177908490600160601b90046001600160601b0316615e32565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600c9091528120805485945090926111d091859116615dc6565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506112e5565b6020808c01516000908152600690915260409020546001600160601b038083169116101561123a57604051631e9acf1760e31b815260040160405180910390fd5b6020808c0151600090815260069091526040812080548392906112679084906001600160601b0316615e32565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600b9091528120805485945090926112c091859116615dc6565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b8a6020015188602001517f49580fdfd9497e1ed5c1b1cec0495087ae8e3f1267470ec2fb015db32e3d6aa78a604001518488604051611342939291909283526001600160601b039190911660208301521515604082015260600190565b60405180910390a3985050505050505050505b92915050565b600d54600160301b900460ff16156113865760405163769dd35360e11b815260040160405180910390fd5b61138f81613c46565b6113b757604051635428d44960e01b81526001600160a01b0382166004820152602401610c03565b6000806000806113c6866132d0565b945094505093509350336001600160a01b0316826001600160a01b0316146114305760405162461bcd60e51b815260206004820152601660248201527f4e6f7420737562736372697074696f6e206f776e6572000000000000000000006044820152606401610c03565b61143986611782565b156114865760405162461bcd60e51b815260206004820152601660248201527f50656e64696e67207265717565737420657869737473000000000000000000006044820152606401610c03565b60006040518060c0016040528061149b600190565b60ff168152602001888152602001846001600160a01b03168152602001838152602001866001600160601b03168152602001856001600160601b031681525090506000816040516020016114ef9190615a6d565b604051602081830303815290604052905061150988613cb0565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b03881690611542908590600401615a5a565b6000604051808303818588803b15801561155b57600080fd5b505af115801561156f573d6000803e3d6000fd5b50506002546001600160a01b031615801593509150611598905057506001600160601b03861615155b156116775760025460405163a9059cbb60e01b81526001600160a01b0389811660048301526001600160601b03891660248301529091169063a9059cbb90604401602060405180830381600087803b1580156115f357600080fd5b505af1158015611607573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162b91906155a7565b6116775760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742066756e647300000000000000000000000000006044820152606401610c03565b600d805466ff0000000000001916600160301b17905560005b8351811015611725578381815181106116ab576116ab615f22565b6020908102919091010151604051638ea9811760e01b81526001600160a01b038a8116600483015290911690638ea9811790602401600060405180830381600087803b1580156116fa57600080fd5b505af115801561170e573d6000803e3d6000fd5b50505050808061171d90615e8a565b915050611690565b50600d805466ff00000000000019169055604080516001600160a01b0389168152602081018a90527fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be4187910160405180910390a15050505050505050565b6000818152600560209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561180c57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116117ee575b505050505081525050905060005b8160400151518110156119795760005b600f5481101561196657600061192f600f838154811061184c5761184c615f22565b90600052602060002001548560400151858151811061186d5761186d615f22565b602002602001015188600460008960400151898151811061189057611890615f22565b6020908102919091018101516001600160a01b03908116835282820193909352604091820160009081208e82528252829020548251808301889052959093168583015260608501939093526001600160401b039091166080808501919091528151808503909101815260a08401825280519083012060c084019490945260e0808401859052815180850390910181526101009093019052815191012091565b50600081815260106020526040902054909150156119535750600195945050505050565b508061195e81615e8a565b91505061182a565b508061197181615e8a565b91505061181a565b5060009392505050565b600d54600160301b900460ff16156119ae5760405163769dd35360e11b815260040160405180910390fd5b336000908152600c60205260409020546001600160601b03808316911610156119ea57604051631e9acf1760e31b815260040160405180910390fd5b336000908152600c602052604081208054839290611a129084906001600160601b0316615e32565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b0316611a5a9190615e32565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114611ad4576040519150601f19603f3d011682016040523d82523d6000602084013e611ad9565b606091505b5050905080611afb57604051630dcf35db60e41b815260040160405180910390fd5b505050565b611b08613703565b6002546001600160a01b031615611b3257604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b611b68613703565b611b7181613c46565b15611b9a5760405163ac8a27ef60e01b81526001600160a01b0382166004820152602401610c03565b601380546001810182556000919091527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180546001600160a01b0319166001600160a01b0383169081179091556040519081527fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af016259060200160405180910390a150565b600d54600160301b900460ff1615611c495760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b0316611c725760405163c1f0c0a160e01b815260040160405180910390fd5b336000908152600b60205260409020546001600160601b0380831691161015611cae57604051631e9acf1760e31b815260040160405180910390fd5b336000908152600b602052604081208054839290611cd69084906001600160601b0316615e32565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b0316611d1e9190615e32565b82546101009290920a6001600160601b0381810219909316918316021790915560025460405163a9059cbb60e01b81526001600160a01b03868116600483015292851660248201529116915063a9059cbb90604401602060405180830381600087803b158015611d8d57600080fd5b505af1158015611da1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dc591906155a7565b611de257604051631e9acf1760e31b815260040160405180910390fd5b5050565b611dee613703565b604080518082018252600091611e1d919084906002908390839080828437600092019190915250612e5d915050565b6000818152600e60205260409020549091506001600160a01b031615611e5957604051634a0b8fa760e01b815260048101829052602401610c03565b6000818152600e6020908152604080832080546001600160a01b0319166001600160a01b038816908117909155600f805460018101825594527f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac802909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b89101610d96565b6001546001600160a01b03163314611f3f5760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610c03565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600d54600090600160301b900460ff1615611fc45760405163769dd35360e11b815260040160405180910390fd5b6020808301356000908152600590915260409020546001600160a01b0316611fff57604051630fb532db60e11b815260040160405180910390fd5b3360009081526004602090815260408083208583013584529091529020546001600160401b031680612050576040516379bfd40160e01b815260208401356004820152336024820152604401610c03565b600d5461ffff166120676060850160408601615758565b61ffff16108061208a575060c86120846060850160408601615758565b61ffff16115b156120d05761209f6060840160408501615758565b600d5460405163539c34bb60e11b815261ffff92831660048201529116602482015260c86044820152606401610c03565b600d5462010000900463ffffffff166120ef6080850160608601615858565b63ffffffff16111561213f5761210b6080840160608501615858565b600d54604051637aebf00f60e11b815263ffffffff9283166004820152620100009091049091166024820152604401610c03565b6101f461215260a0850160808601615858565b63ffffffff1611156121985761216e60a0840160808501615858565b6040516311ce1afb60e21b815263ffffffff90911660048201526101f46024820152604401610c03565b60006121a5826001615d9b565b604080518635602080830182905233838501528089013560608401526001600160401b0385166080808501919091528451808503909101815260a0808501865281519183019190912060c085019390935260e0808501849052855180860390910181526101009094019094528251920191909120929350906000906122359061223090890189615c9f565b613eff565b9050600061224282613f7c565b90508361224d613fed565b60208a013561226260808c0160608d01615858565b61227260a08d0160808e01615858565b338660405160200161228a9796959493929190615bad565b604051602081830303815290604052805190602001206010600086815260200190815260200160002081905550336001600160a01b0316886020013589600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e87878d60400160208101906123019190615758565b8e60600160208101906123149190615858565b8f60800160208101906123279190615858565b8960405161233a96959493929190615b6e565b60405180910390a450503360009081526004602090815260408083208983013584529091529020805467ffffffffffffffff19166001600160401b039490941693909317909255925050505b919050565b600d54600090600160301b900460ff16156123b95760405163769dd35360e11b815260040160405180910390fd5b6000336123c7600143615e1b565b600754604051606093841b6bffffffffffffffffffffffff199081166020830152924060348201523090931b909116605483015260c01b6001600160c01b031916606882015260700160408051601f198184030181529190528051602090910120600780549192506001600160401b0390911690600061244683615ea5565b91906101000a8154816001600160401b0302191690836001600160401b03160217905550506000806001600160401b0381111561248557612485615f38565b6040519080825280602002602001820160405280156124ae578160200160208202803683370190505b506040805160608082018352600080835260208084018281528486018381528984526006835286842095518654925191516001600160601b039182166001600160c01b031990941693909317600160601b9190921602176001600160c01b0316600160c01b6001600160401b039092169190910217909355835191820184523382528183018181528285018681528883526005855294909120825181546001600160a01b03199081166001600160a01b03928316178355925160018301805490941691161790915592518051949550909361258f9260028501920190615145565b5061259f91506008905083614086565b5060405133815282907f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d9060200160405180910390a250905090565b600d54600160301b900460ff16156126065760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b03163314612631576040516344b0e3c360e01b815260040160405180910390fd5b6020811461265257604051638129bbcd60e01b815260040160405180910390fd5b6000612660828401846155c4565b6000818152600560205260409020549091506001600160a01b031661269857604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b0316918691906126bf8385615dc6565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b03166127079190615dc6565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a82878461275a9190615d83565b604080519283526020830191909152015b60405180910390a2505050505050565b612783613703565b600a544790600160601b90046001600160601b0316818111156127c3576040516354ced18160e11b81526004810182905260248101839052604401610c03565b81811015611afb5760006127d78284615e1b565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114612826576040519150601f19603f3d011682016040523d82523d6000602084013e61282b565b606091505b505090508061284d57604051630dcf35db60e41b815260040160405180910390fd5b604080516001600160a01b0387168152602081018490527f879c9ea2b9d5345b84ccd12610b032602808517cebdb795007f3dcb4df377317910160405180910390a15050505050565b61289e613703565b6000818152600560205260409020546001600160a01b03166128d357604051630fb532db60e11b815260040160405180910390fd5b600081815260056020526040902054610c0c9082906001600160a01b031661375f565b606060006129046008614092565b905080841061292657604051631390f2a160e01b815260040160405180910390fd5b60006129328486615d83565b905081811180612940575083155b61294a578061294c565b815b9050600061295a8683615e1b565b6001600160401b0381111561297157612971615f38565b60405190808252806020026020018201604052801561299a578160200160208202803683370190505b50905060005b81518110156129ed576129be6129b68883615d83565b60089061409c565b8282815181106129d0576129d0615f22565b6020908102919091010152806129e581615e8a565b9150506129a0565b5095945050505050565b6129ff613703565b60c861ffff87161115612a395760405163539c34bb60e11b815261ffff871660048201819052602482015260c86044820152606401610c03565b60008213612a5d576040516321ea67b360e11b815260048101839052602401610c03565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600d805465ffffffffffff19168817620100008702176effffffffffffffffff000000000000191667010000000000000085026effffffff0000000000000000000000191617600160581b83021790558a51601280548d87015192891667ffffffffffffffff199091161764010000000092891692909202919091179081905560118d90558a519788528785019590955298860191909152840196909652938201879052838116928201929092529190921c90911660c08201527f777357bb93f63d088f18112d3dba38457aec633eb8f1341e1d418380ad328e789060e00160405180910390a1505050505050565b600d54600160301b900460ff1615612bb65760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b0316612beb57604051630fb532db60e11b815260040160405180910390fd5b6000818152600560205260409020600101546001600160a01b03163314612c44576000818152600560205260409081902060010154905163d084e97560e01b81526001600160a01b039091166004820152602401610c03565b6000818152600560209081526040918290208054336001600160a01b0319808316821784556001909301805490931690925583516001600160a01b0390911680825292810191909152909183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c938691015b60405180910390a25050565b60008281526005602052604090205482906001600160a01b031680612cf957604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612d2d57604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff1615612d585760405163769dd35360e11b815260040160405180910390fd5b60008481526005602052604090206002015460641415612d8b576040516305a48e0f60e01b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b031615612dc257610e6b565b6001600160a01b03831660008181526004602090815260408083208884528252808320805467ffffffffffffffff19166001908117909155600583528184206002018054918201815584529282902090920180546001600160a01b03191684179055905191825285917f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e191015b60405180910390a250505050565b600081604051602001612e709190615a39565b604051602081830303815290604052805190602001209050919050565b60008281526005602052604090205482906001600160a01b031680612ec557604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612ef957604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff1615612f245760405163769dd35360e11b815260040160405180910390fd5b612f2d84611782565b15612f4b57604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b0316612fa7576040516379bfd40160e01b8152600481018590526001600160a01b0384166024820152604401610c03565b60008481526005602090815260408083206002018054825181850281018501909352808352919290919083018282801561300a57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612fec575b505050505090506000600182516130219190615e1b565b905060005b825181101561312d57856001600160a01b031683828151811061304b5761304b615f22565b60200260200101516001600160a01b0316141561311b57600083838151811061307657613076615f22565b6020026020010151905080600560008a815260200190815260200160002060020183815481106130a8576130a8615f22565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394909416939093179092558981526005909152604090206002018054806130f3576130f3615f0c565b600082815260209020810160001990810180546001600160a01b03191690550190555061312d565b8061312581615e8a565b915050613026565b506001600160a01b03851660008181526004602090815260408083208a8452825291829020805467ffffffffffffffff19169055905191825287917f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a7910161276b565b600f81815481106131a057600080fd5b600091825260209091200154905081565b60008281526005602052604090205482906001600160a01b0316806131e957604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b0382161461321d57604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff16156132485760405163769dd35360e11b815260040160405180910390fd5b6000848152600560205260409020600101546001600160a01b03848116911614610e6b5760008481526005602090815260409182902060010180546001600160a01b0319166001600160a01b03871690811790915582513381529182015285917f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a19101612e4f565b6000818152600560205260408120548190819081906060906001600160a01b031661330e57604051630fb532db60e11b815260040160405180910390fd5b60008681526006602090815260408083205460058352928190208054600290910180548351818602810186019094528084526001600160601b0380871696600160601b810490911695600160c01b9091046001600160401b0316946001600160a01b03909416939183918301828280156133b157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613393575b505050505090509450945094509450945091939590929450565b6133d3613703565b6002546001600160a01b03166133fc5760405163c1f0c0a160e01b815260040160405180910390fd5b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b15801561344057600080fd5b505afa158015613454573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061347891906155dd565b600a549091506001600160601b0316818111156134b2576040516354ced18160e11b81526004810182905260248101839052604401610c03565b81811015611afb5760006134c68284615e1b565b60025460405163a9059cbb60e01b81526001600160a01b0387811660048301526024820184905292935091169063a9059cbb90604401602060405180830381600087803b15801561351657600080fd5b505af115801561352a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061354e91906155a7565b61356b57604051631f01ff1360e21b815260040160405180910390fd5b604080516001600160a01b0386168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a150505050565b600d54600160301b900460ff16156135de5760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b031661361357604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c6136428385615dc6565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b031661368a9190615dc6565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f3f1ddc3ab1bdb39001ad76ca51a0e6f57ce6627c69f251d1de41622847721cde8234846136dd9190615d83565b60408051928352602083019190915201612cb5565b6136fa613703565b610c0c816140a8565b6000546001600160a01b0316331461375d5760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610c03565b565b60008061376b84613cb0565b60025491935091506001600160a01b03161580159061379257506001600160601b03821615155b156138425760025460405163a9059cbb60e01b81526001600160a01b0385811660048301526001600160601b03851660248301529091169063a9059cbb90604401602060405180830381600087803b1580156137ed57600080fd5b505af1158015613801573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061382591906155a7565b61384257604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114613898576040519150601f19603f3d011682016040523d82523d6000602084013e61389d565b606091505b50509050806138bf57604051630dcf35db60e41b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b038581166020830152841681830152905186917f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c4919081900360600190a25050505050565b604080516060810182526000808252602082018190529181019190915260006139478460000151612e5d565b6000818152600e60205260409020549091506001600160a01b03168061398357604051631dfd6e1360e21b815260048101839052602401610c03565b60008286608001516040516020016139a5929190918252602082015260400190565b60408051601f19818403018152918152815160209283012060008181526010909352912054909150806139eb57604051631b44092560e11b815260040160405180910390fd5b85516020808801516040808a015160608b015160808c015160a08d01519351613a1a978a979096959101615bf7565b604051602081830303815290604052805190602001208114613a4f5760405163354a450b60e21b815260040160405180910390fd5b6000613a5e8760000151614152565b905080613b36578651604051631d2827a760e31b81526001600160401b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e9413d389060240160206040518083038186803b158015613ad057600080fd5b505afa158015613ae4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b0891906155dd565b905080613b3657865160405163175dadad60e01b81526001600160401b039091166004820152602401610c03565b6000886080015182604051602001613b58929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c90506000613b7f8a83614249565b604080516060810182529889526020890196909652948701949094525093979650505050505050565b60005a611388811015613bba57600080fd5b611388810390508460408204820311613bd257600080fd5b50823b613bde57600080fd5b60008083516020850160008789f190505b9392505050565b60008115613c2457601254613c1d9086908690640100000000900463ffffffff16866142b4565b9050613c3e565b601254613c3b908690869063ffffffff168661431e565b90505b949350505050565b6000805b601354811015613ca757826001600160a01b031660138281548110613c7157613c71615f22565b6000918252602090912001546001600160a01b03161415613c955750600192915050565b80613c9f81615e8a565b915050613c4a565b50600092915050565b6000818152600560209081526040808320815160608101835281546001600160a01b03908116825260018301541681850152600282018054845181870281018701865281815287968796949594860193919290830182828015613d3c57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613d1e575b505050919092525050506000858152600660209081526040808320815160608101835290546001600160601b03808216808452600160601b8304909116948301859052600160c01b9091046001600160401b0316928201929092529096509094509192505b826040015151811015613e19576004600084604001518381518110613dc857613dc8615f22565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208982529092529020805467ffffffffffffffff1916905580613e1181615e8a565b915050613da1565b50600085815260056020526040812080546001600160a01b03199081168255600182018054909116905590613e5160028301826151aa565b5050600085815260066020526040812055613e6d60088661440c565b50600a8054859190600090613e8c9084906001600160601b0316615e32565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555082600a600c8282829054906101000a90046001600160601b0316613ed49190615e32565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505050915091565b60408051602081019091526000815281613f285750604080516020810190915260008152611355565b63125fa26760e31b613f3a8385615e5a565b6001600160e01b03191614613f6257604051632923fee760e11b815260040160405180910390fd5b613f6f8260048186615d59565b810190613bef91906155f6565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401613fb591511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b60004661a4b1811480614002575062066eed81145b1561407f5760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561404157600080fd5b505afa158015614055573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061407991906155dd565b91505090565b4391505090565b6000613bef8383614418565b6000611355825490565b6000613bef8383614467565b6001600160a01b0381163314156141015760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610c03565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60004661a4b1811480614167575062066eed81145b80614174575062066eee81145b1561423a57610100836001600160401b031661418e613fed565b6141989190615e1b565b11806141b457506141a7613fed565b836001600160401b031610155b156141c25750600092915050565b6040516315a03d4160e11b81526001600160401b0384166004820152606490632b407a829060240160206040518083038186803b15801561420257600080fd5b505afa158015614216573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bef91906155dd565b50506001600160401b03164090565b600061427d8360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151614491565b60038360200151604051602001614295929190615b41565b60408051601f1981840301815291905280516020909101209392505050565b6000806142bf6146bc565b905060005a6142ce8888615d83565b6142d89190615e1b565b6142e29085615dfc565b905060006142fb63ffffffff871664e8d4a51000615dfc565b9050826143088284615d83565b6143129190615d83565b98975050505050505050565b600080614329614718565b90506000811361434f576040516321ea67b360e11b815260048101829052602401610c03565b60006143596146bc565b9050600082825a61436a8b8b615d83565b6143749190615e1b565b61437e9088615dfc565b6143889190615d83565b61439a90670de0b6b3a7640000615dfc565b6143a49190615de8565b905060006143bd63ffffffff881664e8d4a51000615dfc565b90506143d5816b033b2e3c9fd0803ce8000000615e1b565b8211156143f55760405163e80fa38160e01b815260040160405180910390fd5b6143ff8183615d83565b9998505050505050505050565b6000613bef83836147e7565b600081815260018301602052604081205461445f57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611355565b506000611355565b600082600001828154811061447e5761447e615f22565b9060005260206000200154905092915050565b61449a896148da565b6144e65760405162461bcd60e51b815260206004820152601a60248201527f7075626c6963206b6579206973206e6f74206f6e2063757276650000000000006044820152606401610c03565b6144ef886148da565b61453b5760405162461bcd60e51b815260206004820152601560248201527f67616d6d61206973206e6f74206f6e20637572766500000000000000000000006044820152606401610c03565b614544836148da565b6145905760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e2063757276650000006044820152606401610c03565b614599826148da565b6145e55760405162461bcd60e51b815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e206375727665000000006044820152606401610c03565b6145f1878a88876149b3565b61463d5760405162461bcd60e51b815260206004820152601960248201527f6164647228632a706b2b732a6729213d5f755769746e657373000000000000006044820152606401610c03565b60006146498a87614ad6565b9050600061465c898b878b868989614b3a565b9050600061466d838d8d8a86614c5a565b9050808a146146ae5760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610c03565b505050505050505050505050565b60004661a4b18114806146d1575062066eed81145b1561471057606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561404157600080fd5b600091505090565b600d5460035460408051633fabe5a360e21b81529051600093670100000000000000900463ffffffff169283151592859283926001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b15801561477a57600080fd5b505afa15801561478e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147b29190615873565b5094509092508491505080156147d657506147cd8242615e1b565b8463ffffffff16105b15613c3e5750601154949350505050565b600081815260018301602052604081205480156148d057600061480b600183615e1b565b855490915060009061481f90600190615e1b565b905081811461488457600086600001828154811061483f5761483f615f22565b906000526020600020015490508087600001848154811061486257614862615f22565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061489557614895615f0c565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611355565b6000915050611355565b80516000906401000003d019116149335760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420782d6f7264696e61746500000000000000000000000000006044820152606401610c03565b60208201516401000003d0191161498c5760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420792d6f7264696e61746500000000000000000000000000006044820152606401610c03565b60208201516401000003d0199080096149ac8360005b6020020151614c9a565b1492915050565b60006001600160a01b0382166149f95760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b6044820152606401610c03565b602084015160009060011615614a1057601c614a13565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe19918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa158015614aae573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b614ade6151c8565b614b0b60018484604051602001614af793929190615a18565b604051602081830303815290604052614cbe565b90505b614b17816148da565b611355578051604080516020810192909252614b339101614af7565b9050614b0e565b614b426151c8565b825186516401000003d0199081900691061415614ba15760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e637400006044820152606401610c03565b614bac878988614d0c565b614bf85760405162461bcd60e51b815260206004820152601660248201527f4669727374206d756c20636865636b206661696c6564000000000000000000006044820152606401610c03565b614c03848685614d0c565b614c4f5760405162461bcd60e51b815260206004820152601760248201527f5365636f6e64206d756c20636865636b206661696c65640000000000000000006044820152606401610c03565b614312868484614e34565b600060028686868587604051602001614c78969594939291906159b9565b60408051601f1981840301815291905280516020909101209695505050505050565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614cc66151c8565b614ccf82614efb565b8152614ce4614cdf8260006149a2565b614f36565b602082018190526002900660011415612386576020810180516401000003d019039052919050565b600082614d495760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b6044820152606401610c03565b83516020850151600090614d5f90600290615ecc565b15614d6b57601c614d6e565b601b5b9050600070014551231950b75fc4402da1732fc9bebe198387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa158015614de0573d6000803e3d6000fd5b505050602060405103519050600086604051602001614dff91906159a7565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614e3c6151c8565b835160208086015185519186015160009384938493614e5d93909190614f56565b919450925090506401000003d019858209600114614ebd5760405162461bcd60e51b815260206004820152601960248201527f696e765a206d75737420626520696e7665727365206f66207a000000000000006044820152606401610c03565b60405180604001604052806401000003d01980614edc57614edc615ef6565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d019811061238657604080516020808201939093528151808203840181529082019091528051910120614f03565b6000611355826002614f4f6401000003d0196001615d83565b901c615036565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614f96838385856150d8565b9098509050614fa788828e886150fc565b9098509050614fb888828c876150fc565b90985090506000614fcb8d878b856150fc565b9098509050614fdc888286866150d8565b9098509050614fed88828e896150fc565b9098509050818114615022576401000003d019818a0998506401000003d01982890997506401000003d0198183099650615026565b8196505b5050505050509450945094915050565b6000806150416151e6565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a0820152615073615204565b60208160c0846005600019fa9250826150ce5760405162461bcd60e51b815260206004820152601260248201527f6269674d6f64457870206661696c7572652100000000000000000000000000006044820152606401610c03565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b82805482825590600052602060002090810192821561519a579160200282015b8281111561519a57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190615165565b506151a6929150615222565b5090565b5080546000825590600052602060002090810190610c0c9190615222565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b808211156151a65760008155600101615223565b803561238681615f4e565b806040810183101561135557600080fd5b600082601f83011261526457600080fd5b61526c615cec565b80838560408601111561527e57600080fd5b60005b60028110156152a0578135845260209384019390910190600101615281565b509095945050505050565b600082601f8301126152bc57600080fd5b81356001600160401b03808211156152d6576152d6615f38565b604051601f8301601f19908116603f011681019082821181831017156152fe576152fe615f38565b8160405283815286602085880101111561531757600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060c0828403121561534957600080fd5b615351615d14565b905081356001600160401b03808216821461536b57600080fd5b81835260208401356020840152615384604085016153ea565b6040840152615395606085016153ea565b60608401526153a660808501615237565b608084015260a08401359150808211156153bf57600080fd5b506153cc848285016152ab565b60a08301525092915050565b803561ffff8116811461238657600080fd5b803563ffffffff8116811461238657600080fd5b805169ffffffffffffffffffff8116811461238657600080fd5b80356001600160601b038116811461238657600080fd5b60006020828403121561544157600080fd5b8135613bef81615f4e565b6000806040838503121561545f57600080fd5b823561546a81615f4e565b915061547860208401615418565b90509250929050565b6000806040838503121561549457600080fd5b823561549f81615f4e565b915060208301356154af81615f4e565b809150509250929050565b600080606083850312156154cd57600080fd5b82356154d881615f4e565b91506154788460208501615242565b600080600080606085870312156154fd57600080fd5b843561550881615f4e565b93506020850135925060408501356001600160401b038082111561552b57600080fd5b818701915087601f83011261553f57600080fd5b81358181111561554e57600080fd5b88602082850101111561556057600080fd5b95989497505060200194505050565b60006040828403121561558157600080fd5b613bef8383615242565b60006040828403121561559d57600080fd5b613bef8383615253565b6000602082840312156155b957600080fd5b8151613bef81615f63565b6000602082840312156155d657600080fd5b5035919050565b6000602082840312156155ef57600080fd5b5051919050565b60006020828403121561560857600080fd5b604051602081018181106001600160401b038211171561562a5761562a615f38565b604052823561563881615f63565b81529392505050565b6000808284036101c081121561565657600080fd5b6101a08082121561566657600080fd5b61566e615d36565b915061567a8686615253565b82526156898660408701615253565b60208301526080850135604083015260a0850135606083015260c085013560808301526156b860e08601615237565b60a08301526101006156cc87828801615253565b60c08401526156df876101408801615253565b60e0840152610180860135908301529092508301356001600160401b0381111561570857600080fd5b61571485828601615337565b9150509250929050565b60006020828403121561573057600080fd5b81356001600160401b0381111561574657600080fd5b820160c08185031215613bef57600080fd5b60006020828403121561576a57600080fd5b613bef826153d8565b60008060008060008086880360e081121561578d57600080fd5b615796886153d8565b96506157a4602089016153ea565b95506157b2604089016153ea565b94506157c0606089016153ea565b9350608088013592506040609f19820112156157db57600080fd5b506157e4615cec565b6157f060a089016153ea565b81526157fe60c089016153ea565b6020820152809150509295509295509295565b6000806040838503121561582457600080fd5b8235915060208301356154af81615f4e565b6000806040838503121561584957600080fd5b50508035926020909101359150565b60006020828403121561586a57600080fd5b613bef826153ea565b600080600080600060a0868803121561588b57600080fd5b615894866153fe565b94506020860151935060408601519250606086015191506158b7608087016153fe565b90509295509295909350565b600081518084526020808501945080840160005b838110156158fc5781516001600160a01b0316875295820195908201906001016158d7565b509495945050505050565b8060005b6002811015610e6b57815184526020938401939091019060010161590b565b600081518084526020808501945080840160005b838110156158fc5781518752958201959082019060010161593e565b6000815180845260005b8181101561598057602081850181015186830182015201615964565b81811115615992576000602083870101525b50601f01601f19169290920160200192915050565b6159b18183615907565b604001919050565b8681526159c96020820187615907565b6159d66060820186615907565b6159e360a0820185615907565b6159f060e0820184615907565b60609190911b6bffffffffffffffffffffffff19166101208201526101340195945050505050565b838152615a286020820184615907565b606081019190915260800192915050565b604081016113558284615907565b602081526000613bef602083018461592a565b602081526000613bef602083018461595a565b6020815260ff8251166020820152602082015160408201526001600160a01b0360408301511660608201526000606083015160c06080840152615ab360e08401826158c3565b905060808401516001600160601b0380821660a08601528060a08701511660c086015250508091505092915050565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b81811015615b3357845183529383019391830191600101615b17565b509098975050505050505050565b82815260608101613bef6020830184615907565b828152604060208201526000613c3e604083018461592a565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a083015261431260c083018461595a565b878152866020820152856040820152600063ffffffff80871660608401528086166080840152506001600160a01b03841660a083015260e060c08301526143ff60e083018461595a565b8781526001600160401b0387166020820152856040820152600063ffffffff80871660608401528086166080840152506001600160a01b03841660a083015260e060c08301526143ff60e083018461595a565b60006001600160601b0380881683528087166020840152506001600160401b03851660408301526001600160a01b038416606083015260a06080830152615c9460a08301846158c3565b979650505050505050565b6000808335601e19843603018112615cb657600080fd5b8301803591506001600160401b03821115615cd057600080fd5b602001915036819003821315615ce557600080fd5b9250929050565b604080519081016001600160401b0381118282101715615d0e57615d0e615f38565b60405290565b60405160c081016001600160401b0381118282101715615d0e57615d0e615f38565b60405161012081016001600160401b0381118282101715615d0e57615d0e615f38565b60008085851115615d6957600080fd5b83861115615d7657600080fd5b5050820193919092039150565b60008219821115615d9657615d96615ee0565b500190565b60006001600160401b03808316818516808303821115615dbd57615dbd615ee0565b01949350505050565b60006001600160601b03808316818516808303821115615dbd57615dbd615ee0565b600082615df757615df7615ef6565b500490565b6000816000190483118215151615615e1657615e16615ee0565b500290565b600082821015615e2d57615e2d615ee0565b500390565b60006001600160601b0383811690831681811015615e5257615e52615ee0565b039392505050565b6001600160e01b03198135818116916004851015615e825780818660040360031b1b83161692505b505092915050565b6000600019821415615e9e57615e9e615ee0565b5060010190565b60006001600160401b0380831681811415615ec257615ec2615ee0565b6001019392505050565b600082615edb57615edb615ef6565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610c0c57600080fd5b8015158114610c0c57600080fdfea164736f6c6343000806000a", } var VRFCoordinatorV2PlusABI = VRFCoordinatorV2PlusMetaData.ABI diff --git a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 97b336b1885..55039c279d5 100644 --- a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -59,23 +59,23 @@ solidity_vrf_v08_verifier_wrapper: ../../contracts/solc/v0.8.6/VRFTestHelper.abi solidity_vrf_verifier_wrapper: ../../contracts/solc/v0.6/VRFTestHelper.abi ../../contracts/solc/v0.6/VRFTestHelper.bin 44c2b67d8d2990ab580453deb29d63508c6147a3dc49908a1db563bef06e6474 solidity_vrf_wrapper: ../../contracts/solc/v0.6/VRF.abi ../../contracts/solc/v0.6/VRF.bin 04ede5b83c06ba5b76ef99c081c72928007d8a7aaefcf21449a46a07cbd4bfc2 streams_lookup_compatible_interface: ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface.abi ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface.bin feb92cc666df21ea04ab9d7a588a513847b01b2f66fc167d06ab28ef2b17e015 -streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/StreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/StreamsLookupUpkeep.bin 4999afb752411696ec59210609b6deef45f519b18bd5e1450688062b3f7d0951 +streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/StreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/StreamsLookupUpkeep.bin b1a598963cacac51ed4706538d0f142bdc0d94b9a4b13e2d402131cdf05c9bcf test_api_consumer_wrapper: ../../contracts/solc/v0.6/TestAPIConsumer.abi ../../contracts/solc/v0.6/TestAPIConsumer.bin ed10893cb18894c18e275302329c955f14ea2de37ee044f84aa1e067ac5ea71e -trusted_blockhash_store: ../../contracts/solc/v0.8.6/TrustedBlockhashStore.abi ../../contracts/solc/v0.8.6/TrustedBlockhashStore.bin a85d2899892aa9fd73fc99852ccba52c3983375113580673e6c5d655bfa79909 +trusted_blockhash_store: ../../contracts/solc/v0.8.6/TrustedBlockhashStore.abi ../../contracts/solc/v0.8.6/TrustedBlockhashStore.bin 34e71c5dc94f50e21f2bef76b0daa5821634655ca3722ce1204ce43cca1b2e19 type_and_version_interface_wrapper: ../../contracts/solc/v0.8.6/TypeAndVersionInterface.abi ../../contracts/solc/v0.8.6/TypeAndVersionInterface.bin bc9c3a6e73e3ebd5b58754df0deeb3b33f4bb404d5709bb904aed51d32f4b45e upkeep_counter_wrapper: ../../contracts/solc/v0.7/UpkeepCounter.abi ../../contracts/solc/v0.7/UpkeepCounter.bin 901961ebf18906febc1c350f02da85c7ea1c2a68da70cfd94efa27c837a48663 upkeep_perform_counter_restrictive_wrapper: ../../contracts/solc/v0.7/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.7/UpkeepPerformCounterRestrictive.bin 8975a058fba528e16d8414dc6f13946d17a145fcbc66cf25a32449b6fe1ce878 upkeep_transcoder: ../../contracts/solc/v0.8.6/UpkeepTranscoder.abi ../../contracts/solc/v0.8.6/UpkeepTranscoder.bin 336c92a981597be26508455f81a908a0784a817b129a59686c5b2c4afcba730a -verifiable_load_log_trigger_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep.bin 9d6f38552015d190c32671d785339716803b3b97223ea388e7a699d7f707494f -verifiable_load_streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep.bin 4c02260ab1ab687536e13f417c048ee387c56c64d22a1b35ccd9bbc56f13ce50 +verifiable_load_log_trigger_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep.bin 99b6ac1c38e939af0772c6ad8f43bb6788007ab4da0ac77058ef2b4357bdecda +verifiable_load_streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep.bin 785f68c44bfff070505eaa65e38a1af94046e5f9afc1189bcf2c8cfcd1102d66 verifiable_load_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadUpkeep.bin a3e02c43756ea91e7ce4b81e48c11648f1d12f6663c236780147e41dfa36ebee vrf_consumer_v2: ../../contracts/solc/v0.8.6/VRFConsumerV2.abi ../../contracts/solc/v0.8.6/VRFConsumerV2.bin 9ef258bf8e9f8d880fd229ceb145593d91e24fc89366baa0bf19169c5787d15f vrf_consumer_v2_plus_upgradeable_example: ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample.bin 3155c611e4d6882e9324b6e975033b31356776ea8b031ca63d63da37589d583b vrf_consumer_v2_upgradeable_example: ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample.bin f1790a9a2f2a04c730593e483459709cb89e897f8a19d7a3ac0cfe6a97265e6e vrf_coordinator_mock: ../../contracts/solc/v0.8.6/VRFCoordinatorMock.abi ../../contracts/solc/v0.8.6/VRFCoordinatorMock.bin 5c495cf8df1f46d8736b9150cdf174cce358cb8352f60f0d5bb9581e23920501 -vrf_coordinator_v2: ../../contracts/solc/v0.8.6/VRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2.bin 75c87cf1624a401ac6303df9c8e04896aa8a53849e8b0c3d7340a9d089ef6d4b +vrf_coordinator_v2: ../../contracts/solc/v0.8.6/VRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2.bin 906e8155db28513c64c6f828d5b8eaf586b873de4369c77c0a19b6c5adf623c1 vrf_coordinator_v2_plus_v2_example: ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example.bin 50d881ecf2551c0e56b84cb932f068b703b38b00c73eb05d4e4b80754ecf6b6d -vrf_coordinator_v2plus: ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus.bin f80932e5292602d0b3adbde425f9c0774926f786c12ad020463e4f8e025426d3 +vrf_coordinator_v2plus: ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus.bin e4409bbe361258273458a5c99408b3d7f0cc57a2560dee91c0596cc6d6f738be vrf_external_sub_owner_example: ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample.bin 14f888eb313930b50233a6f01ea31eba0206b7f41a41f6311670da8bb8a26963 vrf_load_test_external_sub_owner: ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner.abi ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner.bin 2097faa70265e420036cc8a3efb1f1e0836ad2d7323b295b9a26a125dbbe6c7d vrf_load_test_ownerless_consumer: ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer.abi ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer.bin 74f914843cbc70b9c3079c3e1c709382ce415225e8bb40113e7ac018bfcb0f5c diff --git a/core/gethwrappers/go_generate.go b/core/gethwrappers/go_generate.go index cbcc1a76627..6471b2a2636 100644 --- a/core/gethwrappers/go_generate.go +++ b/core/gethwrappers/go_generate.go @@ -107,6 +107,7 @@ package gethwrappers // VRF V2Plus //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus.bin BatchVRFCoordinatorV2Plus batch_vrf_coordinator_v2plus +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/TrustedBlockhashStore.abi ../../contracts/solc/v0.8.6/TrustedBlockhashStore.bin TrustedBlockhashStore trusted_blockhash_store //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample.bin VRFV2PlusConsumerExample vrfv2plus_consumer_example //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus.bin VRFCoordinatorV2Plus vrf_coordinator_v2plus //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusWrapper.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapper.bin VRFV2PlusWrapper vrfv2plus_wrapper diff --git a/core/gethwrappers/llo-feeds/generated/fee_manager/fee_manager.go b/core/gethwrappers/llo-feeds/generated/fee_manager/fee_manager.go index d8fdd50e6ed..43f2844adc7 100644 --- a/core/gethwrappers/llo-feeds/generated/fee_manager/fee_manager.go +++ b/core/gethwrappers/llo-feeds/generated/fee_manager/fee_manager.go @@ -50,8 +50,8 @@ type IRewardManagerFeePayment struct { } var FeeManagerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_linkAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_nativeAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_proxyAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_rewardManagerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ExpiredReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDeposit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDiscount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidQuote\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReceivingAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSurcharge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroDeficit\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structCommon.Asset\",\"name\":\"fee\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structCommon.Asset\",\"name\":\"reward\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"appliedDiscount\",\"type\":\"uint256\"}],\"name\":\"DiscountApplied\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"indexed\":false,\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"rewards\",\"type\":\"tuple[]\"}],\"name\":\"InsufficientLink\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"linkQuantity\",\"type\":\"uint256\"}],\"name\":\"LinkDeficitCleared\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newSurcharge\",\"type\":\"uint64\"}],\"name\":\"NativeSurchargeUpdated\",\"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\":\"subscriber\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"discount\",\"type\":\"uint64\"}],\"name\":\"SubscriberDiscountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"Withdraw\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteAddress\",\"type\":\"address\"}],\"internalType\":\"structIFeeManager.Quote\",\"name\":\"quote\",\"type\":\"tuple\"}],\"name\":\"getFeeAndReward\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structCommon.Asset\",\"name\":\"\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structCommon.Asset\",\"name\":\"\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkAvailableForPayment\",\"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\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"payLinkDeficit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"}],\"name\":\"processFee\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"payloads\",\"type\":\"bytes[]\"},{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"}],\"name\":\"processFeeBulk\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_linkDeficit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_nativeSurcharge\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_subscriberDiscounts\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"rewardRecipientAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setFeeRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"surcharge\",\"type\":\"uint64\"}],\"name\":\"setNativeSurcharge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"discount\",\"type\":\"uint64\"}],\"name\":\"updateSubscriberDiscount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x6101006040523480156200001257600080fd5b50604051620034d8380380620034d8833981016040819052620000359162000288565b33806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620001c0565b5050506001600160a01b0384161580620000e057506001600160a01b038316155b80620000f357506001600160a01b038216155b806200010657506001600160a01b038116155b15620001255760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b03848116608081905284821660a05283821660c05290821660e081905260405163095ea7b360e01b81526004810191909152600019602482015263095ea7b3906044016020604051808303816000875af11580156200018f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001b59190620002e5565b505050505062000310565b336001600160a01b038216036200021a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200028357600080fd5b919050565b600080600080608085870312156200029f57600080fd5b620002aa856200026b565b9350620002ba602086016200026b565b9250620002ca604086016200026b565b9150620002da606086016200026b565b905092959194509250565b600060208284031215620002f857600080fd5b815180151581146200030957600080fd5b9392505050565b60805160a05160c05160e051613102620003d660003960008181611185015281816114a601528181611ce20152611f3001526000818161061a0152818161124501526113ec015260008181610a7a01528181610ad101528181610d8801528181610e9701528181611c080152611cb101526000818161079301528181610a9f01528181610b2c01528181610c7601528181610ce501528181610d2401528181610e4001528181610fd70152818161134f015281816118830152611da301526131026000f3fe60806040526004361061010e5760003560e01c806387d6d843116100a5578063d09dc33911610074578063f1387e1611610059578063f1387e1614610382578063f2fde38b14610395578063f65df962146103b557600080fd5b8063d09dc3391461034d578063e389d9a41461036257600080fd5b806387d6d8431461024f5780638da5cb5b1461028d578063c541cbde146102c2578063ce7817d11461032d57600080fd5b806332f5f746116100e157806332f5f746146101f157806340d7f78e14610207578063505380941461021a57806379ba50971461023a57600080fd5b8063013f542b1461011357806301ffc9a714610153578063181f5a77146101835780631d4d84a2146101cf575b600080fd5b34801561011f57600080fd5b5061014061012e366004612532565b60036020526000908152604090205481565b6040519081526020015b60405180910390f35b34801561015f57600080fd5b5061017361016e36600461254b565b6103d5565b604051901515815260200161014a565b34801561018f57600080fd5b50604080518082018252601081527f4665654d616e6167657220312e302e30000000000000000000000000000000006020820152905161014a91906125b1565b3480156101db57600080fd5b506101ef6101ea36600461264a565b61046e565b005b3480156101fd57600080fd5b5061014060045481565b6101ef610215366004612695565b610602565b34801561022657600080fd5b506101ef61023536600461272d565b610845565b34801561024657600080fd5b506101ef6108df565b34801561025b57600080fd5b5061014061026a366004612748565b600260209081526000938452604080852082529284528284209052825290205481565b34801561029957600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161014a565b3480156102ce57600080fd5b506102e26102dd3660046128b4565b6109e1565b60408051845173ffffffffffffffffffffffffffffffffffffffff9081168252602095860151868301528451169181019190915292909101516060830152608082015260a00161014a565b34801561033957600080fd5b506101ef610348366004612955565b610dea565b34801561035957600080fd5b50610140610fa6565b34801561036e57600080fd5b506101ef61037d366004612532565b61105c565b6101ef6103903660046129a6565b61122d565b3480156103a157600080fd5b506101ef6103b0366004612a08565b6113c0565b3480156103c157600080fd5b506101ef6103d0366004612a25565b6113d4565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167ff1387e1600000000000000000000000000000000000000000000000000000000148061046857507fffffffff0000000000000000000000000000000000000000000000000000000082167f40d7f78e00000000000000000000000000000000000000000000000000000000145b92915050565b61047661150d565b73ffffffffffffffffffffffffffffffffffffffff831661054b5760008273ffffffffffffffffffffffffffffffffffffffff168277ffffffffffffffffffffffffffffffffffffffffffffffff1660405160006040518083038185875af1925050503d8060008114610505576040519150601f19603f3d011682016040523d82523d6000602084013e61050a565b606091505b5050905080610545576040517fef2af20100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b61058673ffffffffffffffffffffffffffffffffffffffff84168377ffffffffffffffffffffffffffffffffffffffffffffffff8416611590565b6040805133815273ffffffffffffffffffffffffffffffffffffffff848116602083015285168183015277ffffffffffffffffffffffffffffffffffffffffffffffff8316606082015290517f7ff78a71698bdb18dcca96f52ab25e0a1b146fb6a49adf8e6845299e49021f299181900360800190a15b505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610671576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008267ffffffffffffffff81111561068c5761068c61277f565b6040519080825280602002602001820160405280156106c557816020015b6106b26124a5565b8152602001906001900390816106aa5790505b5090506000806000805b8681101561080e5760008060006107098b8b868181106106f1576106f1612aa4565b90506020028101906107039190612ad3565b8b611664565b92509250925082602001516000146107fa5760405180608001604052808c8c8781811061073857610738612aa4565b905060200281019061074a9190612ad3565b61075391612b3f565b81526020018481526020018381526020018281525088868061077490612baa565b97508151811061078657610786612aa4565b60200260200101819052507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff16036107f3578660010196506107fa565b8560010195505b5050508061080790612baa565b90506106cf565b508215158061081c57508115155b156108325761082d8585858561179e565b61083c565b61083c8534611fb2565b50505050505050565b61084d61150d565b670de0b6b3a764000067ffffffffffffffff82161115610899576040517f05e8ac2900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff811660048190556040519081527f08f7c0d17932ddb8523bc06754d42ff19ebc77d76a8b9bfde02c28ab1ed3d6399060200160405180910390a150565b60015473ffffffffffffffffffffffffffffffffffffffff163314610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6040805180820182526000808252602080830182905283518085018552828152808201839052845180860186528381528083018490528551808701909652838652918501839052929382610a3488612be2565b90507fffff000000000000000000000000000000000000000000000000000000000000808216908101610acf57505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811683527f0000000000000000000000000000000000000000000000000000000000000000168152909350915060009050610de1565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16886000015173ffffffffffffffffffffffffffffffffffffffff1614158015610b7f57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16886000015173ffffffffffffffffffffffffffffffffffffffff1614155b15610bb6576040517ff861803000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060008b806020019051810190610bcf9190612c3b565b77ffffffffffffffffffffffffffffffffffffffffffffffff92831698509116955063ffffffff1693505050428210159050610c37576040517fb6c405f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808e16600090815260026020908152604080832089845282528083208f51851684529091529020547f00000000000000000000000000000000000000000000000000000000000000009091168752610cc7610caf82670de0b6b3a7640000612cad565b610cb99086612cc0565b670de0b6b3a7640000611fff565b60208801528b5173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116911603610d555773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016885260208088015190890152610dd2565b600454600090610d7190610caf90670de0b6b3a7640000612cfd565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168a529050610dcb610dc183670de0b6b3a7640000612cad565b610cb99083612cc0565b60208a0152505b96995094975094955050505050505b93509350939050565b610df261150d565b670de0b6b3a764000067ffffffffffffffff82161115610e3e576040517f997ea36000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610ee657507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15610f1d576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff848116600081815260026020908152604080832088845282528083209487168084529482529182902067ffffffffffffffff86169081905582519485529084015285927f5eba5a8afa39780f0f99b6cbeb95f3da6a7040ca00abd46bdc91a0a060134139910160405180910390a350505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611033573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110579190612d10565b905090565b61106461150d565b600081815260036020526040812054908190036110ad576040517f03aad31200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600360205260408082208290558051600180825281830190925290816020015b60408051808201909152600080825260208201528152602001906001900390816110d257905050905060405180604001604052808481526020018377ffffffffffffffffffffffffffffffffffffffffffffffff168152508160008151811061113d5761113d612aa4565b60209081029190910101526040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b0d9fa19906111bc9084903090600401612d89565b600060405180830381600087803b1580156111d657600080fd5b505af11580156111ea573d6000803e3d6000fd5b50505050827f843f0b103e50b42b08f9d30f12f961845a6d02623730872e24644899c0dd98958360405161122091815260200190565b60405180910390a2505050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461129c576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060006112ac868686611664565b92509250925082602001516000036112d0576112c88434611fb2565b505050505050565b604080516001808252818301909252600091816020015b6112ef6124a5565b8152602001906001900390816112e757505060408051608081019091529091508061131a888a612b3f565b8152602001858152602001848152602001838152508160008151811061134257611342612aa4565b60200260200101819052507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff16036113b25761082d85826001600061179e565b61083c85826000600161179e565b6113c861150d565b6113d181612037565b50565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614801590611432575060005473ffffffffffffffffffffffffffffffffffffffff163314155b15611469576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f14060f2300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906314060f23906114df90869086908690600401612dc1565b600060405180830381600087803b1580156114f957600080fd5b505af115801561083c573d6000803e3d6000fd5b60005473ffffffffffffffffffffffffffffffffffffffff16331461158e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161095c565b565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526105fd9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261212c565b6040805180820190915260008082526020820152604080518082019091526000808252602082015260003073ffffffffffffffffffffffffffffffffffffffff8516036116dd576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006116eb86880188612eaf565b9150506000816116fa90612be2565b6040805160208101909152600081529091507e010000000000000000000000000000000000000000000000000000000000007fffff000000000000000000000000000000000000000000000000000000000000831614611781576000611762898b018b612f73565b955050505050508080602001905181019061177d919061303b565b9150505b61178c8784836109e1565b95509550955050505093509350939050565b60008267ffffffffffffffff8111156117b9576117b961277f565b6040519080825280602002602001820160405280156117fe57816020015b60408051808201909152600080825260208201528152602001906001900390816117d75790505b50905060008267ffffffffffffffff81111561181c5761181c61277f565b60405190808252806020026020018201604052801561186157816020015b604080518082019091526000808252602082015281526020019060019003908161183a5790505b509050600080808080611874888a612cfd565b905060005b81811015611bc3577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168b82815181106118ca576118ca612aa4565b6020026020010151602001516000015173ffffffffffffffffffffffffffffffffffffffff16036119905760405180604001604052808c838151811061191257611912612aa4565b60200260200101516000015181526020018c838151811061193557611935612aa4565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff1681525088858061196e90612baa565b96508151811061198057611980612aa4565b6020026020010181905250611a85565b60405180604001604052808c83815181106119ad576119ad612aa4565b60200260200101516000015181526020018c83815181106119d0576119d0612aa4565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16815250878480611a0990612baa565b955081518110611a1b57611a1b612aa4565b60200260200101819052508a8181518110611a3857611a38612aa4565b6020026020010151602001516020015186611a539190612cfd565b95508a8181518110611a6757611a67612aa4565b6020026020010151604001516020015185611a829190612cfd565b94505b8a8181518110611a9757611a97612aa4565b602002602001015160600151600014611bb3578b73ffffffffffffffffffffffffffffffffffffffff168b8281518110611ad357611ad3612aa4565b6020026020010151600001517f88b15eb682210089cddf967648e2cb2a4535aeadc8f8f36050922e33c04e71258d8481518110611b1257611b12612aa4565b6020026020010151602001518e8581518110611b3057611b30612aa4565b6020026020010151604001518f8681518110611b4e57611b4e612aa4565b602002602001015160600151604051611baa93929190835173ffffffffffffffffffffffffffffffffffffffff908116825260209485015185830152835116604082015291909201516060820152608081019190915260a00190565b60405180910390a35b611bbc81612baa565b9050611879565b5060003415611c915734861115611c06576040517fb2e532de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0876040518263ffffffff1660e01b81526004016000604051808303818588803b158015611c6e57600080fd5b505af1158015611c82573d6000803e3d6000fd5b50505050508534039050611cd9565b8515611cd957611cd973ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168d3089612238565b875115611d6e577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b0d9fa19898e6040518363ffffffff1660e01b8152600401611d3b929190612d89565b600060405180830381600087803b158015611d5557600080fd5b505af1158015611d69573d6000803e3d6000fd5b505050505b865115611f9a576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611dff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e239190612d10565b851115611ef35760005b8751811015611eb657878181518110611e4857611e48612aa4565b60200260200101516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16600360008a8481518110611e8457611e84612aa4565b60209081029190910181015151825281019190915260400160002080549091019055611eaf81612baa565b9050611e2d565b507ff52e5907b69d97c33392936c12d78b494463b78c5b72df50b4c497eee5720b6787604051611ee69190613069565b60405180910390a1611f9a565b6040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b0d9fa1990611f67908a903090600401612d89565b600060405180830381600087803b158015611f8157600080fd5b505af1158015611f95573d6000803e3d6000fd5b505050505b611fa48c82611fb2565b505050505050505050505050565b8015611ffb5760405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f193505050501580156105fd573d6000803e3d6000fd5b5050565b6000821561202d5781612013600185612cad565b61201d919061307c565b612028906001612cfd565b612030565b60005b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036120b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161095c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061218e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166122969092919063ffffffff16565b8051909150156105fd57808060200190518101906121ac91906130b7565b6105fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161095c565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526105459085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016115e2565b60606122a584846000856122ad565b949350505050565b60608247101561233f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161095c565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161236891906130d9565b60006040518083038185875af1925050503d80600081146123a5576040519150601f19603f3d011682016040523d82523d6000602084013e6123aa565b606091505b50915091506123bb878383876123c6565b979650505050505050565b6060831561245c5782516000036124555773ffffffffffffffffffffffffffffffffffffffff85163b612455576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161095c565b50816122a5565b6122a583838151156124715781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161095c91906125b1565b6040518060800160405280600080191681526020016124ed6040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b81526020016125256040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b8152602001600081525090565b60006020828403121561254457600080fd5b5035919050565b60006020828403121561255d57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461203057600080fd5b60005b838110156125a8578181015183820152602001612590565b50506000910152565b60208152600082518060208401526125d081604085016020870161258d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b73ffffffffffffffffffffffffffffffffffffffff811681146113d157600080fd5b77ffffffffffffffffffffffffffffffffffffffffffffffff811681146113d157600080fd5b60008060006060848603121561265f57600080fd5b833561266a81612602565b9250602084013561267a81612602565b9150604084013561268a81612624565b809150509250925092565b6000806000604084860312156126aa57600080fd5b833567ffffffffffffffff808211156126c257600080fd5b818601915086601f8301126126d657600080fd5b8135818111156126e557600080fd5b8760208260051b85010111156126fa57600080fd5b6020928301955093505084013561268a81612602565b803567ffffffffffffffff8116811461272857600080fd5b919050565b60006020828403121561273f57600080fd5b61203082612710565b60008060006060848603121561275d57600080fd5b833561276881612602565b925060208401359150604084013561268a81612602565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516020810167ffffffffffffffff811182821017156127d1576127d161277f565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561281e5761281e61277f565b604052919050565b600082601f83011261283757600080fd5b813567ffffffffffffffff8111156128515761285161277f565b61288260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016127d7565b81815284602083860101111561289757600080fd5b816020850160208301376000918101602001919091529392505050565b600080600083850360608112156128ca57600080fd5b84356128d581612602565b9350602085013567ffffffffffffffff8111156128f157600080fd5b6128fd87828801612826565b93505060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08201121561293057600080fd5b506129396127ae565b604085013561294781612602565b815292959194509192509050565b6000806000806080858703121561296b57600080fd5b843561297681612602565b935060208501359250604085013561298d81612602565b915061299b60608601612710565b905092959194509250565b6000806000604084860312156129bb57600080fd5b833567ffffffffffffffff808211156129d357600080fd5b818601915086601f8301126129e757600080fd5b8135818111156129f657600080fd5b8760208285010111156126fa57600080fd5b600060208284031215612a1a57600080fd5b813561203081612602565b600080600060408486031215612a3a57600080fd5b83359250602084013567ffffffffffffffff80821115612a5957600080fd5b818601915086601f830112612a6d57600080fd5b813581811115612a7c57600080fd5b8760208260061b8501011115612a9157600080fd5b6020830194508093505050509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612b0857600080fd5b83018035915067ffffffffffffffff821115612b2357600080fd5b602001915036819003821315612b3857600080fd5b9250929050565b80356020831015610468577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612bdb57612bdb612b7b565b5060010190565b80516020808301519190811015612c21577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b805163ffffffff8116811461272857600080fd5b60008060008060008060c08789031215612c5457600080fd5b86519550612c6460208801612c27565b9450612c7260408801612c27565b93506060870151612c8281612624565b6080880151909350612c9381612624565b9150612ca160a08801612c27565b90509295509295509295565b8181038181111561046857610468612b7b565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612cf857612cf8612b7b565b500290565b8082018082111561046857610468612b7b565b600060208284031215612d2257600080fd5b5051919050565b600081518084526020808501945080840160005b83811015612d7e5781518051885283015177ffffffffffffffffffffffffffffffffffffffffffffffff168388015260409096019590820190600101612d3d565b509495945050505050565b604081526000612d9c6040830185612d29565b905073ffffffffffffffffffffffffffffffffffffffff831660208301529392505050565b8381526040602080830182905282820184905260009190859060608501845b87811015612e34578335612df381612602565b73ffffffffffffffffffffffffffffffffffffffff16825267ffffffffffffffff612e1f858501612710565b16828401529284019290840190600101612de0565b5098975050505050505050565b600082601f830112612e5257600080fd5b6040516060810181811067ffffffffffffffff82111715612e7557612e7561277f565b604052806060840185811115612e8a57600080fd5b845b81811015612ea4578035835260209283019201612e8c565b509195945050505050565b60008060808385031215612ec257600080fd5b612ecc8484612e41565b9150606083013567ffffffffffffffff811115612ee857600080fd5b612ef485828601612826565b9150509250929050565b600082601f830112612f0f57600080fd5b8135602067ffffffffffffffff821115612f2b57612f2b61277f565b8160051b612f3a8282016127d7565b9283528481018201928281019087851115612f5457600080fd5b83870192505b848310156123bb57823582529183019190830190612f5a565b6000806000806000806101008789031215612f8d57600080fd5b612f978888612e41565b9550606087013567ffffffffffffffff80821115612fb457600080fd5b612fc08a838b01612826565b96506080890135915080821115612fd657600080fd5b612fe28a838b01612efe565b955060a0890135915080821115612ff857600080fd5b6130048a838b01612efe565b945060c0890135935060e089013591508082111561302157600080fd5b5061302e89828a01612826565b9150509295509295509295565b60006020828403121561304d57600080fd5b6130556127ae565b825161306081612602565b81529392505050565b6020815260006120306020830184612d29565b6000826130b2577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000602082840312156130c957600080fd5b8151801515811461203057600080fd5b600082516130eb81846020870161258d565b919091019291505056fea164736f6c6343000810000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_linkAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_nativeAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_proxyAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_rewardManagerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ExpiredReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDeposit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDiscount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidQuote\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReceivingAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSurcharge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroDeficit\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structCommon.Asset\",\"name\":\"fee\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structCommon.Asset\",\"name\":\"reward\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"appliedDiscount\",\"type\":\"uint256\"}],\"name\":\"DiscountApplied\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"indexed\":false,\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"rewards\",\"type\":\"tuple[]\"}],\"name\":\"InsufficientLink\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"linkQuantity\",\"type\":\"uint256\"}],\"name\":\"LinkDeficitCleared\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newSurcharge\",\"type\":\"uint64\"}],\"name\":\"NativeSurchargeUpdated\",\"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\":\"subscriber\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"discount\",\"type\":\"uint64\"}],\"name\":\"SubscriberDiscountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"Withdraw\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteAddress\",\"type\":\"address\"}],\"internalType\":\"structIFeeManager.Quote\",\"name\":\"quote\",\"type\":\"tuple\"}],\"name\":\"getFeeAndReward\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structCommon.Asset\",\"name\":\"\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structCommon.Asset\",\"name\":\"\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_linkAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_nativeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_proxyAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_rewardManager\",\"outputs\":[{\"internalType\":\"contractIRewardManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkAvailableForPayment\",\"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\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"payLinkDeficit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"}],\"name\":\"processFee\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"payloads\",\"type\":\"bytes[]\"},{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"}],\"name\":\"processFeeBulk\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_linkDeficit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_nativeSurcharge\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_subscriberDiscounts\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"rewardRecipientAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setFeeRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"surcharge\",\"type\":\"uint64\"}],\"name\":\"setNativeSurcharge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"discount\",\"type\":\"uint64\"}],\"name\":\"updateSubscriberDiscount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x6101006040523480156200001257600080fd5b506040516200363b3803806200363b833981016040819052620000359162000288565b33806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620001c0565b5050506001600160a01b0384161580620000e057506001600160a01b038316155b80620000f357506001600160a01b038216155b806200010657506001600160a01b038116155b15620001255760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b03848116608081905284821660a05283821660c05290821660e081905260405163095ea7b360e01b81526004810191909152600019602482015263095ea7b3906044016020604051808303816000875af11580156200018f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001b59190620002e5565b505050505062000310565b336001600160a01b038216036200021a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200028357600080fd5b919050565b600080600080608085870312156200029f57600080fd5b620002aa856200026b565b9350620002ba602086016200026b565b9250620002ca604086016200026b565b9150620002da606086016200026b565b905092959194509250565b600060208284031215620002f857600080fd5b815180151581146200030957600080fd5b9392505050565b60805160a05160c05160e051613249620003f260003960008181610275015281816112cc015281816115ed01528181611e290152612077015260008181610335015281816107610152818161138c015261153301526000818161030101528181610bc101528181610c1801528181610ecf01528181610fde01528181611d4f0152611df80152600081816104a7015281816108da01528181610be601528181610c7301528181610dbd01528181610e2c01528181610e6b01528181610f870152818161111e01528181611496015281816119ca0152611eea01526132496000f3fe60806040526004361061016a5760003560e01c806379ba5097116100cb578063d09dc3391161007f578063f1387e1611610059578063f1387e16146104c9578063f2fde38b146104dc578063f65df962146104fc57600080fd5b8063d09dc33914610460578063e389d9a414610475578063ea4b861b1461049557600080fd5b80638da5cb5b116100b05780638da5cb5b146103aa578063c541cbde146103d5578063ce7817d11461044057600080fd5b806379ba50971461035757806387d6d8431461036c57600080fd5b80633aa5ac0711610122578063505380941161010757806350538094146102cf57806363878668146102ef5780636d1342cb1461032357600080fd5b80633aa5ac071461026357806340d7f78e146102bc57600080fd5b8063181f5a7711610153578063181f5a77146101df5780631d4d84a21461022b57806332f5f7461461024d57600080fd5b8063013f542b1461016f57806301ffc9a7146101af575b600080fd5b34801561017b57600080fd5b5061019c61018a366004612679565b60036020526000908152604090205481565b6040519081526020015b60405180910390f35b3480156101bb57600080fd5b506101cf6101ca366004612692565b61051c565b60405190151581526020016101a6565b3480156101eb57600080fd5b50604080518082018252601081527f4665654d616e6167657220312e302e3000000000000000000000000000000000602082015290516101a691906126f8565b34801561023757600080fd5b5061024b610246366004612791565b6105b5565b005b34801561025957600080fd5b5061019c60045481565b34801561026f57600080fd5b506102977f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a6565b61024b6102ca3660046127dc565b610749565b3480156102db57600080fd5b5061024b6102ea366004612874565b61098c565b3480156102fb57600080fd5b506102977f000000000000000000000000000000000000000000000000000000000000000081565b34801561032f57600080fd5b506102977f000000000000000000000000000000000000000000000000000000000000000081565b34801561036357600080fd5b5061024b610a26565b34801561037857600080fd5b5061019c61038736600461288f565b600260209081526000938452604080852082529284528284209052825290205481565b3480156103b657600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610297565b3480156103e157600080fd5b506103f56103f03660046129fb565b610b28565b60408051845173ffffffffffffffffffffffffffffffffffffffff9081168252602095860151868301528451169181019190915292909101516060830152608082015260a0016101a6565b34801561044c57600080fd5b5061024b61045b366004612a9c565b610f31565b34801561046c57600080fd5b5061019c6110ed565b34801561048157600080fd5b5061024b610490366004612679565b6111a3565b3480156104a157600080fd5b506102977f000000000000000000000000000000000000000000000000000000000000000081565b61024b6104d7366004612aed565b611374565b3480156104e857600080fd5b5061024b6104f7366004612b4f565b611507565b34801561050857600080fd5b5061024b610517366004612b6c565b61151b565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167ff1387e160000000000000000000000000000000000000000000000000000000014806105af57507fffffffff0000000000000000000000000000000000000000000000000000000082167f40d7f78e00000000000000000000000000000000000000000000000000000000145b92915050565b6105bd611654565b73ffffffffffffffffffffffffffffffffffffffff83166106925760008273ffffffffffffffffffffffffffffffffffffffff168277ffffffffffffffffffffffffffffffffffffffffffffffff1660405160006040518083038185875af1925050503d806000811461064c576040519150601f19603f3d011682016040523d82523d6000602084013e610651565b606091505b505090508061068c576040517fef2af20100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b6106cd73ffffffffffffffffffffffffffffffffffffffff84168377ffffffffffffffffffffffffffffffffffffffffffffffff84166116d7565b6040805133815273ffffffffffffffffffffffffffffffffffffffff848116602083015285168183015277ffffffffffffffffffffffffffffffffffffffffffffffff8316606082015290517f7ff78a71698bdb18dcca96f52ab25e0a1b146fb6a49adf8e6845299e49021f299181900360800190a15b505050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146107b8576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008267ffffffffffffffff8111156107d3576107d36128c6565b60405190808252806020026020018201604052801561080c57816020015b6107f96125ec565b8152602001906001900390816107f15790505b5090506000806000805b868110156109555760008060006108508b8b8681811061083857610838612beb565b905060200281019061084a9190612c1a565b8b6117ab565b92509250925082602001516000146109415760405180608001604052808c8c8781811061087f5761087f612beb565b90506020028101906108919190612c1a565b61089a91612c86565b8152602001848152602001838152602001828152508886806108bb90612cf1565b9750815181106108cd576108cd612beb565b60200260200101819052507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff160361093a57866001019650610941565b8560010195505b5050508061094e90612cf1565b9050610816565b508215158061096357508115155b1561097957610974858585856118e5565b610983565b61098385346120f9565b50505050505050565b610994611654565b670de0b6b3a764000067ffffffffffffffff821611156109e0576040517f05e8ac2900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff811660048190556040519081527f08f7c0d17932ddb8523bc06754d42ff19ebc77d76a8b9bfde02c28ab1ed3d6399060200160405180910390a150565b60015473ffffffffffffffffffffffffffffffffffffffff163314610aac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6040805180820182526000808252602080830182905283518085018552828152808201839052845180860186528381528083018490528551808701909652838652918501839052929382610b7b88612d29565b90507fffff000000000000000000000000000000000000000000000000000000000000808216908101610c1657505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811683527f0000000000000000000000000000000000000000000000000000000000000000168152909350915060009050610f28565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16886000015173ffffffffffffffffffffffffffffffffffffffff1614158015610cc657507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16886000015173ffffffffffffffffffffffffffffffffffffffff1614155b15610cfd576040517ff861803000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060008b806020019051810190610d169190612d82565b77ffffffffffffffffffffffffffffffffffffffffffffffff91821698509116955063ffffffff1693505050428210159050610d7e576040517fb6c405f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808e16600090815260026020908152604080832089845282528083208f51851684529091529020547f00000000000000000000000000000000000000000000000000000000000000009091168752610e0e610df682670de0b6b3a7640000612df4565b610e009086612e07565b670de0b6b3a7640000612146565b60208801528b5173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116911603610e9c5773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016885260208088015190890152610f19565b600454600090610eb890610df690670de0b6b3a7640000612e44565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168a529050610f12610f0883670de0b6b3a7640000612df4565b610e009083612e07565b60208a0152505b96995094975094955050505050505b93509350939050565b610f39611654565b670de0b6b3a764000067ffffffffffffffff82161115610f85576040517f997ea36000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415801561102d57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15611064576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff848116600081815260026020908152604080832088845282528083209487168084529482529182902067ffffffffffffffff86169081905582519485529084015285927f5eba5a8afa39780f0f99b6cbeb95f3da6a7040ca00abd46bdc91a0a060134139910160405180910390a350505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561117a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119e9190612e57565b905090565b6111ab611654565b600081815260036020526040812054908190036111f4576040517f03aad31200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600360205260408082208290558051600180825281830190925290816020015b604080518082019091526000808252602082015281526020019060019003908161121957905050905060405180604001604052808481526020018377ffffffffffffffffffffffffffffffffffffffffffffffff168152508160008151811061128457611284612beb565b60209081029190910101526040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b0d9fa19906113039084903090600401612ed0565b600060405180830381600087803b15801561131d57600080fd5b505af1158015611331573d6000803e3d6000fd5b50505050827f843f0b103e50b42b08f9d30f12f961845a6d02623730872e24644899c0dd98958360405161136791815260200190565b60405180910390a2505050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146113e3576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060006113f38686866117ab565b92509250925082602001516000036114175761140f84346120f9565b505050505050565b604080516001808252818301909252600091816020015b6114366125ec565b81526020019060019003908161142e575050604080516080810190915290915080611461888a612c86565b8152602001858152602001848152602001838152508160008151811061148957611489612beb565b60200260200101819052507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff16036114f9576109748582600160006118e5565b6109838582600060016118e5565b61150f611654565b6115188161217e565b50565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614801590611579575060005473ffffffffffffffffffffffffffffffffffffffff163314155b156115b0576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f14060f2300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906314060f239061162690869086908690600401612f08565b600060405180830381600087803b15801561164057600080fd5b505af1158015610983573d6000803e3d6000fd5b60005473ffffffffffffffffffffffffffffffffffffffff1633146116d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610aa3565b565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526107449084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612273565b6040805180820190915260008082526020820152604080518082019091526000808252602082015260003073ffffffffffffffffffffffffffffffffffffffff851603611824576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061183286880188612ff6565b91505060008161184190612d29565b6040805160208101909152600081529091507e010000000000000000000000000000000000000000000000000000000000007fffff0000000000000000000000000000000000000000000000000000000000008316146118c85760006118a9898b018b6130ba565b95505050505050808060200190518101906118c49190613182565b9150505b6118d3878483610b28565b95509550955050505093509350939050565b60008267ffffffffffffffff811115611900576119006128c6565b60405190808252806020026020018201604052801561194557816020015b604080518082019091526000808252602082015281526020019060019003908161191e5790505b50905060008267ffffffffffffffff811115611963576119636128c6565b6040519080825280602002602001820160405280156119a857816020015b60408051808201909152600080825260208201528152602001906001900390816119815790505b5090506000808080806119bb888a612e44565b905060005b81811015611d0a577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168b8281518110611a1157611a11612beb565b6020026020010151602001516000015173ffffffffffffffffffffffffffffffffffffffff1603611ad75760405180604001604052808c8381518110611a5957611a59612beb565b60200260200101516000015181526020018c8381518110611a7c57611a7c612beb565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16815250888580611ab590612cf1565b965081518110611ac757611ac7612beb565b6020026020010181905250611bcc565b60405180604001604052808c8381518110611af457611af4612beb565b60200260200101516000015181526020018c8381518110611b1757611b17612beb565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16815250878480611b5090612cf1565b955081518110611b6257611b62612beb565b60200260200101819052508a8181518110611b7f57611b7f612beb565b6020026020010151602001516020015186611b9a9190612e44565b95508a8181518110611bae57611bae612beb565b6020026020010151604001516020015185611bc99190612e44565b94505b8a8181518110611bde57611bde612beb565b602002602001015160600151600014611cfa578b73ffffffffffffffffffffffffffffffffffffffff168b8281518110611c1a57611c1a612beb565b6020026020010151600001517f88b15eb682210089cddf967648e2cb2a4535aeadc8f8f36050922e33c04e71258d8481518110611c5957611c59612beb565b6020026020010151602001518e8581518110611c7757611c77612beb565b6020026020010151604001518f8681518110611c9557611c95612beb565b602002602001015160600151604051611cf193929190835173ffffffffffffffffffffffffffffffffffffffff908116825260209485015185830152835116604082015291909201516060820152608081019190915260a00190565b60405180910390a35b611d0381612cf1565b90506119c0565b5060003415611dd85734861115611d4d576040517fb2e532de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0876040518263ffffffff1660e01b81526004016000604051808303818588803b158015611db557600080fd5b505af1158015611dc9573d6000803e3d6000fd5b50505050508534039050611e20565b8515611e2057611e2073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168d308961237f565b875115611eb5577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b0d9fa19898e6040518363ffffffff1660e01b8152600401611e82929190612ed0565b600060405180830381600087803b158015611e9c57600080fd5b505af1158015611eb0573d6000803e3d6000fd5b505050505b8651156120e1576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611f46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f6a9190612e57565b85111561203a5760005b8751811015611ffd57878181518110611f8f57611f8f612beb565b60200260200101516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16600360008a8481518110611fcb57611fcb612beb565b60209081029190910181015151825281019190915260400160002080549091019055611ff681612cf1565b9050611f74565b507ff52e5907b69d97c33392936c12d78b494463b78c5b72df50b4c497eee5720b678760405161202d91906131b0565b60405180910390a16120e1565b6040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b0d9fa19906120ae908a903090600401612ed0565b600060405180830381600087803b1580156120c857600080fd5b505af11580156120dc573d6000803e3d6000fd5b505050505b6120eb8c826120f9565b505050505050505050505050565b80156121425760405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f19350505050158015610744573d6000803e3d6000fd5b5050565b60008215612174578161215a600185612df4565b61216491906131c3565b61216f906001612e44565b612177565b60005b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036121fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610aa3565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006122d5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166123dd9092919063ffffffff16565b80519091501561074457808060200190518101906122f391906131fe565b610744576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610aa3565b60405173ffffffffffffffffffffffffffffffffffffffff8085166024830152831660448201526064810182905261068c9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401611729565b60606123ec84846000856123f4565b949350505050565b606082471015612486576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610aa3565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516124af9190613220565b60006040518083038185875af1925050503d80600081146124ec576040519150601f19603f3d011682016040523d82523d6000602084013e6124f1565b606091505b50915091506125028783838761250d565b979650505050505050565b606083156125a357825160000361259c5773ffffffffffffffffffffffffffffffffffffffff85163b61259c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610aa3565b50816123ec565b6123ec83838151156125b85781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610aa391906126f8565b6040518060800160405280600080191681526020016126346040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b815260200161266c6040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b8152602001600081525090565b60006020828403121561268b57600080fd5b5035919050565b6000602082840312156126a457600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461217757600080fd5b60005b838110156126ef5781810151838201526020016126d7565b50506000910152565b60208152600082518060208401526127178160408501602087016126d4565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b73ffffffffffffffffffffffffffffffffffffffff8116811461151857600080fd5b77ffffffffffffffffffffffffffffffffffffffffffffffff8116811461151857600080fd5b6000806000606084860312156127a657600080fd5b83356127b181612749565b925060208401356127c181612749565b915060408401356127d18161276b565b809150509250925092565b6000806000604084860312156127f157600080fd5b833567ffffffffffffffff8082111561280957600080fd5b818601915086601f83011261281d57600080fd5b81358181111561282c57600080fd5b8760208260051b850101111561284157600080fd5b602092830195509350508401356127d181612749565b803567ffffffffffffffff8116811461286f57600080fd5b919050565b60006020828403121561288657600080fd5b61217782612857565b6000806000606084860312156128a457600080fd5b83356128af81612749565b92506020840135915060408401356127d181612749565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516020810167ffffffffffffffff81118282101715612918576129186128c6565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715612965576129656128c6565b604052919050565b600082601f83011261297e57600080fd5b813567ffffffffffffffff811115612998576129986128c6565b6129c960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161291e565b8181528460208386010111156129de57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008385036060811215612a1157600080fd5b8435612a1c81612749565b9350602085013567ffffffffffffffff811115612a3857600080fd5b612a448782880161296d565b93505060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc082011215612a7757600080fd5b50612a806128f5565b6040850135612a8e81612749565b815292959194509192509050565b60008060008060808587031215612ab257600080fd5b8435612abd81612749565b9350602085013592506040850135612ad481612749565b9150612ae260608601612857565b905092959194509250565b600080600060408486031215612b0257600080fd5b833567ffffffffffffffff80821115612b1a57600080fd5b818601915086601f830112612b2e57600080fd5b813581811115612b3d57600080fd5b87602082850101111561284157600080fd5b600060208284031215612b6157600080fd5b813561217781612749565b600080600060408486031215612b8157600080fd5b83359250602084013567ffffffffffffffff80821115612ba057600080fd5b818601915086601f830112612bb457600080fd5b813581811115612bc357600080fd5b8760208260061b8501011115612bd857600080fd5b6020830194508093505050509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612c4f57600080fd5b83018035915067ffffffffffffffff821115612c6a57600080fd5b602001915036819003821315612c7f57600080fd5b9250929050565b803560208310156105af577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612d2257612d22612cc2565b5060010190565b80516020808301519190811015612d68577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b805163ffffffff8116811461286f57600080fd5b60008060008060008060c08789031215612d9b57600080fd5b86519550612dab60208801612d6e565b9450612db960408801612d6e565b93506060870151612dc98161276b565b6080880151909350612dda8161276b565b9150612de860a08801612d6e565b90509295509295509295565b818103818111156105af576105af612cc2565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612e3f57612e3f612cc2565b500290565b808201808211156105af576105af612cc2565b600060208284031215612e6957600080fd5b5051919050565b600081518084526020808501945080840160005b83811015612ec55781518051885283015177ffffffffffffffffffffffffffffffffffffffffffffffff168388015260409096019590820190600101612e84565b509495945050505050565b604081526000612ee36040830185612e70565b905073ffffffffffffffffffffffffffffffffffffffff831660208301529392505050565b8381526040602080830182905282820184905260009190859060608501845b87811015612f7b578335612f3a81612749565b73ffffffffffffffffffffffffffffffffffffffff16825267ffffffffffffffff612f66858501612857565b16828401529284019290840190600101612f27565b5098975050505050505050565b600082601f830112612f9957600080fd5b6040516060810181811067ffffffffffffffff82111715612fbc57612fbc6128c6565b604052806060840185811115612fd157600080fd5b845b81811015612feb578035835260209283019201612fd3565b509195945050505050565b6000806080838503121561300957600080fd5b6130138484612f88565b9150606083013567ffffffffffffffff81111561302f57600080fd5b61303b8582860161296d565b9150509250929050565b600082601f83011261305657600080fd5b8135602067ffffffffffffffff821115613072576130726128c6565b8160051b61308182820161291e565b928352848101820192828101908785111561309b57600080fd5b83870192505b84831015612502578235825291830191908301906130a1565b60008060008060008061010087890312156130d457600080fd5b6130de8888612f88565b9550606087013567ffffffffffffffff808211156130fb57600080fd5b6131078a838b0161296d565b9650608089013591508082111561311d57600080fd5b6131298a838b01613045565b955060a089013591508082111561313f57600080fd5b61314b8a838b01613045565b945060c0890135935060e089013591508082111561316857600080fd5b5061317589828a0161296d565b9150509295509295509295565b60006020828403121561319457600080fd5b61319c6128f5565b82516131a781612749565b81529392505050565b6020815260006121776020830184612e70565b6000826131f9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60006020828403121561321057600080fd5b8151801515811461217757600080fd5b600082516132328184602087016126d4565b919091019291505056fea164736f6c6343000810000a", } var FeeManagerABI = FeeManagerMetaData.ABI @@ -214,6 +214,94 @@ func (_FeeManager *FeeManagerCallerSession) GetFeeAndReward(subscriber common.Ad return _FeeManager.Contract.GetFeeAndReward(&_FeeManager.CallOpts, subscriber, report, quote) } +func (_FeeManager *FeeManagerCaller) ILinkAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _FeeManager.contract.Call(opts, &out, "i_linkAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_FeeManager *FeeManagerSession) ILinkAddress() (common.Address, error) { + return _FeeManager.Contract.ILinkAddress(&_FeeManager.CallOpts) +} + +func (_FeeManager *FeeManagerCallerSession) ILinkAddress() (common.Address, error) { + return _FeeManager.Contract.ILinkAddress(&_FeeManager.CallOpts) +} + +func (_FeeManager *FeeManagerCaller) INativeAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _FeeManager.contract.Call(opts, &out, "i_nativeAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_FeeManager *FeeManagerSession) INativeAddress() (common.Address, error) { + return _FeeManager.Contract.INativeAddress(&_FeeManager.CallOpts) +} + +func (_FeeManager *FeeManagerCallerSession) INativeAddress() (common.Address, error) { + return _FeeManager.Contract.INativeAddress(&_FeeManager.CallOpts) +} + +func (_FeeManager *FeeManagerCaller) IProxyAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _FeeManager.contract.Call(opts, &out, "i_proxyAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_FeeManager *FeeManagerSession) IProxyAddress() (common.Address, error) { + return _FeeManager.Contract.IProxyAddress(&_FeeManager.CallOpts) +} + +func (_FeeManager *FeeManagerCallerSession) IProxyAddress() (common.Address, error) { + return _FeeManager.Contract.IProxyAddress(&_FeeManager.CallOpts) +} + +func (_FeeManager *FeeManagerCaller) IRewardManager(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _FeeManager.contract.Call(opts, &out, "i_rewardManager") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_FeeManager *FeeManagerSession) IRewardManager() (common.Address, error) { + return _FeeManager.Contract.IRewardManager(&_FeeManager.CallOpts) +} + +func (_FeeManager *FeeManagerCallerSession) IRewardManager() (common.Address, error) { + return _FeeManager.Contract.IRewardManager(&_FeeManager.CallOpts) +} + func (_FeeManager *FeeManagerCaller) LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _FeeManager.contract.Call(opts, &out, "linkAvailableForPayment") @@ -1570,6 +1658,14 @@ func (_FeeManager *FeeManager) Address() common.Address { type FeeManagerInterface interface { GetFeeAndReward(opts *bind.CallOpts, subscriber common.Address, report []byte, quote IFeeManagerQuote) (CommonAsset, CommonAsset, *big.Int, error) + ILinkAddress(opts *bind.CallOpts) (common.Address, error) + + INativeAddress(opts *bind.CallOpts) (common.Address, error) + + IProxyAddress(opts *bind.CallOpts) (common.Address, error) + + IRewardManager(opts *bind.CallOpts) (common.Address, error) + LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) Owner(opts *bind.CallOpts) (common.Address, error) diff --git a/core/gethwrappers/llo-feeds/generated/reward_manager/reward_manager.go b/core/gethwrappers/llo-feeds/generated/reward_manager/reward_manager.go index 236eeaa5c1a..ab14e04fceb 100644 --- a/core/gethwrappers/llo-feeds/generated/reward_manager/reward_manager.go +++ b/core/gethwrappers/llo-feeds/generated/reward_manager/reward_manager.go @@ -41,8 +41,8 @@ type IRewardManagerFeePayment struct { } var RewardManagerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPoolId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPoolLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidWeights\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newFeeManagerAddress\",\"type\":\"address\"}],\"name\":\"FeeManagerUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"indexed\":false,\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"payments\",\"type\":\"tuple[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"}],\"name\":\"FeePaid\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"indexed\":false,\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"newRewardRecipients\",\"type\":\"tuple[]\"}],\"name\":\"RewardRecipientsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"RewardsClaimed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"poolIds\",\"type\":\"bytes32[]\"}],\"name\":\"claimRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"endIndex\",\"type\":\"uint256\"}],\"name\":\"getAvailableRewardPoolIds\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"payments\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"}],\"name\":\"onFeePaid\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"}],\"name\":\"payRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_feeManagerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_registeredPoolIds\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_rewardRecipientWeights\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_rewardRecipientWeightsSet\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_totalRewardRecipientFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_totalRewardRecipientFeesLastClaimedAmounts\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newFeeManagerAddress\",\"type\":\"address\"}],\"name\":\"setFeeManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"rewardRecipientAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setRewardRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"newRewardRecipients\",\"type\":\"tuple[]\"}],\"name\":\"updateRewardRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b50604051620020ec380380620020ec8339810160408190526200003491620001a6565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000fb565b5050506001600160a01b038116620000e95760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b0316608052620001d8565b336001600160a01b03821603620001555760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215620001b957600080fd5b81516001600160a01b0381168114620001d157600080fd5b9392505050565b608051611ef1620001fb60003960008181610cda0152610f150152611ef16000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c80634d322084116100b25780638ac85a5c11610081578063b0d9fa1911610066578063b0d9fa1914610377578063cd5f72921461038a578063f2fde38b1461039d57600080fd5b80638ac85a5c1461032e5780638da5cb5b1461035957600080fd5b80634d322084146102c557806359256201146102d857806360122608146102fb57806379ba50971461032657600080fd5b8063276e76601161010957806347226475116100ee578063472264751461027f578063472d35b91461029f5780634944832f146102b257600080fd5b8063276e76601461020c57806339ee81e11461025157600080fd5b806301ffc9a71461013b5780630f3c34d1146101a557806314060f23146101ba578063181f5a77146101cd575b600080fd5b6101906101493660046117dd565b7fffffffff00000000000000000000000000000000000000000000000000000000167fb0d9fa19000000000000000000000000000000000000000000000000000000001490565b60405190151581526020015b60405180910390f35b6101b86101b336600461189d565b6103b0565b005b6101b86101c836600461198f565b6103be565b604080518082018252601381527f5265776172644d616e6167657220312e302e30000000000000000000000000006020820152905161019c91906119ff565b60075461022c9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019c565b61027161025f366004611a50565b60026020526000908152604090205481565b60405190815260200161019c565b61029261028d366004611a92565b610574565b60405161019c9190611ac5565b6101b86102ad366004611b09565b6106fe565b6101b86102c036600461198f565b6107cc565b6101b86102d3366004611b2b565b61094e565b6101906102e6366004611a50565b60056020526000908152604090205460ff1681565b610271610309366004611baa565b600360209081526000928352604080842090915290825290205481565b6101b8610a8d565b61027161033c366004611baa565b600460209081526000928352604080842090915290825290205481565b60005473ffffffffffffffffffffffffffffffffffffffff1661022c565b6101b8610385366004611bd6565b610b8f565b610271610398366004611a50565b610d43565b6101b86103ab366004611b09565b610d64565b6103ba3382610d78565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906103fe575060075473ffffffffffffffffffffffffffffffffffffffff163314155b15610435576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000819003610470576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526005602052604090205460ff16156104b9576040517f0afa7ee800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006805460018181019092557ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01849055600084815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169091179055610535838383670de0b6b3a7640000610f45565b827f8f668d6090683f98b3373a8b83d214da45737f7486cb7de554cc07b54e61cfe68383604051610567929190611c42565b60405180910390a2505050565b6006546060906000818411610589578361058b565b815b9050808511156105c7576040517fa22caccc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006105d38683611cd9565b67ffffffffffffffff8111156105eb576105eb61181f565b604051908082528060200260200182016040528015610614578160200160208202803683370190505b5090506000865b838110156106f15760006006828154811061063857610638611cec565b600091825260208083209091015480835260048252604080842073ffffffffffffffffffffffffffffffffffffffff8f168552909252912054909150156106e0576000818152600260209081526040808320546003835281842073ffffffffffffffffffffffffffffffffffffffff8f1685529092529091205481146106de57818585806001019650815181106106d1576106d1611cec565b6020026020010181815250505b505b506106ea81611d1b565b905061061b565b5090979650505050505050565b610706611156565b73ffffffffffffffffffffffffffffffffffffffff8116610753576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fe45f5e140399b0a7e12971ab020724b828fbed8ac408c420884dc7d1bbe506b49060200160405180910390a150565b6107d4611156565b60408051600180825281830190925260009160208083019080368337019050509050838160008151811061080a5761080a611cec565b6020026020010181815250506000805b8381101561090057600085858381811061083657610836611cec565b61084c9260206040909202019081019150611b09565b600088815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff851684529091528120549192508190036108b8576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108e98787858181106108cd576108cd611cec565b6108e39260206040909202019081019150611b09565b86610d78565b509290920191506108f981611d1b565b905061081a565b5061090d85858584610f45565b847f8f668d6090683f98b3373a8b83d214da45737f7486cb7de554cc07b54e61cfe6858560405161093f929190611c42565b60405180910390a25050505050565b8261096e60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141580156109c057506000818152600460209081526040808320338452909152902054155b156109f7576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516001808252818301909252600091602080830190803683370190505090508481600081518110610a2d57610a2d611cec565b60200260200101818152505060005b83811015610a8557610a74858583818110610a5957610a59611cec565b9050602002016020810190610a6e9190611b09565b83610d78565b50610a7e81611d1b565b9050610a3c565b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60075473ffffffffffffffffffffffffffffffffffffffff163314610be0576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b83811015610cbf57848482818110610bfe57610bfe611cec565b9050604002016020016020810190610c169190611d7b565b77ffffffffffffffffffffffffffffffffffffffffffffffff1660026000878785818110610c4657610c46611cec565b6040908102929092013583525060208201929092520160002080549091019055848482818110610c7857610c78611cec565b9050604002016020016020810190610c909190611d7b565b77ffffffffffffffffffffffffffffffffffffffffffffffff168201915080610cb890611d1b565b9050610be4565b50610d0273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168330846111d9565b7fa1cc025ea76bacce5d740ee4bc331899375dc2c5f2ab33933aaacbd9ba001b66848484604051610d3593929190611d96565b60405180910390a150505050565b60068181548110610d5357600080fd5b600091825260209091200154905081565b610d6c611156565b610d75816112bb565b50565b60008060005b8351811015610ef4576000848281518110610d9b57610d9b611cec565b6020026020010151905060006002600083815260200190815260200160002054905080600003610dcc575050610ee4565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8b16808552908352818420548685526004845282852091855292528220549083039190670de0b6b3a764000090830204905080600003610e355750505050610ee4565b600084815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8d168085529252909120849055885196820196899087908110610e8057610e80611cec565b60200260200101517f989969655bc1d593922527fe85d71347bb8e12fa423cc71f362dd8ef7cb10ef283604051610ed7919077ffffffffffffffffffffffffffffffffffffffffffffffff91909116815260200190565b60405180910390a3505050505b610eed81611d1b565b9050610d7e565b508015610f3c57610f3c73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001685836113b0565b90505b92915050565b610fa08383808060200260200160405190810160405280939291908181526020016000905b82821015610f9657610f8760408302860136819003810190611e1d565b81526020019060010190610f6a565b505050505061140b565b15610fd7576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b83811015611115576000858583818110610ff757610ff7611cec565b905060400201602001602081019061100f9190611e78565b67ffffffffffffffff169050600086868481811061102f5761102f611cec565b6110459260206040909202019081019150611b09565b905073ffffffffffffffffffffffffffffffffffffffff8116611094576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816000036110ce576040517f84677ce800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600088815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff909416835292905220819055919091019061110e81611d1b565b9050610fdb565b5081811461114f576040517f84677ce800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146111d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b0a565b565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526112b59085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526114c2565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff82160361133a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b0a565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526114069084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611233565b505050565b6000805b82518110156114b9576000611425826001611e93565b90505b83518110156114b05783818151811061144357611443611cec565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1684838151811061147757611477611cec565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16036114a8575060019392505050565b600101611428565b5060010161140f565b50600092915050565b6000611524826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166115ce9092919063ffffffff16565b80519091501561140657808060200190518101906115429190611ea6565b611406576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b0a565b60606115dd84846000856115e5565b949350505050565b606082471015611677576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b0a565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516116a09190611ec8565b60006040518083038185875af1925050503d80600081146116dd576040519150601f19603f3d011682016040523d82523d6000602084013e6116e2565b606091505b50915091506116f3878383876116fe565b979650505050505050565b6060831561179457825160000361178d5773ffffffffffffffffffffffffffffffffffffffff85163b61178d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b0a565b50816115dd565b6115dd83838151156117a95781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b0a91906119ff565b6000602082840312156117ef57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610f3c57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156118955761189561181f565b604052919050565b600060208083850312156118b057600080fd5b823567ffffffffffffffff808211156118c857600080fd5b818501915085601f8301126118dc57600080fd5b8135818111156118ee576118ee61181f565b8060051b91506118ff84830161184e565b818152918301840191848101908884111561191957600080fd5b938501935b838510156119375784358252938501939085019061191e565b98975050505050505050565b60008083601f84011261195557600080fd5b50813567ffffffffffffffff81111561196d57600080fd5b6020830191508360208260061b850101111561198857600080fd5b9250929050565b6000806000604084860312156119a457600080fd5b83359250602084013567ffffffffffffffff8111156119c257600080fd5b6119ce86828701611943565b9497909650939450505050565b60005b838110156119f65781810151838201526020016119de565b50506000910152565b6020815260008251806020840152611a1e8160408501602087016119db565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b600060208284031215611a6257600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611a8d57600080fd5b919050565b600080600060608486031215611aa757600080fd5b611ab084611a69565b95602085013595506040909401359392505050565b6020808252825182820181905260009190848201906040850190845b81811015611afd57835183529284019291840191600101611ae1565b50909695505050505050565b600060208284031215611b1b57600080fd5b611b2482611a69565b9392505050565b600080600060408486031215611b4057600080fd5b83359250602084013567ffffffffffffffff80821115611b5f57600080fd5b818601915086601f830112611b7357600080fd5b813581811115611b8257600080fd5b8760208260051b8501011115611b9757600080fd5b6020830194508093505050509250925092565b60008060408385031215611bbd57600080fd5b82359150611bcd60208401611a69565b90509250929050565b600080600060408486031215611beb57600080fd5b833567ffffffffffffffff811115611c0257600080fd5b611c0e86828701611943565b9094509250611c21905060208501611a69565b90509250925092565b803567ffffffffffffffff81168114611a8d57600080fd5b6020808252818101839052600090604080840186845b878110156106f15773ffffffffffffffffffffffffffffffffffffffff611c7e83611a69565b16835267ffffffffffffffff611c95868401611c2a565b16838601529183019190830190600101611c58565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610f3f57610f3f611caa565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611d4c57611d4c611caa565b5060010190565b803577ffffffffffffffffffffffffffffffffffffffffffffffff81168114611a8d57600080fd5b600060208284031215611d8d57600080fd5b611b2482611d53565b60408082528181018490526000908560608401835b87811015611df25782358252602077ffffffffffffffffffffffffffffffffffffffffffffffff611ddd828601611d53565b16908301529183019190830190600101611dab565b5080935050505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b600060408284031215611e2f57600080fd5b6040516040810181811067ffffffffffffffff82111715611e5257611e5261181f565b604052611e5e83611a69565b8152611e6c60208401611c2a565b60208201529392505050565b600060208284031215611e8a57600080fd5b611b2482611c2a565b80820180821115610f3f57610f3f611caa565b600060208284031215611eb857600080fd5b81518015158114610f3c57600080fd5b60008251611eda8184602087016119db565b919091019291505056fea164736f6c6343000810000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPoolId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPoolLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidWeights\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newFeeManagerAddress\",\"type\":\"address\"}],\"name\":\"FeeManagerUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"indexed\":false,\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"payments\",\"type\":\"tuple[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"}],\"name\":\"FeePaid\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"indexed\":false,\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"newRewardRecipients\",\"type\":\"tuple[]\"}],\"name\":\"RewardRecipientsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"RewardsClaimed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"poolIds\",\"type\":\"bytes32[]\"}],\"name\":\"claimRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"endIndex\",\"type\":\"uint256\"}],\"name\":\"getAvailableRewardPoolIds\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_linkAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"payments\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"}],\"name\":\"onFeePaid\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"}],\"name\":\"payRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_feeManagerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_registeredPoolIds\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_rewardRecipientWeights\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_rewardRecipientWeightsSet\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_totalRewardRecipientFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_totalRewardRecipientFeesLastClaimedAmounts\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newFeeManagerAddress\",\"type\":\"address\"}],\"name\":\"setFeeManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"rewardRecipientAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setRewardRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"newRewardRecipients\",\"type\":\"tuple[]\"}],\"name\":\"updateRewardRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b5060405162002135380380620021358339810160408190526200003491620001a6565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000fb565b5050506001600160a01b038116620000e95760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b0316608052620001d8565b336001600160a01b03821603620001555760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215620001b957600080fd5b81516001600160a01b0381168114620001d157600080fd5b9392505050565b608051611f3362000202600039600081816103bd01528181610d1c0152610f570152611f336000f3fe608060405234801561001057600080fd5b50600436106101515760003560e01c80634d322084116100cd5780638da5cb5b11610081578063cd5f729211610066578063cd5f7292146103a5578063ea4b861b146103b8578063f2fde38b146103df57600080fd5b80638da5cb5b14610374578063b0d9fa191461039257600080fd5b806360122608116100b2578063601226081461031657806379ba5097146103415780638ac85a5c1461034957600080fd5b80634d322084146102e057806359256201146102f357600080fd5b8063276e7660116101245780634722647511610109578063472264751461029a578063472d35b9146102ba5780634944832f146102cd57600080fd5b8063276e76601461022757806339ee81e11461026c57600080fd5b806301ffc9a7146101565780630f3c34d1146101c057806314060f23146101d5578063181f5a77146101e8575b600080fd5b6101ab61016436600461181f565b7fffffffff00000000000000000000000000000000000000000000000000000000167fb0d9fa19000000000000000000000000000000000000000000000000000000001490565b60405190151581526020015b60405180910390f35b6101d36101ce3660046118df565b6103f2565b005b6101d36101e33660046119d1565b610400565b604080518082018252601381527f5265776172644d616e6167657220312e302e3000000000000000000000000000602082015290516101b79190611a41565b6007546102479073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101b7565b61028c61027a366004611a92565b60026020526000908152604090205481565b6040519081526020016101b7565b6102ad6102a8366004611ad4565b6105b6565b6040516101b79190611b07565b6101d36102c8366004611b4b565b610740565b6101d36102db3660046119d1565b61080e565b6101d36102ee366004611b6d565b610990565b6101ab610301366004611a92565b60056020526000908152604090205460ff1681565b61028c610324366004611bec565b600360209081526000928352604080842090915290825290205481565b6101d3610acf565b61028c610357366004611bec565b600460209081526000928352604080842090915290825290205481565b60005473ffffffffffffffffffffffffffffffffffffffff16610247565b6101d36103a0366004611c18565b610bd1565b61028c6103b3366004611a92565b610d85565b6102477f000000000000000000000000000000000000000000000000000000000000000081565b6101d36103ed366004611b4b565b610da6565b6103fc3382610dba565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610440575060075473ffffffffffffffffffffffffffffffffffffffff163314155b15610477576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008190036104b2576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526005602052604090205460ff16156104fb576040517f0afa7ee800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006805460018181019092557ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01849055600084815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169091179055610577838383670de0b6b3a7640000610f87565b827f8f668d6090683f98b3373a8b83d214da45737f7486cb7de554cc07b54e61cfe683836040516105a9929190611c84565b60405180910390a2505050565b60065460609060008184116105cb57836105cd565b815b905080851115610609576040517fa22caccc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006106158683611d1b565b67ffffffffffffffff81111561062d5761062d611861565b604051908082528060200260200182016040528015610656578160200160208202803683370190505b5090506000865b838110156107335760006006828154811061067a5761067a611d2e565b600091825260208083209091015480835260048252604080842073ffffffffffffffffffffffffffffffffffffffff8f16855290925291205490915015610722576000818152600260209081526040808320546003835281842073ffffffffffffffffffffffffffffffffffffffff8f168552909252909120548114610720578185858060010196508151811061071357610713611d2e565b6020026020010181815250505b505b5061072c81611d5d565b905061065d565b5090979650505050505050565b610748611198565b73ffffffffffffffffffffffffffffffffffffffff8116610795576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fe45f5e140399b0a7e12971ab020724b828fbed8ac408c420884dc7d1bbe506b49060200160405180910390a150565b610816611198565b60408051600180825281830190925260009160208083019080368337019050509050838160008151811061084c5761084c611d2e565b6020026020010181815250506000805b8381101561094257600085858381811061087857610878611d2e565b61088e9260206040909202019081019150611b4b565b600088815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff851684529091528120549192508190036108fa576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61092b87878581811061090f5761090f611d2e565b6109259260206040909202019081019150611b4b565b86610dba565b5092909201915061093b81611d5d565b905061085c565b5061094f85858584610f87565b847f8f668d6090683f98b3373a8b83d214da45737f7486cb7de554cc07b54e61cfe68585604051610981929190611c84565b60405180910390a25050505050565b826109b060005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015610a0257506000818152600460209081526040808320338452909152902054155b15610a39576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516001808252818301909252600091602080830190803683370190505090508481600081518110610a6f57610a6f611d2e565b60200260200101818152505060005b83811015610ac757610ab6858583818110610a9b57610a9b611d2e565b9050602002016020810190610ab09190611b4b565b83610dba565b50610ac081611d5d565b9050610a7e565b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60075473ffffffffffffffffffffffffffffffffffffffff163314610c22576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b83811015610d0157848482818110610c4057610c40611d2e565b9050604002016020016020810190610c589190611dbd565b77ffffffffffffffffffffffffffffffffffffffffffffffff1660026000878785818110610c8857610c88611d2e565b6040908102929092013583525060208201929092520160002080549091019055848482818110610cba57610cba611d2e565b9050604002016020016020810190610cd29190611dbd565b77ffffffffffffffffffffffffffffffffffffffffffffffff168201915080610cfa90611d5d565b9050610c26565b50610d4473ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001683308461121b565b7fa1cc025ea76bacce5d740ee4bc331899375dc2c5f2ab33933aaacbd9ba001b66848484604051610d7793929190611dd8565b60405180910390a150505050565b60068181548110610d9557600080fd5b600091825260209091200154905081565b610dae611198565b610db7816112fd565b50565b60008060005b8351811015610f36576000848281518110610ddd57610ddd611d2e565b6020026020010151905060006002600083815260200190815260200160002054905080600003610e0e575050610f26565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8b16808552908352818420548685526004845282852091855292528220549083039190670de0b6b3a764000090830204905080600003610e775750505050610f26565b600084815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8d168085529252909120849055885196820196899087908110610ec257610ec2611d2e565b60200260200101517f989969655bc1d593922527fe85d71347bb8e12fa423cc71f362dd8ef7cb10ef283604051610f19919077ffffffffffffffffffffffffffffffffffffffffffffffff91909116815260200190565b60405180910390a3505050505b610f2f81611d5d565b9050610dc0565b508015610f7e57610f7e73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001685836113f2565b90505b92915050565b610fe28383808060200260200160405190810160405280939291908181526020016000905b82821015610fd857610fc960408302860136819003810190611e5f565b81526020019060010190610fac565b505050505061144d565b15611019576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b8381101561115757600085858381811061103957611039611d2e565b90506040020160200160208101906110519190611eba565b67ffffffffffffffff169050600086868481811061107157611071611d2e565b6110879260206040909202019081019150611b4b565b905073ffffffffffffffffffffffffffffffffffffffff81166110d6576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81600003611110576040517f84677ce800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600088815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff909416835292905220819055919091019061115081611d5d565b905061101d565b50818114611191576040517f84677ce800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611219576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b4c565b565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526112f79085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611504565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff82160361137c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b4c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526114489084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611275565b505050565b6000805b82518110156114fb576000611467826001611ed5565b90505b83518110156114f25783818151811061148557611485611d2e565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff168483815181106114b9576114b9611d2e565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16036114ea575060019392505050565b60010161146a565b50600101611451565b50600092915050565b6000611566826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166116109092919063ffffffff16565b80519091501561144857808060200190518101906115849190611ee8565b611448576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b4c565b606061161f8484600085611627565b949350505050565b6060824710156116b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b4c565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516116e29190611f0a565b60006040518083038185875af1925050503d806000811461171f576040519150601f19603f3d011682016040523d82523d6000602084013e611724565b606091505b509150915061173587838387611740565b979650505050505050565b606083156117d65782516000036117cf5773ffffffffffffffffffffffffffffffffffffffff85163b6117cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b4c565b508161161f565b61161f83838151156117eb5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b4c9190611a41565b60006020828403121561183157600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610f7e57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156118d7576118d7611861565b604052919050565b600060208083850312156118f257600080fd5b823567ffffffffffffffff8082111561190a57600080fd5b818501915085601f83011261191e57600080fd5b81358181111561193057611930611861565b8060051b9150611941848301611890565b818152918301840191848101908884111561195b57600080fd5b938501935b8385101561197957843582529385019390850190611960565b98975050505050505050565b60008083601f84011261199757600080fd5b50813567ffffffffffffffff8111156119af57600080fd5b6020830191508360208260061b85010111156119ca57600080fd5b9250929050565b6000806000604084860312156119e657600080fd5b83359250602084013567ffffffffffffffff811115611a0457600080fd5b611a1086828701611985565b9497909650939450505050565b60005b83811015611a38578181015183820152602001611a20565b50506000910152565b6020815260008251806020840152611a60816040850160208701611a1d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b600060208284031215611aa457600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611acf57600080fd5b919050565b600080600060608486031215611ae957600080fd5b611af284611aab565b95602085013595506040909401359392505050565b6020808252825182820181905260009190848201906040850190845b81811015611b3f57835183529284019291840191600101611b23565b50909695505050505050565b600060208284031215611b5d57600080fd5b611b6682611aab565b9392505050565b600080600060408486031215611b8257600080fd5b83359250602084013567ffffffffffffffff80821115611ba157600080fd5b818601915086601f830112611bb557600080fd5b813581811115611bc457600080fd5b8760208260051b8501011115611bd957600080fd5b6020830194508093505050509250925092565b60008060408385031215611bff57600080fd5b82359150611c0f60208401611aab565b90509250929050565b600080600060408486031215611c2d57600080fd5b833567ffffffffffffffff811115611c4457600080fd5b611c5086828701611985565b9094509250611c63905060208501611aab565b90509250925092565b803567ffffffffffffffff81168114611acf57600080fd5b6020808252818101839052600090604080840186845b878110156107335773ffffffffffffffffffffffffffffffffffffffff611cc083611aab565b16835267ffffffffffffffff611cd7868401611c6c565b16838601529183019190830190600101611c9a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610f8157610f81611cec565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611d8e57611d8e611cec565b5060010190565b803577ffffffffffffffffffffffffffffffffffffffffffffffff81168114611acf57600080fd5b600060208284031215611dcf57600080fd5b611b6682611d95565b60408082528181018490526000908560608401835b87811015611e345782358252602077ffffffffffffffffffffffffffffffffffffffffffffffff611e1f828601611d95565b16908301529183019190830190600101611ded565b5080935050505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b600060408284031215611e7157600080fd5b6040516040810181811067ffffffffffffffff82111715611e9457611e94611861565b604052611ea083611aab565b8152611eae60208401611c6c565b60208201529392505050565b600060208284031215611ecc57600080fd5b611b6682611c6c565b80820180821115610f8157610f81611cec565b600060208284031215611efa57600080fd5b81518015158114610f7e57600080fd5b60008251611f1c818460208701611a1d565b919091019291505056fea164736f6c6343000810000a", } var RewardManagerABI = RewardManagerMetaData.ABI @@ -203,6 +203,28 @@ func (_RewardManager *RewardManagerCallerSession) GetAvailableRewardPoolIds(reci return _RewardManager.Contract.GetAvailableRewardPoolIds(&_RewardManager.CallOpts, recipient, startIndex, endIndex) } +func (_RewardManager *RewardManagerCaller) ILinkAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _RewardManager.contract.Call(opts, &out, "i_linkAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_RewardManager *RewardManagerSession) ILinkAddress() (common.Address, error) { + return _RewardManager.Contract.ILinkAddress(&_RewardManager.CallOpts) +} + +func (_RewardManager *RewardManagerCallerSession) ILinkAddress() (common.Address, error) { + return _RewardManager.Contract.ILinkAddress(&_RewardManager.CallOpts) +} + func (_RewardManager *RewardManagerCaller) Owner(opts *bind.CallOpts) (common.Address, error) { var out []interface{} err := _RewardManager.contract.Call(opts, &out, "owner") @@ -1320,6 +1342,8 @@ func (_RewardManager *RewardManager) Address() common.Address { type RewardManagerInterface interface { GetAvailableRewardPoolIds(opts *bind.CallOpts, recipient common.Address, startIndex *big.Int, endIndex *big.Int) ([][32]byte, error) + ILinkAddress(opts *bind.CallOpts) (common.Address, error) + Owner(opts *bind.CallOpts) (common.Address, error) SFeeManagerAddress(opts *bind.CallOpts) (common.Address, error) diff --git a/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 284e9886f3e..47444d741d5 100644 --- a/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,9 +1,9 @@ GETH_VERSION: 1.12.0 errored_verifier: ../../../contracts/solc/v0.8.16/ErroredVerifier.abi ../../../contracts/solc/v0.8.16/ErroredVerifier.bin a1b88979c6b0b210677346df554ffc33992d6ebe24be5a244475bfb4d153155e exposed_verifier: ../../../contracts/solc/v0.8.16/ExposedVerifier.abi ../../../contracts/solc/v0.8.16/ExposedVerifier.bin 6932cea8f2738e874d3ec9e1a4231d2421704030c071d9e15dd2f7f08482c246 -fee_manager: ../../../contracts/solc/v0.8.16/FeeManager.abi ../../../contracts/solc/v0.8.16/FeeManager.bin 2c22cbfb24374f645eef8a368f30d1821e350501742118eebd0fa3e8bcbc4d29 +fee_manager: ../../../contracts/solc/v0.8.16/FeeManager.abi ../../../contracts/solc/v0.8.16/FeeManager.bin 630d7dfa814579001a359e26d99ff9c1f76a6a6480b0140da91b9f20cc1ab8df llo_feeds: ../../../contracts/solc/v0.8.16/FeeManager.abi ../../../contracts/solc/v0.8.16/FeeManager.bin cb71e018f67e49d7bc0e194c822204dfd59f79ff42e4fc8fd8ab63f3acd71361 llo_feeds_test: ../../../contracts/solc/v0.8.16/ExposedVerifier.abi ../../../contracts/solc/v0.8.16/ExposedVerifier.bin 6932cea8f2738e874d3ec9e1a4231d2421704030c071d9e15dd2f7f08482c246 -reward_manager: ../../../contracts/solc/v0.8.16/RewardManager.abi ../../../contracts/solc/v0.8.16/RewardManager.bin 8b163eb0537180accfa69beea298890f1605c8d9f776689ea26802eefda46457 +reward_manager: ../../../contracts/solc/v0.8.16/RewardManager.abi ../../../contracts/solc/v0.8.16/RewardManager.bin ec52c851ffe7ed00e05a68dbb363b2e01d38088ac829988b611653b30d10ec97 verifier: ../../../contracts/solc/v0.8.16/Verifier.abi ../../../contracts/solc/v0.8.16/Verifier.bin 8f841ddd5e616fc1a8d6ac3d27ea9a383d958055237c90ecaf980f5cb3421e49 verifier_proxy: ../../../contracts/solc/v0.8.16/VerifierProxy.abi ../../../contracts/solc/v0.8.16/VerifierProxy.bin 92ad0416e999e9d55e4f00a8b7df616bb69ae27ce52994a6061598e95364d2cc diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 4fe03004d97..139d66b590f 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -378,9 +378,6 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn } } - if ethClient == nil { - ethClient = evmclient.NewNullClient(cfg.DefaultChainID(), lggr) - } keyStore := keystore.New(db, utils.FastScryptParams, lggr, cfg.Database()) @@ -395,22 +392,28 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn GRPCOpts: loop.GRPCOpts{}, } - chainId := ethClient.ConfiguredChainID() evmOpts := chainlink.EVMFactoryConfig{ RelayerConfig: &evm.RelayerConfig{ AppConfig: cfg, EventBroadcaster: eventBroadcaster, MailMon: mailMon, - GenEthClient: func(_ *big.Int) evmclient.Client { - if chainId.Cmp(cfg.DefaultChainID()) != 0 { - t.Fatalf("expected eth client ChainID %d to match configured DefaultChainID %d", chainId, cfg.DefaultChainID()) - } - return ethClient - }, }, CSAETHKeystore: keyStore, } + if cfg.EVMEnabled() { + if ethClient == nil { + ethClient = evmclient.NewNullClient(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()), lggr) + } + chainId := ethClient.ConfiguredChainID() + evmOpts.GenEthClient = func(_ *big.Int) evmclient.Client { + if chainId.Cmp(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs())) != 0 { + t.Fatalf("expected eth client ChainID %d to match evm config chain id %d", chainId, evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs())) + } + return ethClient + } + } + testCtx := testutils.Context(t) // evm alway enabled for backward compatibility initOps := []chainlink.CoreRelayerChainInitFunc{chainlink.InitEVM(testCtx, relayerFactory, evmOpts)} @@ -530,15 +533,19 @@ func NewEthMocksWithTransactionsOnBlocksAssertions(t testing.TB) *evmclimocks.Cl c.On("HeadByHash", mock.Anything, h0.Hash).Maybe().Return(h0, nil) c.On("BatchCallContext", mock.Anything, mock.Anything).Maybe().Return(nil).Run(func(args mock.Arguments) { elems := args.Get(1).([]rpc.BatchElem) - elems[0].Result = &evmtypes.Block{ - Number: 42, - Hash: utils.NewHash(), - Transactions: LegacyTransactionsFromGasPrices(9001, 9002), + if len(elems) > 0 { + elems[0].Result = &evmtypes.Block{ + Number: 42, + Hash: utils.NewHash(), + Transactions: LegacyTransactionsFromGasPrices(9001, 9002), + } } - elems[1].Result = &evmtypes.Block{ - Number: 41, - Hash: utils.NewHash(), - Transactions: LegacyTransactionsFromGasPrices(9003, 9004), + if len(elems) > 1 { + elems[1].Result = &evmtypes.Block{ + Number: 41, + Hash: utils.NewHash(), + Transactions: LegacyTransactionsFromGasPrices(9003, 9004), + } } }) c.On("ConfiguredChainID").Maybe().Return(&FixtureChainID) @@ -983,7 +990,7 @@ func AssertEthTxAttemptCountStays(t testing.TB, db *sqlx.DB, want int) []int64 { var err error g.Consistently(func() []int64 { txaIds = make([]int64, 0) - err = db.Select(&txaIds, `SELECT ID FROM eth_tx_attempts ORDER BY id ASC`) + err = db.Select(&txaIds, `SELECT ID FROM evm.tx_attempts ORDER BY id ASC`) assert.NoError(t, err) return txaIds }, AssertNoActionTimeout, DBPollingInterval).Should(gomega.HaveLen(want)) @@ -1286,7 +1293,7 @@ func MockApplicationEthCalls(t *testing.T, app *TestApplication, ethClient *evmc // Start ethClient.On("Dial", mock.Anything).Return(nil) ethClient.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(sub, nil).Maybe() - ethClient.On("ConfiguredChainID", mock.Anything).Return(app.GetConfig().DefaultChainID(), nil) + ethClient.On("ConfiguredChainID", mock.Anything).Return(evmtest.MustGetDefaultChainID(t, app.GetConfig().EVMConfigs()), nil) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil).Maybe() ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(nil, nil).Maybe() ethClient.On("Close").Return().Maybe() @@ -1536,7 +1543,7 @@ func AssertCountStays(t testing.TB, db *sqlx.DB, tableName string, want int64) { var count int64 var err error g.Consistently(func() int64 { - err = db.Get(&count, fmt.Sprintf(`SELECT count(*) FROM %q`, tableName)) + err = db.Get(&count, fmt.Sprintf(`SELECT count(*) FROM %s`, tableName)) assert.NoError(t, err) return count }, AssertNoActionTimeout, DBPollingInterval).Should(gomega.Equal(want)) diff --git a/core/internal/cltest/factories.go b/core/internal/cltest/factories.go index bfa479af624..36a89971ca6 100644 --- a/core/internal/cltest/factories.go +++ b/core/internal/cltest/factories.go @@ -443,7 +443,7 @@ func MustInsertRevertedEthReceipt(t *testing.T, txStore txmgr.TestEvmTxStore, bl return r } -// Inserts into eth_receipts but does not update eth_txes or eth_tx_attempts +// Inserts into evm.receipts but does not update evm.txes or evm.tx_attempts func MustInsertConfirmedEthTxWithReceipt(t *testing.T, txStore txmgr.TestEvmTxStore, fromAddress common.Address, nonce, blockNum int64) (etx txmgr.Tx) { etx = MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, nonce, blockNum, fromAddress) MustInsertEthReceipt(t, txStore, blockNum, utils.NewHash(), etx.TxAttempts[0].Hash) @@ -481,6 +481,14 @@ func MustAddRandomKeyToKeystore(t testing.TB, ethKeyStore keystore.Eth) (ethkey. return k, k.Address } +func MustAddRandomKeyToKeystoreWithChainID(t testing.TB, chainID *big.Int, ethKeyStore keystore.Eth) (ethkey.KeyV2, common.Address) { + t.Helper() + k := MustGenerateRandomKey(t) + MustAddKeyToKeystore(t, k, chainID, ethKeyStore) + + return k, k.Address +} + func MustAddKeyToKeystore(t testing.TB, key ethkey.KeyV2, chainID *big.Int, ethKeyStore keystore.Eth) { t.Helper() ethKeyStore.XXXTestingOnlyAdd(key) @@ -624,7 +632,7 @@ NOW(),NOW(),$1,'{}',false,$2,$3,0,0,0,0,0,0,0,0 func MakeDirectRequestJobSpec(t *testing.T) *job.Job { t.Helper() - drs := &job.DirectRequestSpec{} + drs := &job.DirectRequestSpec{EVMChainID: (*utils.Big)(testutils.FixtureChainID)} spec := &job.Job{ Type: job.DirectRequest, SchemaVersion: 1, @@ -640,7 +648,7 @@ func MustInsertKeeperJob(t *testing.T, db *sqlx.DB, korm keeper.ORM, from ethkey t.Helper() var keeperSpec job.KeeperSpec - err := korm.Q().Get(&keeperSpec, `INSERT INTO keeper_specs (contract_address, from_address, created_at, updated_at) VALUES ($1, $2, NOW(), NOW()) RETURNING *`, contract, from) + err := korm.Q().Get(&keeperSpec, `INSERT INTO keeper_specs (contract_address, from_address, created_at, updated_at,evm_chain_id) VALUES ($1, $2, NOW(), NOW(), $3) RETURNING *`, contract, from, testutils.SimulatedChainID.Int64()) require.NoError(t, err) var pipelineSpec pipeline.Spec @@ -668,7 +676,7 @@ func MustInsertKeeperJob(t *testing.T, db *sqlx.DB, korm keeper.ORM, from ethkey } func MustInsertKeeperRegistry(t *testing.T, db *sqlx.DB, korm keeper.ORM, ethKeyStore keystore.Eth, keeperIndex, numKeepers, blockCountPerTurn int32) (keeper.Registry, job.Job) { - key, _ := MustAddRandomKeyToKeystore(t, ethKeyStore) + key, _ := MustAddRandomKeyToKeystoreWithChainID(t, testutils.SimulatedChainID, ethKeyStore) from := key.EIP55Address t.Helper() contractAddress := NewEIP55Address() diff --git a/core/internal/cltest/job_factories.go b/core/internal/cltest/job_factories.go index ef59a9d312c..910ffe79e38 100644 --- a/core/internal/cltest/job_factories.go +++ b/core/internal/cltest/job_factories.go @@ -24,6 +24,7 @@ const ( type = "offchainreporting" schemaVersion = 1 contractAddress = "%s" + evmChainID = "0" p2pPeerID = "%s" p2pBootstrapPeers = ["/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"] isBootstrapPeer = false diff --git a/core/internal/cltest/mocks.go b/core/internal/cltest/mocks.go index 423791f716c..439ca2b721d 100644 --- a/core/internal/cltest/mocks.go +++ b/core/internal/cltest/mocks.go @@ -429,7 +429,5 @@ func NewLegacyChainsWithMockChain(t testing.TB, ethClient evmclient.Client, cfg func NewLegacyChainsWithChain(ch evm.Chain, cfg evm.AppConfig) evm.LegacyChainContainer { m := map[string]evm.Chain{ch.ID().String(): ch} - legacyChains := evm.NewLegacyChains(m, cfg.EVMConfigs()) - legacyChains.SetDefault(ch) - return legacyChains + return evm.NewLegacyChains(m, cfg.EVMConfigs()) } diff --git a/core/internal/cltest/simulated_backend.go b/core/internal/cltest/simulated_backend.go index 9a3dcfd5184..010478837da 100644 --- a/core/internal/cltest/simulated_backend.go +++ b/core/internal/cltest/simulated_backend.go @@ -12,6 +12,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -36,8 +37,8 @@ func NewApplicationWithConfigV2OnSimulatedBlockchain( if bid := backend.Blockchain().Config().ChainID; bid.Cmp(testutils.SimulatedChainID) != 0 { t.Fatalf("expected backend chain ID to be %s but it was %s", testutils.SimulatedChainID.String(), bid.String()) } - defID := cfg.DefaultChainID() - require.Zero(t, defID.Cmp(testutils.SimulatedChainID)) + + require.Zero(t, evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()).Cmp(testutils.SimulatedChainID)) chainID := utils.NewBig(testutils.SimulatedChainID) client := client.NewSimulatedBackendClient(t, backend, testutils.SimulatedChainID) eventBroadcaster := pg.NewEventBroadcaster(cfg.Database().URL(), 0, 0, logger.TestLogger(t), uuid.New()) @@ -61,8 +62,8 @@ func NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain( if bid := backend.Blockchain().Config().ChainID; bid.Cmp(testutils.SimulatedChainID) != 0 { t.Fatalf("expected backend chain ID to be %s but it was %s", testutils.SimulatedChainID.String(), bid.String()) } - defID := cfg.DefaultChainID() - require.Zero(t, defID.Cmp(testutils.SimulatedChainID)) + + require.Zero(t, evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()).Cmp(testutils.SimulatedChainID)) chainID := utils.NewBig(testutils.SimulatedChainID) client := client.NewSimulatedBackendClient(t, backend, testutils.SimulatedChainID) eventBroadcaster := pg.NewEventBroadcaster(cfg.Database().URL(), 0, 0, logger.TestLogger(t), uuid.New()) diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index 2e2d29c248d..39eee3f7b43 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -505,13 +505,14 @@ observationSource = """ data="%s" minConfirmations="2" failOnRevert=false + evmChainID="%s" from="[\\"%s\\"]" ] """ ` // This succeeds for whatever reason revertingData := "0xdeadbeef" - tomlSpec = fmt.Sprintf(tomlSpec, operatorContracts.linkTokenAddress.String(), revertingData, sendingAddr) + tomlSpec = fmt.Sprintf(tomlSpec, operatorContracts.linkTokenAddress.String(), revertingData, testutils.SimulatedChainID.String(), sendingAddr) j := cltest.CreateJobViaWeb(t, app, []byte(cltest.MustJSONMarshal(t, web.CreateJobRequest{TOML: tomlSpec}))) cltest.AwaitJobActive(t, app.JobSpawner(), j.ID, testutils.WaitTimeout(t)) @@ -550,13 +551,14 @@ observationSource = """ data="%s" minConfirmations="2" failOnRevert=true + evmChainID="%s" from="[\\"%s\\"]" ] """ ` // This data is a call to link token's `transfer` function and will revert due to insufficient LINK on the sender address revertingData := "0xa9059cbb000000000000000000000000526485b5abdd8ae9c6a63548e0215a83e7135e6100000000000000000000000000000000000000000000000db069932ea4fe1400" - tomlSpec = fmt.Sprintf(tomlSpec, operatorContracts.linkTokenAddress.String(), revertingData, sendingAddr) + tomlSpec = fmt.Sprintf(tomlSpec, operatorContracts.linkTokenAddress.String(), revertingData, testutils.SimulatedChainID.String(), sendingAddr) j := cltest.CreateJobViaWeb(t, app, []byte(cltest.MustJSONMarshal(t, web.CreateJobRequest{TOML: tomlSpec}))) cltest.AwaitJobActive(t, app.JobSpawner(), j.ID, testutils.WaitTimeout(t)) @@ -587,13 +589,14 @@ observationSource = """ data="%s" minConfirmations="2" failOnRevert=false + evmChainID="%s" from="[\\"%s\\"]" ] """ ` // This data is a call to link token's `transfer` function and will revert due to insufficient LINK on the sender address revertingData := "0xa9059cbb000000000000000000000000526485b5abdd8ae9c6a63548e0215a83e7135e6100000000000000000000000000000000000000000000000db069932ea4fe1400" - tomlSpec = fmt.Sprintf(tomlSpec, operatorContracts.linkTokenAddress.String(), revertingData, sendingAddr) + tomlSpec = fmt.Sprintf(tomlSpec, operatorContracts.linkTokenAddress.String(), revertingData, testutils.SimulatedChainID.String(), sendingAddr) j := cltest.CreateJobViaWeb(t, app, []byte(cltest.MustJSONMarshal(t, web.CreateJobRequest{TOML: tomlSpec}))) cltest.AwaitJobActive(t, app.JobSpawner(), j.ID, testutils.WaitTimeout(t)) @@ -929,8 +932,9 @@ type = "offchainreporting" schemaVersion = 1 name = "boot" contractAddress = "%s" +evmChainID = "%s" isBootstrapPeer = true -`, ocrContractAddress)) +`, ocrContractAddress, testutils.SimulatedChainID.String())) require.NoError(t, err) jb.Name = null.NewString("boot", true) err = appBootstrap.AddJobV2(testutils.Context(t), &jb) @@ -997,6 +1001,7 @@ type = "offchainreporting" schemaVersion = 1 name = "web oracle spec" contractAddress = "%s" +evmChainID = "%s" isBootstrapPeer = false p2pBootstrapPeers = [ "/ip4/127.0.0.1/tcp/%d/p2p/%s" @@ -1022,7 +1027,7 @@ observationSource = """ answer1 [type=median index=0]; """ -`, ocrContractAddress, bootstrapNodePortV1, bootstrapPeerID, keys[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) +`, ocrContractAddress, testutils.SimulatedChainID.String(), bootstrapNodePortV1, bootstrapPeerID, keys[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) require.NoError(t, err) jb.Name = null.NewString("testocr", true) err = apps[i].AddJobV2(testutils.Context(t), &jb) @@ -1157,9 +1162,10 @@ type = "offchainreporting" schemaVersion = 1 name = "boot" contractAddress = "%s" +evmChainID = "%s" forwardingAllowed = true isBootstrapPeer = true -`, ocrContractAddress)) +`, ocrContractAddress, testutils.SimulatedChainID.String())) require.NoError(t, err) jb.Name = null.NewString("boot", true) err = appBootstrap.AddJobV2(testutils.Context(t), &jb) @@ -1227,6 +1233,7 @@ type = "offchainreporting" schemaVersion = 1 name = "web oracle spec" contractAddress = "%s" +evmChainID = "%s" forwardingAllowed = true isBootstrapPeer = false p2pBootstrapPeers = [ @@ -1253,7 +1260,7 @@ observationSource = """ answer1 [type=median index=0]; """ -`, ocrContractAddress, bootstrapNodePortV1, bootstrapPeerID, keys[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) +`, ocrContractAddress, testutils.SimulatedChainID.String(), bootstrapNodePortV1, bootstrapPeerID, keys[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) require.NoError(t, err) jb.Name = null.NewString("testocr", true) err = apps[i].AddJobV2(testutils.Context(t), &jb) @@ -1342,7 +1349,7 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) { Transactions: cltest.LegacyTransactionsFromGasPrices(48_000_000_000, 49_000_000_000, 31_000_000_000), } - evmChainID := utils.NewBig(cfg.DefaultChainID()) + evmChainID := utils.NewBig(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs())) h40 := evmtypes.Head{Hash: utils.NewHash(), Number: 40, EVMChainID: evmChainID} h41 := evmtypes.Head{Hash: b41.Hash, ParentHash: h40.Hash, Number: 41, EVMChainID: evmChainID} h42 := evmtypes.Head{Hash: b42.Hash, ParentHash: h41.Hash, Number: 42, EVMChainID: evmChainID} @@ -1373,7 +1380,7 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) { }) ethClient.On("Dial", mock.Anything).Return(nil) - ethClient.On("ConfiguredChainID", mock.Anything).Return(cfg.DefaultChainID(), nil) + ethClient.On("ConfiguredChainID", mock.Anything).Return(*evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()), nil) ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Maybe().Return(oneETH.ToInt(), nil) // HeadTracker backfill ethClient.On("HeadByHash", mock.Anything, h40.Hash).Return(&h40, nil).Maybe() diff --git a/core/internal/testutils/evmtest/evmtest.go b/core/internal/testutils/evmtest/evmtest.go index 43502ea35ec..62696f75d96 100644 --- a/core/internal/testutils/evmtest/evmtest.go +++ b/core/internal/testutils/evmtest/evmtest.go @@ -34,6 +34,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -44,7 +45,7 @@ func NewChainScopedConfig(t testing.TB, cfg evm.AppConfig) evmconfig.ChainScoped if len(cfg.EVMConfigs()) > 0 { evmCfg = cfg.EVMConfigs()[0] } else { - chainID := utils.NewBigI(0) + var chainID = (*utils.Big)(testutils.FixtureChainID) evmCfg = &evmtoml.EVMConfig{ ChainID: chainID, Chain: evmtoml.Defaults(chainID), @@ -94,7 +95,7 @@ func NewChainRelayExtOpts(t testing.TB, testopts TestChainOpts) evm.ChainRelayEx if testopts.Client != nil { return testopts.Client } - return evmclient.NewNullClient(testopts.GeneralConfig.DefaultChainID(), logger.TestLogger(t)) + return evmclient.NewNullClient(MustGetDefaultChainID(t, testopts.GeneralConfig.EVMConfigs()), logger.TestLogger(t)) } if testopts.LogBroadcaster != nil { opts.GenLogBroadcaster = func(*big.Int) log.Broadcaster { @@ -128,10 +129,21 @@ func NewChainRelayExtOpts(t testing.TB, testopts TestChainOpts) evm.ChainRelayEx return opts } +// Deprecated, this is a replacement function for tests for now removed default evmChainID logic +func MustGetDefaultChainID(t testing.TB, evmCfgs evmtoml.EVMConfigs) *big.Int { + if len(evmCfgs) == 0 { + t.Fatalf("at least one evm chain config must be defined") + } + return evmCfgs[0].ChainID.ToInt() +} + +// Deprecated, this is a replacement function for tests for now removed default chain logic func MustGetDefaultChain(t testing.TB, cc evm.LegacyChainContainer) evm.Chain { - chain, err := cc.Default() - require.NoError(t, err) - return chain + if len(cc.Slice()) == 0 { + t.Fatalf("at least one evm chain container must be defined") + } + + return cc.Slice()[0] } type TestConfigs struct { @@ -150,9 +162,9 @@ func (mo *TestConfigs) PutChains(cs ...evmtoml.EVMConfig) { defer mo.mu.Unlock() chains: for i := range cs { - id := cs[i].ChainID.String() + id := cs[i].ChainID for j, c2 := range mo.EVMConfigs { - if c2.ChainID.String() == id { + if c2.ChainID == id { mo.EVMConfigs[j] = &cs[i] // replace continue chains } @@ -161,7 +173,7 @@ chains: } } -func (mo *TestConfigs) Chains(offset int, limit int, ids ...string) (cs []types.ChainStatus, count int, err error) { +func (mo *TestConfigs) Chains(ids ...relay.ChainID) (cs []types.ChainStatus, count int, err error) { mo.mu.RLock() defer mo.mu.RUnlock() if len(ids) == 0 { @@ -200,19 +212,19 @@ func (mo *TestConfigs) Chains(offset int, limit int, ids ...string) (cs []types. } // Nodes implements evmtypes.Configs -func (mo *TestConfigs) Nodes(chainID utils.Big) (nodes []evmtypes.Node, err error) { +func (mo *TestConfigs) Nodes(id relay.ChainID) (nodes []evmtypes.Node, err error) { mo.mu.RLock() defer mo.mu.RUnlock() for i := range mo.EVMConfigs { c := mo.EVMConfigs[i] - if chainID.Cmp(c.ChainID) == 0 { + if id == c.ChainID.String() { for _, n := range c.Nodes { nodes = append(nodes, legacyNode(n, c.ChainID)) } } } - err = fmt.Errorf("no nodes: chain %s: %w", chainID.String(), chains.ErrNotFound) + err = fmt.Errorf("no nodes: chain %s: %w", id, chains.ErrNotFound) return } diff --git a/core/internal/testutils/testutils.go b/core/internal/testutils/testutils.go index 447475251c4..d50efcc799a 100644 --- a/core/internal/testutils/testutils.go +++ b/core/internal/testutils/testutils.go @@ -427,7 +427,7 @@ func AssertCount(t *testing.T, db *sqlx.DB, tableName string, expected int64) { func AssertCountPerSubject(t *testing.T, db *sqlx.DB, expected int64, subject uuid.UUID) { t.Helper() var count int64 - err := db.Get(&count, `SELECT COUNT(*) FROM eth_txes + err := db.Get(&count, `SELECT COUNT(*) FROM evm.txes WHERE state = 'unstarted' AND subject = $1;`, subject) require.NoError(t, err) require.Equal(t, expected, count) diff --git a/core/scripts/chaincli/handler/keeper_deployer.go b/core/scripts/chaincli/handler/keeper_deployer.go index 089b176695c..eae8c68d332 100644 --- a/core/scripts/chaincli/handler/keeper_deployer.go +++ b/core/scripts/chaincli/handler/keeper_deployer.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ocr2config "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" + ocr3confighelper "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/umbracle/ethgo/abi" @@ -297,11 +298,13 @@ func (d *v21KeeperDeployer) SetKeepers(opts *bind.TransactOpts, cls []cmd.HTTPCl panic(err) } - signerOnchainPublicKeys, transmitterAccounts, f, _, offchainConfigVersion, offchainConfig, err := ocr2config.ContractSetConfigArgsForTests( + signerOnchainPublicKeys, transmitterAccounts, f, _, offchainConfigVersion, offchainConfig, err := ocr3confighelper.ContractSetConfigArgsForTests( 5*time.Second, // deltaProgress time.Duration, 10*time.Second, // deltaResend time.Duration, + 400*time.Millisecond, // deltaInitial time.Duration, 2500*time.Millisecond, // deltaRound time.Duration, 40*time.Millisecond, // deltaGrace time.Duration, + 300*time.Millisecond, // deltaCertifiedCommitRequest time.Duration, 30*time.Second, // deltaStage time.Duration, 50, // rMax uint8, S, // s []int, @@ -309,7 +312,6 @@ func (d *v21KeeperDeployer) SetKeepers(opts *bind.TransactOpts, cls []cmd.HTTPCl offC, // reportingPluginConfig []byte, 20*time.Millisecond, // maxDurationQuery time.Duration, 1600*time.Millisecond, // maxDurationObservation time.Duration, - 800*time.Millisecond, // maxDurationReport time.Duration, 20*time.Millisecond, // maxDurationShouldAcceptFinalizedReport time.Duration, 20*time.Millisecond, // maxDurationShouldTransmitAcceptedReport time.Duration, 1, // f int, diff --git a/core/scripts/chaincli/handler/keeper_launch.go b/core/scripts/chaincli/handler/keeper_launch.go index fb975b48369..83ee6a77129 100644 --- a/core/scripts/chaincli/handler/keeper_launch.go +++ b/core/scripts/chaincli/handler/keeper_launch.go @@ -347,6 +347,7 @@ name = "ocr2-automation" forwardingAllowed = false schemaVersion = 1 contractID = "%s" +contractConfigTrackerPollInterval = "15s" ocrKeyBundleID = "%s" transmitterID = "%s" p2pv2Bootstrappers = [ @@ -358,6 +359,8 @@ chainID = %d [pluginConfig] maxServiceWorkers = 100 +cacheEvictionInterval = "1s" +contractVersion = "%s" mercuryCredentialName = "%s"` // createOCR2KeeperJob creates an ocr2keeper job in the chainlink node by the given address @@ -367,6 +370,12 @@ func (k *Keeper) createOCR2KeeperJob(client cmd.HTTPClient, contractAddr, nodeAd return fmt.Errorf("failed to get node OCR2 key bundle ID: %s", err) } + // Correctly assign contract version in OCR job spec. + var contractVersion string = "v2.0" + if k.cfg.RegistryVersion == keeper.RegistryVersion_2_1 { + contractVersion = "v2.1" + } + request, err := json.Marshal(web.CreateJobRequest{ TOML: fmt.Sprintf(ocr2keeperJobTemplate, contractAddr, // contractID @@ -374,6 +383,7 @@ func (k *Keeper) createOCR2KeeperJob(client cmd.HTTPClient, contractAddr, nodeAd nodeAddr, // transmitterID - node wallet address k.cfg.BootstrapNodeAddr, // bootstrap node key and address k.cfg.ChainID, // chainID + contractVersion, // contractVersion k.cfg.MercuryCredName, // mercury credential name ), }) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 7131bb1d437..adf4f65f519 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -19,7 +19,7 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 - github.com/smartcontractkit/ocr2keepers v0.7.21 + github.com/smartcontractkit/ocr2keepers v0.7.23 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb github.com/spf13/cobra v1.6.1 @@ -298,12 +298,12 @@ require ( github.com/shirou/gopsutil/v3 v3.23.8 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230912195355-fec1da7953fc // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 // indirect - github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e // indirect - github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e // indirect + github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect + github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 641adcd89eb..dcc236cec24 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1375,10 +1375,10 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512 h1:DojChlaudA1HAxwQPKmt/EDf36OUeFJ0LJBYClauMyU= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4 h1:yArUq/0t126bl8BRtjLCf2NuHK35CDIkhc3M5P46apc= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230912195355-fec1da7953fc h1:mQCCjnDz2I1XlYv/fDyFnEB8ryAchlpz12Eg0f7n/N0= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230912195355-fec1da7953fc/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca h1:x7M0m512gtXw5Z4B1WJPZ52VgshoIv+IvHqQ8hsH4AE= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 h1:ByVauKFXphRlSNG47lNuxZ9aicu+r8AoNp933VRPpCw= @@ -1389,16 +1389,16 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 h1:rzbqGoScs9VHGnyCKF7AoQEuUfwJnzcKmGIfaczeanA= github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.21 h1:64CNFoUYVpoJqhQ39WTPIEKVKB5Z/wderX0pIsv/tbA= -github.com/smartcontractkit/ocr2keepers v0.7.21/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= +github.com/smartcontractkit/ocr2keepers v0.7.23 h1:hvMCHm9zTOKGELc40n+JLGmbiW1tkFnHW17qAtoVews= +github.com/smartcontractkit/ocr2keepers v0.7.23/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb/go.mod h1:HNUu4cJekUdsJbwRBCiOybtkPJEfGRELQPe2tkoDEyk= -github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e h1:faa7bAs8xCVsnJoNmAtV18la0wqBoaWSWFqNdjkPdAw= -github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= -github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e h1:JMCSFOQIYOh7zUYi9C3UQG9Lz5ECNejTURBN+Khhwz4= -github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= +github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= +github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= +github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= +github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= github.com/smartcontractkit/wsrpc v0.7.2 h1:iBXzMeg7vc5YoezIQBq896y25BARw7OKbhrb6vPbtRQ= github.com/smartcontractkit/wsrpc v0.7.2/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= diff --git a/core/services/blockhashstore/delegate_test.go b/core/services/blockhashstore/delegate_test.go index 78242d519d7..3060f617876 100644 --- a/core/services/blockhashstore/delegate_test.go +++ b/core/services/blockhashstore/delegate_test.go @@ -89,7 +89,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { defaultWaitBlocks := (int32)(testData.legacyChains.Slice()[0].Config().EVM().FinalityDepth()) t.Run("happy", func(t *testing.T) { - spec := job.Job{BlockhashStoreSpec: &job.BlockhashStoreSpec{WaitBlocks: defaultWaitBlocks}} + spec := job.Job{BlockhashStoreSpec: &job.BlockhashStoreSpec{WaitBlocks: defaultWaitBlocks, EVMChainID: (*utils.Big)(testutils.FixtureChainID)}} services, err := delegate.ServicesForSpec(spec) require.NoError(t, err) @@ -106,6 +106,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { CoordinatorV1Address: &coordinatorV1, CoordinatorV2Address: &coordinatorV2, CoordinatorV2PlusAddress: &coordinatorV2Plus, + EVMChainID: (*utils.Big)(testutils.FixtureChainID), }} services, err := delegate.ServicesForSpec(spec) @@ -150,6 +151,7 @@ func TestDelegate_StartStop(t *testing.T) { WaitBlocks: defaultWaitBlocks, PollPeriod: time.Second, RunTimeout: testutils.WaitTimeout(t), + EVMChainID: (*utils.Big)(testutils.FixtureChainID), }} services, err := delegate.ServicesForSpec(spec) diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index b2e8719e607..9d741130502 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -125,7 +125,6 @@ type ChainlinkApplication struct { ExternalInitiatorManager webhook.ExternalInitiatorManager SessionReaper utils.SleeperTask shutdownOnce sync.Once - explorerClient synchronization.ExplorerClient srvcs []services.ServiceCtx HealthChecker services.Checker Nurse *services.Nurse @@ -222,21 +221,10 @@ func NewApplication(opts ApplicationOpts) (Application, error) { telemetryIngressClient := synchronization.TelemetryIngressClient(&synchronization.NoopTelemetryIngressClient{}) telemetryIngressBatchClient := synchronization.TelemetryIngressBatchClient(&synchronization.NoopTelemetryIngressBatchClient{}) - explorerClient := synchronization.ExplorerClient(&synchronization.NoopExplorerClient{}) monitoringEndpointGen := telemetry.MonitoringEndpointGenerator(&telemetry.NoopAgent{}) - if cfg.Explorer().URL() != nil && cfg.TelemetryIngress().URL() != nil { - globalLogger.Warn("Both ExplorerUrl and TelemetryIngress.Url are set, defaulting to Explorer") - } - - if cfg.Explorer().URL() != nil { - explorerClient = synchronization.NewExplorerClient(cfg.Explorer().URL(), cfg.Explorer().AccessKey(), cfg.Explorer().Secret(), globalLogger) - monitoringEndpointGen = telemetry.NewExplorerAgent(explorerClient) - } - ticfg := cfg.TelemetryIngress() - // Use Explorer over TelemetryIngress if both URLs are set - if cfg.Explorer().URL() == nil && ticfg.URL() != nil { + if ticfg.URL() != nil { if ticfg.UseBatchSend() { telemetryIngressBatchClient = synchronization.NewTelemetryIngressBatchClient(ticfg.URL(), ticfg.ServerPubKey(), keyStore.CSA(), ticfg.Logging(), globalLogger, ticfg.BufferSize(), ticfg.MaxBatchSize(), ticfg.SendInterval(), ticfg.SendTimeout(), ticfg.UniConn()) @@ -248,7 +236,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { monitoringEndpointGen = telemetry.NewIngressAgentWrapper(telemetryIngressClient) } } - srvcs = append(srvcs, explorerClient, telemetryIngressClient, telemetryIngressBatchClient) + srvcs = append(srvcs, telemetryIngressClient, telemetryIngressBatchClient) backupCfg := cfg.Database().Backup() if backupCfg.Mode() != config.DatabaseBackupModeNone && backupCfg.Frequency() > 0 { @@ -471,7 +459,6 @@ func NewApplication(opts ApplicationOpts) (Application, error) { KeyStore: keyStore, SessionReaper: sessions.NewSessionReaper(db.DB, cfg.WebServer(), globalLogger), ExternalInitiatorManager: externalInitiatorManager, - explorerClient: explorerClient, HealthChecker: healthChecker, Nurse: nurse, logger: globalLogger, @@ -750,6 +737,7 @@ func (app *ChainlinkApplication) RunJobV2( "externalJobID": jb.ExternalJobID, "name": jb.Name.ValueOrZero(), "publicKey": jb.VRFSpec.PublicKey[:], + "evmChainID": jb.VRFSpec.EVMChainID.String(), }, "jobRun": map[string]interface{}{ "meta": meta, diff --git a/core/services/chainlink/config.go b/core/services/chainlink/config.go index 73bfeb3d973..5578f8c0453 100644 --- a/core/services/chainlink/config.go +++ b/core/services/chainlink/config.go @@ -129,28 +129,24 @@ func (s *Secrets) SetFrom(f *Secrets) (err error) { err = multierr.Append(err, config.NamedMultiErrorList(err1, "Database")) } - if err2 := s.Explorer.SetFrom(&f.Explorer); err2 != nil { - err = multierr.Append(err, config.NamedMultiErrorList(err2, "Explorer")) + if err2 := s.Password.SetFrom(&f.Password); err2 != nil { + err = multierr.Append(err, config.NamedMultiErrorList(err2, "Password")) } - if err3 := s.Password.SetFrom(&f.Password); err3 != nil { - err = multierr.Append(err, config.NamedMultiErrorList(err3, "Password")) + if err3 := s.Pyroscope.SetFrom(&f.Pyroscope); err3 != nil { + err = multierr.Append(err, config.NamedMultiErrorList(err3, "Pyroscope")) } - if err4 := s.Pyroscope.SetFrom(&f.Pyroscope); err4 != nil { - err = multierr.Append(err, config.NamedMultiErrorList(err4, "Pyroscope")) + if err4 := s.Prometheus.SetFrom(&f.Prometheus); err4 != nil { + err = multierr.Append(err, config.NamedMultiErrorList(err4, "Prometheus")) } - if err5 := s.Prometheus.SetFrom(&f.Prometheus); err5 != nil { - err = multierr.Append(err, config.NamedMultiErrorList(err5, "Prometheus")) + if err5 := s.Mercury.SetFrom(&f.Mercury); err5 != nil { + err = multierr.Append(err, config.NamedMultiErrorList(err5, "Mercury")) } - if err6 := s.Mercury.SetFrom(&f.Mercury); err6 != nil { - err = multierr.Append(err, config.NamedMultiErrorList(err6, "Mercury")) - } - - if err7 := s.Threshold.SetFrom(&f.Threshold); err7 != nil { - err = multierr.Append(err, config.NamedMultiErrorList(err7, "Threshold")) + if err6 := s.Threshold.SetFrom(&f.Threshold); err6 != nil { + err = multierr.Append(err, config.NamedMultiErrorList(err6, "Threshold")) } _, err = utils.MultiErrorList(err) @@ -223,12 +219,6 @@ func (s *Secrets) setEnv() error { s.Database.AllowSimplePasswords = new(bool) *s.Database.AllowSimplePasswords = true } - if explorerKey := env.ExplorerAccessKey.Get(); explorerKey != "" { - s.Explorer.AccessKey = &explorerKey - } - if explorerSecret := env.ExplorerSecret.Get(); explorerSecret != "" { - s.Explorer.Secret = &explorerSecret - } if keystorePassword := env.PasswordKeystore.Get(); keystorePassword != "" { s.Password.Keystore = &keystorePassword } diff --git a/core/services/chainlink/config_explorer.go b/core/services/chainlink/config_explorer.go deleted file mode 100644 index ce6001de195..00000000000 --- a/core/services/chainlink/config_explorer.go +++ /dev/null @@ -1,35 +0,0 @@ -package chainlink - -import ( - "net/url" - - "github.com/smartcontractkit/chainlink/v2/core/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/store/models" -) - -type explorerConfig struct { - explorerURL *models.URL - s toml.ExplorerSecrets -} - -func (e *explorerConfig) URL() *url.URL { - u := (*url.URL)(e.explorerURL) - if *u == zeroURL { - u = nil - } - return u -} - -func (e *explorerConfig) AccessKey() string { - if e.s.AccessKey == nil { - return "" - } - return string(*e.s.AccessKey) -} - -func (e *explorerConfig) Secret() string { - if e.s.Secret == nil { - return "" - } - return string(*e.s.Secret) -} diff --git a/core/services/chainlink/config_explorer_test.go b/core/services/chainlink/config_explorer_test.go deleted file mode 100644 index d68f671690b..00000000000 --- a/core/services/chainlink/config_explorer_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package chainlink - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestExplorerConfig(t *testing.T) { - opts := GeneralConfigOpts{ - ConfigStrings: []string{fullTOML}, - } - cfg, err := opts.New() - require.NoError(t, err) - - e := cfg.Explorer() - assert.Equal(t, "http://explorer.url", e.URL().String()) - -} diff --git a/core/services/chainlink/config_general.go b/core/services/chainlink/config_general.go index c25539684de..688215c6978 100644 --- a/core/services/chainlink/config_general.go +++ b/core/services/chainlink/config_general.go @@ -3,7 +3,6 @@ package chainlink import ( _ "embed" "fmt" - "math/big" "net/url" "os" "path/filepath" @@ -313,15 +312,6 @@ func (g *generalConfig) EVMRPCEnabled() bool { return false } -func (g *generalConfig) DefaultChainID() *big.Int { - for _, c := range g.c.EVM { - if c.IsEnabled() { - return (*big.Int)(c.ChainID) - } - } - return nil -} - func (g *generalConfig) SolanaEnabled() bool { for _, c := range g.c.Solana { if c.IsEnabled() { @@ -409,18 +399,6 @@ func (g *generalConfig) ShutdownGracePeriod() time.Duration { return g.c.ShutdownGracePeriod.Duration() } -func (g *generalConfig) Explorer() config.Explorer { - return &explorerConfig{s: g.secrets.Explorer, explorerURL: g.c.ExplorerURL} -} - -func (g *generalConfig) ExplorerURL() *url.URL { - u := (*url.URL)(g.c.ExplorerURL) - if *u == zeroURL { - u = nil - } - return u -} - func (g *generalConfig) FluxMonitor() config.FluxMonitor { return &fluxMonitorConfig{c: g.c.FluxMonitor} } diff --git a/core/services/chainlink/config_general_secrets.go b/core/services/chainlink/config_general_secrets.go index 6138eab58a3..25dc62d4d01 100644 --- a/core/services/chainlink/config_general_secrets.go +++ b/core/services/chainlink/config_general_secrets.go @@ -14,17 +14,3 @@ func (g *generalConfig) DatabaseURL() url.URL { func (g *generalConfig) DatabaseBackupURL() *url.URL { return g.secrets.Database.BackupURL.URL() } - -func (g *generalConfig) ExplorerAccessKey() string { - if g.secrets.Explorer.AccessKey == nil { - return "" - } - return string(*g.secrets.Explorer.AccessKey) -} - -func (g *generalConfig) ExplorerSecret() string { - if g.secrets.Explorer.Secret == nil { - return "" - } - return string(*g.secrets.Explorer.Secret) -} diff --git a/core/services/chainlink/config_general_test.go b/core/services/chainlink/config_general_test.go index c640e54beb0..8e95e389ffc 100644 --- a/core/services/chainlink/config_general_test.go +++ b/core/services/chainlink/config_general_test.go @@ -24,7 +24,6 @@ func TestTOMLGeneralConfig_Defaults(t *testing.T) { config, err := GeneralConfigOpts{}.New() require.NoError(t, err) assert.Equal(t, (*url.URL)(nil), config.WebServer().BridgeResponseURL()) - assert.Nil(t, config.DefaultChainID()) assert.False(t, config.EVMRPCEnabled()) assert.False(t, config.EVMEnabled()) assert.False(t, config.CosmosEnabled()) @@ -133,9 +132,6 @@ func TestConfig_LogSQL(t *testing.T) { //go:embed testdata/mergingsecretsdata/secrets-database.toml var databaseSecretsTOML string -//go:embed testdata/mergingsecretsdata/secrets-explorer.toml -var explorerSecretsTOML string - //go:embed testdata/mergingsecretsdata/secrets-password.toml var passwordSecretsTOML string @@ -158,8 +154,6 @@ func TestConfig_SecretsMerging(t *testing.T) { t.Run("verify secrets merging in GeneralConfigOpts.New()", func(t *testing.T) { databaseSecrets, err := parseSecrets(databaseSecretsTOML) require.NoErrorf(t, err, "error: %s", err) - explorerSecrets, err1 := parseSecrets(explorerSecretsTOML) - require.NoErrorf(t, err1, "error: %s", err1) passwordSecrets, err2 := parseSecrets(passwordSecretsTOML) require.NoErrorf(t, err2, "error: %s", err2) pyroscopeSecrets, err3 := parseSecrets(pyroscopeSecretsTOML) @@ -179,7 +173,6 @@ func TestConfig_SecretsMerging(t *testing.T) { } secretsFiles := []string{ "testdata/mergingsecretsdata/secrets-database.toml", - "testdata/mergingsecretsdata/secrets-explorer.toml", "testdata/mergingsecretsdata/secrets-password.toml", "testdata/mergingsecretsdata/secrets-pyroscope.toml", "testdata/mergingsecretsdata/secrets-prometheus.toml", @@ -196,8 +189,6 @@ func TestConfig_SecretsMerging(t *testing.T) { assert.Equal(t, databaseSecrets.Database.URL.URL().String(), opts.Secrets.Database.URL.URL().String()) assert.Equal(t, databaseSecrets.Database.BackupURL.URL().String(), opts.Secrets.Database.BackupURL.URL().String()) - assert.Equal(t, (string)(*explorerSecrets.Explorer.AccessKey), (string)(*opts.Secrets.Explorer.AccessKey)) - assert.Equal(t, (string)(*explorerSecrets.Explorer.Secret), (string)(*opts.Secrets.Explorer.Secret)) assert.Equal(t, (string)(*passwordSecrets.Password.Keystore), (string)(*opts.Secrets.Password.Keystore)) assert.Equal(t, (string)(*passwordSecrets.Password.VRF), (string)(*opts.Secrets.Password.VRF)) assert.Equal(t, (string)(*pyroscopeSecrets.Pyroscope.AuthToken), (string)(*opts.Secrets.Pyroscope.AuthToken)) diff --git a/core/services/chainlink/config_mercury.go b/core/services/chainlink/config_mercury.go index 93d88c689b8..1a20dd069d8 100644 --- a/core/services/chainlink/config_mercury.go +++ b/core/services/chainlink/config_mercury.go @@ -11,11 +11,15 @@ type mercuryConfig struct { func (m *mercuryConfig) Credentials(credName string) *models.MercuryCredentials { if mc, ok := m.s.Credentials[credName]; ok { - return &models.MercuryCredentials{ + c := &models.MercuryCredentials{ URL: mc.URL.URL().String(), - Username: string(*mc.Username), Password: string(*mc.Password), + Username: string(*mc.Username), + } + if mc.LegacyURL != nil && mc.LegacyURL.URL() != nil { + c.LegacyURL = mc.LegacyURL.URL().String() } + return c } return nil } diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index e2e12545613..480d06b5806 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -213,7 +213,6 @@ func TestConfig_Marshal(t *testing.T) { global := Config{ Core: toml.Core{ - ExplorerURL: mustURL("http://explorer.url"), InsecureFastScrypt: ptr(true), RootDir: ptr("test/root/dir"), ShutdownGracePeriod: models.MustNewDuration(10 * time.Second), @@ -614,7 +613,7 @@ func TestConfig_Marshal(t *testing.T) { BlocksUntilTxTimeout: ptr[int64](12), ConfirmPollPeriod: relayutils.MustNewDuration(time.Second), FallbackGasPrice: mustDecimal("0.001"), - FeeToken: ptr("ucosm"), + GasToken: ptr("ucosm"), GasLimitMultiplier: mustDecimal("1.2"), MaxMsgsPerBatch: ptr[int64](17), OCR2CachePollPeriod: relayutils.MustNewDuration(time.Minute), @@ -635,8 +634,7 @@ func TestConfig_Marshal(t *testing.T) { exp string }{ {"empty", Config{}, ``}, - {"global", global, `ExplorerURL = 'http://explorer.url' -InsecureFastScrypt = true + {"global", global, `InsecureFastScrypt = true RootDir = 'test/root/dir' ShutdownGracePeriod = '10s' @@ -962,7 +960,7 @@ BlockRate = '1m0s' BlocksUntilTxTimeout = 12 ConfirmPollPeriod = '1s' FallbackGasPrice = '0.001' -FeeToken = 'ucosm' +GasToken = 'ucosm' GasLimitMultiplier = '1.2' MaxMsgsPerBatch = 17 OCR2CachePollPeriod = '1m0s' @@ -1303,9 +1301,7 @@ func TestSecrets_Validate(t *testing.T) { }{ {name: "partial", toml: ` -Database.AllowSimplePasswords = true -Explorer.AccessKey = "access_key" -Explorer.Secret = "secret"`, +Database.AllowSimplePasswords = true`, exp: `invalid secrets: 2 errors: - Database.URL: empty: must be provided and non-empty - Password.Keystore: empty: must be provided and non-empty`}, diff --git a/core/services/chainlink/legacy.env b/core/services/chainlink/legacy.env index 142b4e3b872..01469736e0f 100644 --- a/core/services/chainlink/legacy.env +++ b/core/services/chainlink/legacy.env @@ -7,9 +7,6 @@ AUDIT_LOGGER_JSON_WRAPPER_KEY= CHAIN_TYPE= CHAINLINK_DEV= -EXPLORER_ACCESS_KEY= -EXPLORER_SECRET= -EXPLORER_URL= FLAGS_CONTRACT_ADDRESS= INSECURE_FAST_SCRYPT= REAPER_EXPIRATION= diff --git a/core/services/chainlink/mocks/general_config.go b/core/services/chainlink/mocks/general_config.go index 289c23b26b2..416fbd33756 100644 --- a/core/services/chainlink/mocks/general_config.go +++ b/core/services/chainlink/mocks/general_config.go @@ -3,11 +3,8 @@ package mocks import ( - big "math/big" - - config "github.com/smartcontractkit/chainlink/v2/core/config" - cosmos "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" + config "github.com/smartcontractkit/chainlink/v2/core/config" mock "github.com/stretchr/testify/mock" @@ -147,22 +144,6 @@ func (_m *GeneralConfig) Database() config.Database { return r0 } -// DefaultChainID provides a mock function with given fields: -func (_m *GeneralConfig) DefaultChainID() *big.Int { - ret := _m.Called() - - var r0 *big.Int - if rf, ok := ret.Get(0).(func() *big.Int); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - return r0 -} - // EVMConfigs provides a mock function with given fields: func (_m *GeneralConfig) EVMConfigs() toml.EVMConfigs { ret := _m.Called() @@ -207,22 +188,6 @@ func (_m *GeneralConfig) EVMRPCEnabled() bool { return r0 } -// Explorer provides a mock function with given fields: -func (_m *GeneralConfig) Explorer() config.Explorer { - ret := _m.Called() - - var r0 config.Explorer - if rf, ok := ret.Get(0).(func() config.Explorer); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(config.Explorer) - } - } - - return r0 -} - // Feature provides a mock function with given fields: func (_m *GeneralConfig) Feature() config.Feature { ret := _m.Called() diff --git a/core/services/chainlink/relayer_chain_interoperators.go b/core/services/chainlink/relayer_chain_interoperators.go index f342176f4cf..1a0dbadd266 100644 --- a/core/services/chainlink/relayer_chain_interoperators.go +++ b/core/services/chainlink/relayer_chain_interoperators.go @@ -110,23 +110,13 @@ func InitEVM(ctx context.Context, factory RelayerFactory, config EVMFactoryConfi } legacyMap := make(map[string]evm.Chain) - var defaultChain evm.Chain - for id, a := range adapters { // adapter is a service op.srvs = append(op.srvs, a) op.loopRelayers[id] = a - legacyMap[id.ChainID.String()] = a.Chain() - if a.Default() { - defaultChain = a.Chain() - } - + legacyMap[id.ChainID] = a.Chain() } op.legacyChains.EVMChains = evm.NewLegacyChains(legacyMap, config.AppConfig.EVMConfigs()) - // TODO BCF-2510 this may not be necessary if EVM is not enabled by default - if defaultChain != nil { - op.legacyChains.EVMChains.SetDefault(defaultChain) - } return nil } } @@ -143,7 +133,7 @@ func InitCosmos(ctx context.Context, factory RelayerFactory, config CosmosFactor for id, a := range adapters { op.srvs = append(op.srvs, a) op.loopRelayers[id] = a - legacyMap[id.ChainID.String()] = a.Chain() + legacyMap[id.ChainID] = a.Chain() } op.legacyChains.CosmosChains = cosmos.NewLegacyChains(legacyMap) @@ -276,7 +266,6 @@ func (rs *CoreRelayerChainInteroperators) Node(ctx context.Context, name string) // ids must be a string representation of relay.Identifier // ids are a filter; if none are specified, all are returned. -// TODO: BCF-2440/1 this signature can be changed to id relay.Identifier which is a much better API func (rs *CoreRelayerChainInteroperators) NodeStatuses(ctx context.Context, offset, limit int, relayerIDs ...relay.ID) (nodes []types.NodeStatus, count int, err error) { var ( totalErr error diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index 29dffd1df19..9cfe354fe91 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -140,7 +140,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Chain: coscfg.Chain{ GasLimitMultiplier: ptr(decimal.RequireFromString("1.55555")), Bech32Prefix: ptr("wasm"), - FeeToken: ptr("cosm"), + GasToken: ptr("cosm"), }, Nodes: cosmos.CosmosNodes{ &coscfg.Node{ @@ -155,7 +155,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Chain: coscfg.Chain{ GasLimitMultiplier: ptr(decimal.RequireFromString("0.777")), Bech32Prefix: ptr("wasm"), - FeeToken: ptr("cosm"), + GasToken: ptr("cosm"), }, Nodes: cosmos.CosmosNodes{ &coscfg.Node{ @@ -412,19 +412,19 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { assert.NoError(t, err) stat, err := cr.ChainStatus(testctx, wantId) assert.NoError(t, err) - assert.Equal(t, wantId.ChainID.String(), stat.ID) + assert.Equal(t, wantId.ChainID, stat.ID) // check legacy chains for evm and cosmos if wantId.Network == relay.EVM { - c, err := cr.LegacyEVMChains().Get(wantId.ChainID.String()) + c, err := cr.LegacyEVMChains().Get(wantId.ChainID) assert.NoError(t, err) assert.NotNil(t, c) - assert.Equal(t, wantId.ChainID.String(), c.ID().String()) + assert.Equal(t, wantId.ChainID, c.ID().String()) } if wantId.Network == relay.Cosmos { - c, err := cr.LegacyCosmosChains().Get(wantId.ChainID.String()) + c, err := cr.LegacyCosmosChains().Get(wantId.ChainID) assert.NoError(t, err) assert.NotNil(t, c) - assert.Equal(t, wantId.ChainID.String(), c.ID()) + assert.Equal(t, wantId.ChainID, c.ID()) } } } diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index 6c09f5c4ab4..0a0d653f5fc 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -58,11 +58,11 @@ func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (m legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(evmRelayExtenders) for _, ext := range evmRelayExtenders.Slice() { relayID := relay.ID{Network: relay.EVM, ChainID: relay.ChainID(ext.Chain().ID().String())} - chain, err := legacyChains.Get(relayID.ChainID.String()) + chain, err := legacyChains.Get(relayID.ChainID) if err != nil { return nil, err } - relayer := evmrelay.NewLoopRelayAdapter(evmrelay.NewRelayer(ccOpts.DB, chain, r.QConfig, ccOpts.Logger, config.CSAETHKeystore, ccOpts.EventBroadcaster), ext) + relayer := evmrelay.NewLoopRelayServerAdapter(evmrelay.NewRelayer(ccOpts.DB, chain, r.QConfig, ccOpts.Logger, config.CSAETHKeystore, ccOpts.EventBroadcaster), ext) relayers[relayID] = relayer } @@ -98,10 +98,6 @@ func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.SolanaCo continue } - // all the lower level APIs expect a config slice. create a single valued set per id - // TODO BCF-2605: clean this up - singleChainCfg := solana.SolanaConfigs{chainCfg} - if cmdName := env.SolanaPluginCmd.Get(); cmdName != "" { // setup the solana relayer to be a LOOP @@ -128,14 +124,13 @@ func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.SolanaCo opts := solana.ChainOpts{ Logger: solLggr, KeyStore: signer, - Configs: solana.NewConfigs(singleChainCfg), } chain, err := solana.NewChain(chainCfg, opts) if err != nil { return nil, err } - solanaRelayers[relayId] = relay.NewRelayerAdapter(pkgsolana.NewRelayer(solLggr, chain), chain) + solanaRelayers[relayId] = relay.NewRelayerServerAdapter(pkgsolana.NewRelayer(solLggr, chain), chain) } } return solanaRelayers, nil @@ -172,10 +167,6 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs starknet.St continue } - // all the lower level APIs expect a config slice. create a single valued set per id - // TODO BCF-2605: clean this up - singleChainCfg := starknet.StarknetConfigs{chainCfg} - if cmdName := env.StarknetPluginCmd.Get(); cmdName != "" { // setup the starknet relayer to be a LOOP cfgTOML, err := toml.Marshal(struct { @@ -200,7 +191,6 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs starknet.St opts := starknet.ChainOpts{ Logger: starkLggr, KeyStore: loopKs, - Configs: starknet.NewConfigs(singleChainCfg), } chain, err := starknet.NewChain(chainCfg, opts) @@ -208,7 +198,7 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs starknet.St return nil, err } - starknetRelayers[relayId] = relay.NewRelayerAdapter(pkgstarknet.NewRelayer(starkLggr, chain), chain) + starknetRelayers[relayId] = relay.NewRelayerServerAdapter(pkgstarknet.NewRelayer(starkLggr, chain), chain) } } return starknetRelayers, nil @@ -235,14 +225,13 @@ func (r *RelayerFactory) NewCosmos(ctx context.Context, config CosmosFactoryConf opts := cosmos.ChainOpts{ QueryConfig: r.QConfig, - Logger: lggr.Named(relayId.ChainID.String()), + Logger: lggr.Named(relayId.ChainID), DB: r.DB, KeyStore: loopKs, EventBroadcaster: config.EventBroadcaster, } - opts.Configs = cosmos.NewConfigs(cosmos.CosmosConfigs{chainCfg}) - chain, err := cosmos.NewChain(chainCfg, opts) + chain, err := cosmos.NewChain(chainCfg, opts) if err != nil { return nil, fmt.Errorf("failed to load Cosmos chain %q: %w", relayId, err) } diff --git a/core/services/chainlink/testdata/config-empty-effective.toml b/core/services/chainlink/testdata/config-empty-effective.toml index 8c3eef53f6a..45e92a147d3 100644 --- a/core/services/chainlink/testdata/config-empty-effective.toml +++ b/core/services/chainlink/testdata/config-empty-effective.toml @@ -1,4 +1,3 @@ -ExplorerURL = '' InsecureFastScrypt = false RootDir = '~/.chainlink' ShutdownGracePeriod = '5s' diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index 4279cc729f9..92d0b553d6e 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -1,4 +1,3 @@ -ExplorerURL = 'http://explorer.url' InsecureFastScrypt = true RootDir = 'test/root/dir' ShutdownGracePeriod = '10s' @@ -325,7 +324,7 @@ BlockRate = '1m0s' BlocksUntilTxTimeout = 12 ConfirmPollPeriod = '1s' FallbackGasPrice = '0.001' -FeeToken = 'ucosm' +GasToken = 'ucosm' GasLimitMultiplier = '1.2' MaxMsgsPerBatch = 17 OCR2CachePollPeriod = '1m0s' diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index d6b38349b83..665de9be8cb 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -1,4 +1,3 @@ -ExplorerURL = '' InsecureFastScrypt = false RootDir = 'my/root/dir' ShutdownGracePeriod = '5s' @@ -456,7 +455,7 @@ BlockRate = '6s' BlocksUntilTxTimeout = 30 ConfirmPollPeriod = '1s' FallbackGasPrice = '0.015' -FeeToken = 'ucosm' +GasToken = 'ucosm' GasLimitMultiplier = '1.5' MaxMsgsPerBatch = 13 OCR2CachePollPeriod = '4s' @@ -474,7 +473,7 @@ BlockRate = '6s' BlocksUntilTxTimeout = 20 ConfirmPollPeriod = '1s' FallbackGasPrice = '0.015' -FeeToken = 'ucosm' +GasToken = 'ucosm' GasLimitMultiplier = '1.5' MaxMsgsPerBatch = 100 OCR2CachePollPeriod = '4s' diff --git a/core/services/chainlink/testdata/mergingsecretsdata/secrets-explorer.toml b/core/services/chainlink/testdata/mergingsecretsdata/secrets-explorer.toml deleted file mode 100644 index 6f0682240a8..00000000000 --- a/core/services/chainlink/testdata/mergingsecretsdata/secrets-explorer.toml +++ /dev/null @@ -1,3 +0,0 @@ -[Explorer] -AccessKey = "EXPLORER_ACCESS_KEY" -Secret = "EXPLORER_TOKEN" \ No newline at end of file diff --git a/core/services/chainlink/testdata/secrets-full-redacted.toml b/core/services/chainlink/testdata/secrets-full-redacted.toml index c0c97b76e57..740c3250edb 100644 --- a/core/services/chainlink/testdata/secrets-full-redacted.toml +++ b/core/services/chainlink/testdata/secrets-full-redacted.toml @@ -3,10 +3,6 @@ URL = 'xxxxx' BackupURL = 'xxxxx' AllowSimplePasswords = false -[Explorer] -AccessKey = 'xxxxx' -Secret = 'xxxxx' - [Password] Keystore = 'xxxxx' VRF = 'xxxxx' @@ -28,3 +24,9 @@ Password = 'xxxxx' URL = 'xxxxx' Username = 'xxxxx' Password = 'xxxxx' + +[Mercury.Credentials.cred3] +LegacyURL = 'xxxxx' +URL = 'xxxxx' +Username = 'xxxxx' +Password = 'xxxxx' diff --git a/core/services/chainlink/testdata/secrets-full.toml b/core/services/chainlink/testdata/secrets-full.toml index 3773a798f7e..37e5dafc7d7 100644 --- a/core/services/chainlink/testdata/secrets-full.toml +++ b/core/services/chainlink/testdata/secrets-full.toml @@ -2,10 +2,6 @@ URL = "postgresql://user:pass@localhost:5432/dbname?sslmode=disable" BackupURL = "postgresql://user:pass@localhost:5432/backupdbname?sslmode=disable" -[Explorer] -AccessKey = "access_key" -Secret = "secret" - [Password] Keystore = "keystore_pass" VRF = "VRF_pass" @@ -25,3 +21,9 @@ Password = "password1" URL = "https://chain2.link" Username = "username2" Password = "password2" + +[Mercury.Credentials.cred3] +LegacyURL = "https://chain2.old.link" +URL = "https://chain2.link" +Username = "username2" +Password = "password2" diff --git a/core/services/chainlink/testdata/secrets-multi-redacted.toml b/core/services/chainlink/testdata/secrets-multi-redacted.toml index 32e4b6fca34..27a1eb9fb6c 100644 --- a/core/services/chainlink/testdata/secrets-multi-redacted.toml +++ b/core/services/chainlink/testdata/secrets-multi-redacted.toml @@ -2,9 +2,5 @@ URL = 'xxxxx' AllowSimplePasswords = false -[Explorer] -AccessKey = 'xxxxx' -Secret = 'xxxxx' - [Password] Keystore = 'xxxxx' diff --git a/core/services/chainlink/testdata/secrets-multi.toml b/core/services/chainlink/testdata/secrets-multi.toml index f497d20f307..23438f9e4ab 100644 --- a/core/services/chainlink/testdata/secrets-multi.toml +++ b/core/services/chainlink/testdata/secrets-multi.toml @@ -1,9 +1,5 @@ [Database] URL = "postgresql://user:pass@localhost:5432/dbname?sslmode=disable" -[Explorer] -AccessKey = "access_key" -Secret = "secret" - [Password] Keystore = "keystore_pass" diff --git a/core/services/directrequest/delegate.go b/core/services/directrequest/delegate.go index 4e2ca1e1899..56020f77566 100644 --- a/core/services/directrequest/delegate.go +++ b/core/services/directrequest/delegate.go @@ -339,6 +339,7 @@ func (l *listener) handleOracleRequest(request *operator_wrapper.OperatorOracleR ctx, cancel := runCloserChannel.NewCtx() defer cancel() + evmChainID := lb.EVMChainID() vars := pipeline.NewVarsFrom(map[string]interface{}{ "jobSpec": map[string]interface{}{ "databaseID": l.job.ID, @@ -347,6 +348,7 @@ func (l *listener) handleOracleRequest(request *operator_wrapper.OperatorOracleR "pipelineSpec": &pipeline.Spec{ ForwardingAllowed: l.job.ForwardingAllowed, }, + "evmChainID": evmChainID.String(), }, "jobRun": map[string]interface{}{ "meta": meta, diff --git a/core/services/directrequest/delegate_test.go b/core/services/directrequest/delegate_test.go index 0a4334e8693..ffd78443cc2 100644 --- a/core/services/directrequest/delegate_test.go +++ b/core/services/directrequest/delegate_test.go @@ -57,7 +57,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { }) t.Run("Spec with DirectRequestSpec", func(t *testing.T) { - spec := job.Job{DirectRequestSpec: &job.DirectRequestSpec{}, PipelineSpec: &pipeline.Spec{}} + spec := job.Job{DirectRequestSpec: &job.DirectRequestSpec{EVMChainID: (*utils.Big)(testutils.FixtureChainID)}, PipelineSpec: &pipeline.Spec{}} services, err := delegate.ServicesForSpec(spec) require.NoError(t, err) assert.Len(t, services, 1) @@ -143,6 +143,7 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { log.On("ReceiptsRoot").Return(common.Hash{}) log.On("TransactionsRoot").Return(common.Hash{}) log.On("StateRoot").Return(common.Hash{}) + log.On("EVMChainID").Return(*big.NewInt(0)) uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) logOracleRequest := operator_wrapper.OperatorOracleRequest{ @@ -203,6 +204,7 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { }).Maybe() log.On("DecodedLog").Return(&logOracleRequest).Maybe() log.On("String").Return("") + log.On("EVMChainID").Return(*big.NewInt(0)) uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil).Maybe() err := uni.service.Start(testutils.Context(t)) @@ -295,6 +297,7 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { runLog.On("ReceiptsRoot").Return(common.Hash{}) runLog.On("TransactionsRoot").Return(common.Hash{}) runLog.On("StateRoot").Return(common.Hash{}) + runLog.On("EVMChainID").Return(*big.NewInt(0)) uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) logOracleRequest := operator_wrapper.OperatorOracleRequest{ @@ -364,6 +367,7 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { log.On("ReceiptsRoot").Return(common.Hash{}) log.On("TransactionsRoot").Return(common.Hash{}) log.On("StateRoot").Return(common.Hash{}) + log.On("EVMChainID").Return(*big.NewInt(0)) uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) logOracleRequest := operator_wrapper.OperatorOracleRequest{ @@ -456,6 +460,7 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { log.On("ReceiptsRoot").Return(common.Hash{}) log.On("TransactionsRoot").Return(common.Hash{}) log.On("StateRoot").Return(common.Hash{}) + log.On("EVMChainID").Return(*big.NewInt(0)) uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) logOracleRequest := operator_wrapper.OperatorOracleRequest{ diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index c864b8c1922..db6497d11f6 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -73,6 +73,7 @@ type = "offchainreporting" schemaVersion = 1 name = "example OCR1 spec" externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F46" +evmChainID = 0 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pBootstrapPeers = [ "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", diff --git a/core/services/fluxmonitorv2/flux_monitor.go b/core/services/fluxmonitorv2/flux_monitor.go index ad34c84b1d8..34ca121e9a9 100644 --- a/core/services/fluxmonitorv2/flux_monitor.go +++ b/core/services/fluxmonitorv2/flux_monitor.go @@ -735,6 +735,7 @@ func (fm *FluxMonitor) respondToNewRoundLog(log flux_aggregator_wrapper.FluxAggr "databaseID": fm.jobSpec.ID, "externalJobID": fm.jobSpec.ExternalJobID, "name": fm.jobSpec.Name.ValueOrZero(), + "evmChainID": fm.chainID.String(), }, "jobRun": map[string]interface{}{ "meta": metaDataForBridge, @@ -938,6 +939,7 @@ func (fm *FluxMonitor) pollIfEligible(pollReq PollRequestType, deviationChecker "databaseID": fm.jobSpec.ID, "externalJobID": fm.jobSpec.ExternalJobID, "name": fm.jobSpec.Name.ValueOrZero(), + "evmChainID": fm.chainID.String(), }, "jobRun": map[string]interface{}{ "meta": metaDataForBridge, diff --git a/core/services/fluxmonitorv2/flux_monitor_test.go b/core/services/fluxmonitorv2/flux_monitor_test.go index 923658fef09..5a67c2fa1da 100644 --- a/core/services/fluxmonitorv2/flux_monitor_test.go +++ b/core/services/fluxmonitorv2/flux_monitor_test.go @@ -445,6 +445,7 @@ func TestFluxMonitor_PollIfEligible(t *testing.T) { "databaseID": int32(0), "externalJobID": uuid.UUID{}, "name": "", + "evmChainID": testutils.FixtureChainID.String(), }, }, ), mock.Anything). @@ -1882,6 +1883,7 @@ func TestFluxMonitor_DrumbeatTicker(t *testing.T) { "databaseID": int32(0), "externalJobID": uuid.UUID{}, "name": "", + "evmChainID": testutils.FixtureChainID.String(), }, }, ), mock.Anything). diff --git a/core/services/fluxmonitorv2/integrations_test.go b/core/services/fluxmonitorv2/integrations_test.go index e76d859e81b..5b6a94cac58 100644 --- a/core/services/fluxmonitorv2/integrations_test.go +++ b/core/services/fluxmonitorv2/integrations_test.go @@ -644,6 +644,7 @@ type = "fluxmonitor" schemaVersion = 1 name = "example flux monitor spec" contractAddress = "%s" +evmChainID = "%s" threshold = 0.5 absoluteThreshold = 0.0 @@ -661,7 +662,7 @@ ds1 -> ds1_parse """ ` - s = fmt.Sprintf(s, fa.aggregatorContractAddress, pollTimerPeriod, mockServer.URL) + s = fmt.Sprintf(s, fa.aggregatorContractAddress, testutils.SimulatedChainID.String(), pollTimerPeriod, mockServer.URL) // raise flags to disable polling _, err = fa.flagsContract.RaiseFlag(fa.sergey, utils.ZeroAddress) // global kill switch @@ -752,6 +753,7 @@ type = "fluxmonitor" schemaVersion = 1 name = "example flux monitor spec" contractAddress = "%s" +evmChainID = "%s" threshold = 0.5 absoluteThreshold = 0.0 @@ -769,7 +771,7 @@ ds1 -> ds1_parse """ ` - s = fmt.Sprintf(s, fa.aggregatorContractAddress, "1000ms", mockServer.URL) + s = fmt.Sprintf(s, fa.aggregatorContractAddress, testutils.SimulatedChainID.String(), "1000ms", mockServer.URL) // raise flags _, err = fa.flagsContract.RaiseFlag(fa.sergey, utils.ZeroAddress) // global kill switch @@ -862,6 +864,7 @@ type = "fluxmonitor" schemaVersion = 1 name = "example flux monitor spec" contractAddress = "%s" +evmChainID = "%s" threshold = 0.5 absoluteThreshold = 0.01 @@ -879,7 +882,7 @@ ds1 -> ds1_parse """ ` - s := fmt.Sprintf(toml, fa.aggregatorContractAddress, "100ms", mockServer.URL) + s := fmt.Sprintf(toml, fa.aggregatorContractAddress, testutils.SimulatedChainID.String(), "100ms", mockServer.URL) // raise flags _, err = fa.flagsContract.RaiseFlag(fa.sergey, utils.ZeroAddress) // global kill switch @@ -963,6 +966,7 @@ type = "fluxmonitor" schemaVersion = 1 name = "example flux monitor spec" contractAddress = "%s" +evmChainID = "%s" threshold = 0.5 absoluteThreshold = 0.0 @@ -981,7 +985,7 @@ ds1 -> ds1_parse -> ds1_multiply """ ` - s = fmt.Sprintf(s, fa.aggregatorContractAddress, "200ms", mockServer.URL) + s = fmt.Sprintf(s, fa.aggregatorContractAddress, testutils.SimulatedChainID.String(), "200ms", mockServer.URL) requestBody, err := json.Marshal(web.CreateJobRequest{ TOML: string(s), }) diff --git a/core/services/fluxmonitorv2/orm_test.go b/core/services/fluxmonitorv2/orm_test.go index caaea838517..1377737c49b 100644 --- a/core/services/fluxmonitorv2/orm_test.go +++ b/core/services/fluxmonitorv2/orm_test.go @@ -23,6 +23,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" + "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestORM_MostRecentFluxMonitorRoundID(t *testing.T) { @@ -161,6 +162,7 @@ func makeJob(t *testing.T) *job.Job { IdleTimerDisabled: false, CreatedAt: time.Now(), UpdatedAt: time.Now(), + EVMChainID: (*utils.Big)(testutils.FixtureChainID), }, } } diff --git a/core/services/gateway/api/constants.go b/core/services/gateway/api/constants.go index 9ab7e0c4495..d64f7dded19 100644 --- a/core/services/gateway/api/constants.go +++ b/core/services/gateway/api/constants.go @@ -6,7 +6,7 @@ const ( NoError ErrorCode = iota UserMessageParseError UnsupportedDONIdError - InternalHandlerError + HandlerError RequestTimeoutError NodeReponseEncodingError FatalError @@ -18,7 +18,7 @@ func ToJsonRPCErrorCode(errorCode ErrorCode) int { NoError: 0, UserMessageParseError: -32700, // Parse Error UnsupportedDONIdError: -32602, // Invalid Params - InternalHandlerError: -32000, // Server Error + HandlerError: -32600, // Invalid Request RequestTimeoutError: -32000, // Server Error NodeReponseEncodingError: -32603, // Internal Error FatalError: -32000, // Server Error @@ -37,7 +37,7 @@ func ToHttpErrorCode(errorCode ErrorCode) int { NoError: 200, // OK UserMessageParseError: 400, // Bad Request UnsupportedDONIdError: 400, // Bad Request - InternalHandlerError: 500, // Internal Server Error + HandlerError: 400, // Bad Request RequestTimeoutError: 504, // Gateway Timeout NodeReponseEncodingError: 500, // Internal Server Error FatalError: 500, // Internal Server Error diff --git a/core/services/gateway/connectionmanager.go b/core/services/gateway/connectionmanager.go index 17a31014c81..961212239f2 100644 --- a/core/services/gateway/connectionmanager.go +++ b/core/services/gateway/connectionmanager.go @@ -87,13 +87,16 @@ func NewConnectionManager(gwConfig *config.GatewayConfig, clock utils.Clock, lgg return nil, fmt.Errorf("duplicate node address %s in DON %s", nodeAddress, donConfig.DonId) } nodes[nodeAddress] = &nodeState{conn: network.NewWSConnectionWrapper()} + if nodes[nodeAddress].conn == nil { + return nil, fmt.Errorf("error creating WSConnectionWrapper for node %s", nodeAddress) + } } dons[donConfig.DonId] = &donConnectionManager{ donConfig: &donConfig, codec: codec, nodes: nodes, shutdownCh: make(chan struct{}), - lggr: lggr, + lggr: lggr.Named("DONConnectionManager." + donConfig.DonId), } } connMgr := &connectionManager{ @@ -232,11 +235,18 @@ func (m *donConnectionManager) SetHandler(handler handlers.Handler) { } func (m *donConnectionManager) SendToNode(ctx context.Context, nodeAddress string, msg *api.Message) error { + if msg == nil { + return errors.New("nil message") + } data, err := m.codec.EncodeRequest(msg) if err != nil { return fmt.Errorf("error encoding request for node %s: %v", nodeAddress, err) } - return m.nodes[nodeAddress].conn.Write(ctx, websocket.BinaryMessage, data) + nodeState := m.nodes[nodeAddress] + if nodeState == nil { + return fmt.Errorf("node %s not found", nodeAddress) + } + return nodeState.conn.Write(ctx, websocket.BinaryMessage, data) } func (m *donConnectionManager) readLoop(nodeAddress string, nodeState *nodeState) { diff --git a/core/services/gateway/connectionmanager_test.go b/core/services/gateway/connectionmanager_test.go index f924761439a..d198ef67295 100644 --- a/core/services/gateway/connectionmanager_test.go +++ b/core/services/gateway/connectionmanager_test.go @@ -8,8 +8,10 @@ import ( "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway" + "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" gc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/common" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/config" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/network" @@ -208,3 +210,20 @@ func TestConnectionManager_FinalizeHandshake(t *testing.T) { err = mgr.FinalizeHandshake(attemptId, response, nil) require.ErrorIs(t, err, network.ErrChallengeInvalidSignature) } + +func TestConnectionManager_SendToNode_Failures(t *testing.T) { + t.Parallel() + + config, nodes := newTestConfig(t, 2) + clock := utils.NewFixedClock(time.Now()) + mgr, err := gateway.NewConnectionManager(config, clock, logger.TestLogger(t)) + require.NoError(t, err) + + donMgr := mgr.DONConnectionManager("my_don_1") + err = donMgr.SendToNode(testutils.Context(t), nodes[0].Address, nil) + require.Error(t, err) + + message := &api.Message{} + err = donMgr.SendToNode(testutils.Context(t), "some_other_node", message) + require.Error(t, err) +} diff --git a/core/services/gateway/connector/connector.go b/core/services/gateway/connector/connector.go index 1cd1995e3a4..ca0a45e98c8 100644 --- a/core/services/gateway/connector/connector.go +++ b/core/services/gateway/connector/connector.go @@ -85,7 +85,7 @@ func NewGatewayConnector(config *ConnectorConfig, signer Signer, handler Gateway signer: signer, handler: handler, shutdownCh: make(chan struct{}), - lggr: lggr, + lggr: lggr.Named("GatewayConnector"), } gateways := make(map[string]*gatewayState) urlToId := make(map[string]string) diff --git a/core/services/gateway/gateway.go b/core/services/gateway/gateway.go index 8c77e9b7485..fd158d6e0b8 100644 --- a/core/services/gateway/gateway.go +++ b/core/services/gateway/gateway.go @@ -4,9 +4,12 @@ import ( "context" "encoding/json" "fmt" + "strings" "go.uber.org/multierr" + "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/config" @@ -59,6 +62,12 @@ func NewGatewayFromConfig(config *config.GatewayConfig, handlerFactory HandlerFa if donConnMgr == nil { return nil, fmt.Errorf("connection manager ID %s not found", donConfig.DonId) } + for idx, nodeConfig := range donConfig.Members { + donConfig.Members[idx].Address = strings.ToLower(nodeConfig.Address) + if !common.IsHexAddress(nodeConfig.Address) { + return nil, fmt.Errorf("invalid node address %s", nodeConfig.Address) + } + } handler, err := handlerFactory.NewHandler(donConfig.HandlerName, donConfig.HandlerConfig, &donConfig, donConnMgr) if err != nil { return nil, err @@ -127,7 +136,7 @@ func (g *gateway) ProcessRequest(ctx context.Context, rawRequest []byte) (rawRes responseCh := make(chan handlers.UserCallbackPayload, 1) err = handler.HandleUserMessage(ctx, msg, responseCh) if err != nil { - return newError(g.codec, msg.Body.MessageId, api.InternalHandlerError, err.Error()) + return newError(g.codec, msg.Body.MessageId, api.HandlerError, err.Error()) } // await response var response handlers.UserCallbackPayload diff --git a/core/services/gateway/gateway_test.go b/core/services/gateway/gateway_test.go index a6662505db0..5fad6315a31 100644 --- a/core/services/gateway/gateway_test.go +++ b/core/services/gateway/gateway_test.go @@ -49,6 +49,10 @@ HandlerName = "dummy" [[dons]] DonId = "my_don_2" HandlerName = "dummy" + +[[dons.Members]] +Name = "node one" +Address = "0x0001020304050607080900010203040506070809" `) lggr := logger.TestLogger(t) @@ -102,6 +106,24 @@ SomeOtherField = "abcd" require.Error(t, err) } +func TestGateway_NewGatewayFromConfig_InvalidNodeAddress(t *testing.T) { + t.Parallel() + + tomlConfig := buildConfig(` +[[dons]] +HandlerName = "dummy" +DonId = "my_don" + +[[dons.Members]] +Name = "node one" +Address = "0xnot_an_address" +`) + + lggr := logger.TestLogger(t) + _, err := gateway.NewGatewayFromConfig(parseTOMLConfig(t, tomlConfig), gateway.NewHandlerFactory(nil, lggr), lggr) + require.Error(t, err) +} + func TestGateway_CleanStartAndClose(t *testing.T) { t.Parallel() @@ -220,6 +242,6 @@ func TestGateway_ProcessRequest_HandlerError(t *testing.T) { req := newSignedRequest(t, "abcd", "request", "testDON", []byte{}) response, statusCode := gw.ProcessRequest(testutils.Context(t), req) - requireJsonRPCError(t, response, "abcd", -32000, "failure") - require.Equal(t, 500, statusCode) + requireJsonRPCError(t, response, "abcd", -32600, "failure") + require.Equal(t, 400, statusCode) } diff --git a/core/services/gateway/handlers/functions/allowlist.go b/core/services/gateway/handlers/functions/allowlist.go index af00aeac915..19bc61aabad 100644 --- a/core/services/gateway/handlers/functions/allowlist.go +++ b/core/services/gateway/handlers/functions/allowlist.go @@ -177,6 +177,10 @@ func (a *onchainAllowlist) updateFromContractV1(ctx context.Context, blockNum *b if err != nil { return errors.Wrap(err, "unexpected error during functions_router.GetAllowListId") } + a.lggr.Debugw("successfully fetched allowlist route ID", "id", tosID) + if tosID == [32]byte{} { + return errors.New("allowlist route ID has not been set") + } tosAddress, err := a.contractV1.GetContractById(&bind.CallOpts{ Pending: false, Context: ctx, @@ -184,6 +188,7 @@ func (a *onchainAllowlist) updateFromContractV1(ctx context.Context, blockNum *b if err != nil { return errors.Wrap(err, "unexpected error during functions_router.GetContractById") } + a.lggr.Debugw("successfully fetched allowlist contract address", "address", tosAddress) tosContract, err := functions_allow_list.NewTermsOfServiceAllowList(tosAddress, a.client) if err != nil { return errors.Wrap(err, "unexpected error during functions_allow_list.NewTermsOfServiceAllowList") diff --git a/core/services/gateway/handlers/functions/handler.functions.go b/core/services/gateway/handlers/functions/handler.functions.go index aee099e6cee..4ef6ab72fb2 100644 --- a/core/services/gateway/handlers/functions/handler.functions.go +++ b/core/services/gateway/handlers/functions/handler.functions.go @@ -57,6 +57,7 @@ func NewFunctionsHandlerFromConfig(handlerConfig json.RawMessage, donConfig *con if err != nil { return nil, err } + lggr = lggr.Named("FunctionsHandler:" + donConfig.DonId) var allowlist OnchainAllowlist if cfg.OnchainAllowlist != nil { chain, err2 := legacyChains.Get(cfg.OnchainAllowlistChainID) diff --git a/core/services/gateway/handlers/handler.dummy.go b/core/services/gateway/handlers/handler.dummy.go index 7615c734d8d..9cdd0865606 100644 --- a/core/services/gateway/handlers/handler.dummy.go +++ b/core/services/gateway/handlers/handler.dummy.go @@ -32,7 +32,7 @@ func NewDummyHandler(donConfig *config.DONConfig, don DON, lggr logger.Logger) ( donConfig: donConfig, don: don, savedCallbacks: make(map[string]*savedCallback), - lggr: lggr, + lggr: lggr.Named("DummyHandler." + donConfig.DonId), }, nil } diff --git a/core/services/gateway/integration_tests/gateway_integration_test.go b/core/services/gateway/integration_tests/gateway_integration_test.go index 7a0204a3156..310047950e6 100644 --- a/core/services/gateway/integration_tests/gateway_integration_test.go +++ b/core/services/gateway/integration_tests/gateway_integration_test.go @@ -6,6 +6,7 @@ import ( "crypto/ecdsa" "fmt" "net/http" + "strings" "sync/atomic" "testing" @@ -110,6 +111,8 @@ func TestIntegration_Gateway_NoFullNodes_BasicConnectionAndMessage(t *testing.T) t.Parallel() nodeKeys := common.NewTestNodes(t, 1)[0] + // Verify that addresses in config are case-insensitive + nodeKeys.Address = strings.ToUpper(nodeKeys.Address) // Launch Gateway lggr := logger.TestLogger(t) diff --git a/core/services/job/helpers_test.go b/core/services/job/helpers_test.go index 21f3a8daa99..167ed5297cc 100644 --- a/core/services/job/helpers_test.go +++ b/core/services/job/helpers_test.go @@ -35,6 +35,7 @@ const ( type = "offchainreporting" schemaVersion = 1 contractAddress = "%s" +evmChainID = "0" p2pBootstrapPeers = [ "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", ] @@ -112,6 +113,7 @@ ds1 -> ds1_parse -> ds1_multiply; transmitterAddress = "%s" keyBundleID = "%s" observationTimeout = "10s" + evmChainID = "0" observationSource = """ ds1 [type=http method=GET url="%s" allowunrestrictednetworkaccess="true" %s]; ds1_parse [type=jsonparse path="USD" lax=true]; @@ -122,6 +124,7 @@ ds1 -> ds1_parse; type = "offchainreporting" schemaVersion = 1 contractAddress = "%s" + evmChainID = "0" p2pBootstrapPeers = [] isBootstrapPeer = true ` @@ -129,6 +132,7 @@ ds1 -> ds1_parse; type = "offchainreporting" schemaVersion = 1 contractAddress = "%s" +evmChainID = "0" p2pPeerID = "%s" p2pBootstrapPeers = [ "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index 1f5dba452fe..fb34f92a060 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -15,6 +15,8 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/assets" @@ -603,6 +605,92 @@ func TestORM_CreateJob_OCRBootstrap(t *testing.T) { cltest.AssertCount(t, db, "jobs", 0) } +func TestORM_CreateJob_EVMChainID_Validation(t *testing.T) { + config := configtest.NewGeneralConfig(t, nil) + db := pgtest.NewSqlxDB(t) + keyStore := cltest.NewKeyStore(t, db, config.Database()) + + lggr := logger.TestLogger(t) + pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + bridgesORM := bridges.NewORM(db, lggr, config.Database()) + + relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) + jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) + + t.Run("evm chain id validation for ocr works", func(t *testing.T) { + jb := job.Job{ + Type: job.OffchainReporting, + OCROracleSpec: &job.OCROracleSpec{}, + } + assert.Equal(t, "CreateJobFailed: evm chain id must be defined", jobORM.CreateJob(&jb).Error()) + }) + + t.Run("evm chain id validation for direct request works", func(t *testing.T) { + jb := job.Job{ + Type: job.DirectRequest, + DirectRequestSpec: &job.DirectRequestSpec{}, + } + assert.Equal(t, "CreateJobFailed: evm chain id must be defined", jobORM.CreateJob(&jb).Error()) + }) + + t.Run("evm chain id validation for flux monitor works", func(t *testing.T) { + jb := job.Job{ + Type: job.FluxMonitor, + FluxMonitorSpec: &job.FluxMonitorSpec{}, + } + assert.Equal(t, "CreateJobFailed: evm chain id must be defined", jobORM.CreateJob(&jb).Error()) + }) + + t.Run("evm chain id validation for keepers works", func(t *testing.T) { + jb := job.Job{ + Type: job.Keeper, + KeeperSpec: &job.KeeperSpec{}, + } + assert.Equal(t, "CreateJobFailed: evm chain id must be defined", jobORM.CreateJob(&jb).Error()) + }) + + t.Run("evm chain id validation for vrf works", func(t *testing.T) { + jb := job.Job{ + Type: job.VRF, + VRFSpec: &job.VRFSpec{}, + } + assert.Equal(t, "CreateJobFailed: evm chain id must be defined", jobORM.CreateJob(&jb).Error()) + }) + + t.Run("evm chain id validation for block hash store works", func(t *testing.T) { + jb := job.Job{ + Type: job.BlockhashStore, + BlockhashStoreSpec: &job.BlockhashStoreSpec{}, + } + assert.Equal(t, "CreateJobFailed: evm chain id must be defined", jobORM.CreateJob(&jb).Error()) + }) + + t.Run("evm chain id validation for block header feeder works", func(t *testing.T) { + jb := job.Job{ + Type: job.BlockHeaderFeeder, + BlockHeaderFeederSpec: &job.BlockHeaderFeederSpec{}, + } + assert.Equal(t, "CreateJobFailed: evm chain id must be defined", jobORM.CreateJob(&jb).Error()) + }) + + t.Run("evm chain id validation for legacy gas station server spec works", func(t *testing.T) { + jb := job.Job{ + Type: job.LegacyGasStationServer, + LegacyGasStationServerSpec: &job.LegacyGasStationServerSpec{}, + } + assert.Equal(t, "CreateJobFailed: evm chain id must be defined", jobORM.CreateJob(&jb).Error()) + }) + + t.Run("evm chain id validation for legacy gas station sidecar spec works", func(t *testing.T) { + jb := job.Job{ + Type: job.LegacyGasStationSidecar, + LegacyGasStationSidecarSpec: &job.LegacyGasStationSidecarSpec{}, + } + assert.Equal(t, "CreateJobFailed: evm chain id must be defined", jobORM.CreateJob(&jb).Error()) + }) +} + func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { customChainID := utils.NewBig(testutils.NewRandomEVMChainID()) @@ -627,16 +715,15 @@ func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) - defaultChainID := config.DefaultChainID() - + // defaultChainID is deprecated + defaultChainID := customChainID _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) _, bridge := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) _, bridge2 := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) - // EVMChainID will default to 0, but we want to override that - // with nil later to represent a job spec with no chain id spec := testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ Name: "job1", + EVMChainID: testutils.FixtureChainID.String(), DS1BridgeName: bridge.Name.String(), DS2BridgeName: bridge2.Name.String(), TransmitterAddress: address.Hex(), @@ -645,40 +732,30 @@ func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { jb, err := ocr.ValidatedOracleSpecToml(legacyChains, spec.Toml()) require.NoError(t, err) - // 2nd job with no Chain ID - spec2 := testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ - Name: "job2", - DS1BridgeName: bridge.Name.String(), - DS2BridgeName: bridge2.Name.String(), - TransmitterAddress: address.Hex(), - }) - jb2, err := ocr.ValidatedOracleSpecToml(legacyChains, spec2.Toml()) - require.NoError(t, err) - // Default Chain Job externalJobID := uuid.NullUUID{UUID: uuid.New(), Valid: true} - spec3 := testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ - Name: "job3", + spec2 := testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ + Name: "job2", EVMChainID: defaultChainID.String(), DS1BridgeName: bridge.Name.String(), DS2BridgeName: bridge2.Name.String(), TransmitterAddress: address.Hex(), JobID: externalJobID.UUID.String(), }) - jb3, err := ocr.ValidatedOracleSpecToml(legacyChains, spec3.Toml()) + jb2, err := ocr.ValidatedOracleSpecToml(legacyChains, spec2.Toml()) require.NoError(t, err) // Custom Chain Job externalJobID = uuid.NullUUID{UUID: uuid.New(), Valid: true} - spec4 := testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ - Name: "job4", + spec3 := testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ + Name: "job3", EVMChainID: customChainID.String(), DS1BridgeName: bridge.Name.String(), DS2BridgeName: bridge2.Name.String(), TransmitterAddress: address.Hex(), JobID: externalJobID.UUID.String(), }) - jb4, err := ocr.ValidatedOracleSpecToml(legacyChains, spec4.Toml()) + jb3, err := ocr.ValidatedOracleSpecToml(legacyChains, spec3.Toml()) require.NoError(t, err) t.Run("with legacy NULL chain id", func(t *testing.T) { @@ -691,33 +768,24 @@ func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { cltest.AssertCount(t, db, "ocr_oracle_specs", 1) cltest.AssertCount(t, db, "jobs", 1) - jb2.OCROracleSpec.EVMChainID = nil - err = jobORM.CreateJob(&jb2) // try adding job for same contract with no chain id in spec + err = jobORM.CreateJob(&jb2) // try adding job for same contract with default chain id require.Error(t, err) - assert.Equal(t, fmt.Sprintf("CreateJobFailed: a job with contract address %s already exists for chain ID %s", jb2.OCROracleSpec.ContractAddress, defaultChainID.String()), err.Error()) + assert.Equal(t, fmt.Sprintf("CreateJobFailed: a job with contract address %s already exists for chain ID %d", jb2.OCROracleSpec.ContractAddress, jb2.OCROracleSpec.EVMChainID.ToInt()), err.Error()) - err = jobORM.CreateJob(&jb3) // try adding job for same contract with default chain id + err = jobORM.CreateJob(&jb3) // Try adding job with custom chain id require.Error(t, err) assert.Equal(t, fmt.Sprintf("CreateJobFailed: a job with contract address %s already exists for chain ID %d", jb3.OCROracleSpec.ContractAddress, jb3.OCROracleSpec.EVMChainID.ToInt()), err.Error()) - - err = jobORM.CreateJob(&jb4) // Try adding job with custom chain id - require.Error(t, err) - assert.Equal(t, fmt.Sprintf("CreateJobFailed: a job with contract address %s already exists for chain ID %d", jb4.OCROracleSpec.ContractAddress, jb4.OCROracleSpec.EVMChainID.ToInt()), err.Error()) }) require.NoError(t, jobORM.DeleteJob(jb.ID)) t.Run("with a set chain id", func(t *testing.T) { - err = jobORM.CreateJob(&jb4) // Add job with custom chain id + err = jobORM.CreateJob(&jb3) // Add job with custom chain id require.NoError(t, err) cltest.AssertCount(t, db, "ocr_oracle_specs", 1) cltest.AssertCount(t, db, "jobs", 1) - jb.OCROracleSpec.EVMChainID = nil - err = jobORM.CreateJob(&jb) - require.NoError(t, err) // should be able to add same contract address on default chain by omitting chain id - externalJobID = uuid.NullUUID{UUID: uuid.New(), Valid: true} spec3.JobID = externalJobID.UUID.String() jb3a, err := ocr.ValidatedOracleSpecToml(legacyChains, spec3.Toml()) @@ -727,11 +795,11 @@ func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { assert.Equal(t, fmt.Sprintf("CreateJobFailed: a job with contract address %s already exists for chain ID %s", jb3.OCROracleSpec.ContractAddress, defaultChainID.String()), err.Error()) externalJobID = uuid.NullUUID{UUID: uuid.New(), Valid: true} - spec4.JobID = externalJobID.UUID.String() - jb5, err := ocr.ValidatedOracleSpecToml(legacyChains, spec4.Toml()) + spec3.JobID = externalJobID.UUID.String() + jb4, err := ocr.ValidatedOracleSpecToml(legacyChains, spec3.Toml()) require.NoError(t, err) - err = jobORM.CreateJob(&jb5) // Try to add duplicate job with custom id + err = jobORM.CreateJob(&jb4) // Try to add duplicate job with custom id require.Error(t, err) assert.Equal(t, fmt.Sprintf("CreateJobFailed: a job with contract address %s already exists for chain ID %s", jb4.OCROracleSpec.ContractAddress, customChainID), err.Error()) }) @@ -911,7 +979,7 @@ func TestORM_ValidateKeyStoreMatch(t *testing.T) { }) t.Run("test Mercury ETH key validation", func(t *testing.T) { - jb.OCR2OracleSpec.PluginType = job.Mercury + jb.OCR2OracleSpec.PluginType = types.Mercury err = job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, "bad key") require.EqualError(t, err, "no CSA key matching: \"bad key\"") diff --git a/core/services/job/models.go b/core/services/job/models.go index d70afde12c2..03015aa1a7b 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -14,8 +14,10 @@ import ( "github.com/pkg/errors" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" @@ -310,28 +312,7 @@ func (r JSONConfig) MercuryCredentialName() (string, error) { return name, nil } -var ForwardersSupportedPlugins = []OCR2PluginType{Median, DKG, OCR2VRF, OCR2Keeper, OCR2Functions} - -// OCR2PluginType defines supported OCR2 plugin types. -type OCR2PluginType string - -const ( - // Median refers to the median.Median type - Median OCR2PluginType = "median" - - DKG OCR2PluginType = "dkg" - - OCR2VRF OCR2PluginType = "ocr2vrf" - - // Keeper was rebranded to automation. For now the plugin type required in job spec points - // to the new name (automation) but in code we refer it to keepers - // TODO: sc-55296 to rename ocr2keeper to ocr2automation in code - OCR2Keeper OCR2PluginType = "ocr2automation" - - OCR2Functions OCR2PluginType = "functions" - - Mercury OCR2PluginType = "mercury" -) +var ForwardersSupportedPlugins = []types.OCR2PluginType{types.Median, types.DKG, types.OCR2VRF, types.OCR2Keeper, types.Functions} // OCR2OracleSpec defines the job spec for OCR2 jobs. // Relay config is chain specific config for a relay (chain adapter). @@ -341,21 +322,32 @@ type OCR2OracleSpec struct { FeedID *common.Hash `toml:"feedID"` Relay relay.Network `toml:"relay"` // TODO BCF-2442 implement ChainID as top level parameter rathe than buried in RelayConfig. - ChainID string `toml:"chainID"` - RelayConfig JSONConfig `toml:"relayConfig"` - P2PV2Bootstrappers pq.StringArray `toml:"p2pv2Bootstrappers"` - OCRKeyBundleID null.String `toml:"ocrKeyBundleID"` - MonitoringEndpoint null.String `toml:"monitoringEndpoint"` - TransmitterID null.String `toml:"transmitterID"` - BlockchainTimeout models.Interval `toml:"blockchainTimeout"` - ContractConfigTrackerPollInterval models.Interval `toml:"contractConfigTrackerPollInterval"` - ContractConfigConfirmations uint16 `toml:"contractConfigConfirmations"` - PluginConfig JSONConfig `toml:"pluginConfig"` - PluginType OCR2PluginType `toml:"pluginType"` - CreatedAt time.Time `toml:"-"` - UpdatedAt time.Time `toml:"-"` - CaptureEATelemetry bool `toml:"captureEATelemetry"` - CaptureAutomationCustomTelemetry bool `toml:"captureAutomationCustomTelemetry"` + ChainID string `toml:"chainID"` + RelayConfig JSONConfig `toml:"relayConfig"` + P2PV2Bootstrappers pq.StringArray `toml:"p2pv2Bootstrappers"` + OCRKeyBundleID null.String `toml:"ocrKeyBundleID"` + MonitoringEndpoint null.String `toml:"monitoringEndpoint"` + TransmitterID null.String `toml:"transmitterID"` + BlockchainTimeout models.Interval `toml:"blockchainTimeout"` + ContractConfigTrackerPollInterval models.Interval `toml:"contractConfigTrackerPollInterval"` + ContractConfigConfirmations uint16 `toml:"contractConfigConfirmations"` + PluginConfig JSONConfig `toml:"pluginConfig"` + PluginType types.OCR2PluginType `toml:"pluginType"` + CreatedAt time.Time `toml:"-"` + UpdatedAt time.Time `toml:"-"` + CaptureEATelemetry bool `toml:"captureEATelemetry"` + CaptureAutomationCustomTelemetry bool `toml:"captureAutomationCustomTelemetry"` +} + +func validateRelayID(id relay.ID) error { + // only the EVM has specific requirements + if id.Network == relay.EVM { + _, err := toml.ChainIDInt64(id.ChainID) + if err != nil { + return fmt.Errorf("invalid EVM chain id %s: %w", id.ChainID, err) + } + } + return nil } func (s *OCR2OracleSpec) RelayID() (relay.ID, error) { @@ -363,7 +355,12 @@ func (s *OCR2OracleSpec) RelayID() (relay.ID, error) { if err != nil { return relay.ID{}, err } - return relay.NewID(s.Relay, cid) + rid := relay.NewID(s.Relay, cid) + err = validateRelayID(rid) + if err != nil { + return relay.ID{}, err + } + return rid, nil } func (s *OCR2OracleSpec) getChainID() (relay.ChainID, error) { diff --git a/core/services/job/orm.go b/core/services/job/orm.go index 277b03b24dd..190df2f4966 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -19,6 +19,8 @@ import ( "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" @@ -165,6 +167,9 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { switch jb.Type { case DirectRequest: + if jb.DirectRequestSpec.EVMChainID == nil { + return errors.New("evm chain id must be defined") + } var specID int32 sql := `INSERT INTO direct_request_specs (contract_address, min_incoming_confirmations, requesters, min_contract_payment, evm_chain_id, created_at, updated_at) VALUES (:contract_address, :min_incoming_confirmations, :requesters, :min_contract_payment, :evm_chain_id, now(), now()) @@ -174,6 +179,9 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { } jb.DirectRequestSpecID = &specID case FluxMonitor: + if jb.FluxMonitorSpec.EVMChainID == nil { + return errors.New("evm chain id must be defined") + } var specID int32 sql := `INSERT INTO flux_monitor_specs (contract_address, threshold, absolute_threshold, poll_timer_period, poll_timer_disabled, idle_timer_period, idle_timer_disabled, drumbeat_schedule, drumbeat_random_delay, drumbeat_enabled, min_payment, evm_chain_id, created_at, updated_at) @@ -185,6 +193,10 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { } jb.FluxMonitorSpecID = &specID case OffchainReporting: + if jb.OCROracleSpec.EVMChainID == nil { + return errors.New("evm chain id must be defined") + } + var specID int32 if jb.OCROracleSpec.EncryptedOCRKeyBundleID != nil { _, err := o.keyStore.OCR().Get(jb.OCROracleSpec.EncryptedOCRKeyBundleID.String()) @@ -199,16 +211,7 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { } } - if jb.OCROracleSpec.EVMChainID == nil { - // If unspecified, assume we're creating a job intended to run on default chain id - newChain, err := o.legacyChains.Default() - if err != nil { - return err - } - jb.OCROracleSpec.EVMChainID = utils.NewBig(newChain.ID()) - } newChainID := jb.OCROracleSpec.EVMChainID - existingSpec := new(OCROracleSpec) err := tx.Get(existingSpec, `SELECT * FROM ocr_oracle_specs WHERE contract_address = $1 and (evm_chain_id = $2 or evm_chain_id IS NULL) LIMIT 1;`, jb.OCROracleSpec.ContractAddress, newChainID, @@ -268,7 +271,7 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { return errors.Errorf("forwarding is not currently supported for %s jobs", jb.OCR2OracleSpec.PluginType) } - if jb.OCR2OracleSpec.PluginType == Mercury { + if jb.OCR2OracleSpec.PluginType == types.Mercury { if jb.OCR2OracleSpec.FeedID == nil { return errors.New("feed ID is required for mercury plugin type") } @@ -278,7 +281,7 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { } } - if jb.OCR2OracleSpec.PluginType == Median { + if jb.OCR2OracleSpec.PluginType == types.Median { var cfg medianconfig.PluginConfig err = json.Unmarshal(jb.OCR2OracleSpec.PluginConfig.Bytes(), &cfg) if err != nil { @@ -306,6 +309,9 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { } jb.OCR2OracleSpecID = &specID case Keeper: + if jb.KeeperSpec.EVMChainID == nil { + return errors.New("evm chain id must be defined") + } var specID int32 sql := `INSERT INTO keeper_specs (contract_address, from_address, evm_chain_id, created_at, updated_at) VALUES (:contract_address, :from_address, :evm_chain_id, NOW(), NOW()) @@ -324,6 +330,9 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { } jb.CronSpecID = &specID case VRF: + if jb.VRFSpec.EVMChainID == nil { + return errors.New("evm chain id must be defined") + } var specID int32 sql := `INSERT INTO vrf_specs ( coordinator_address, public_key, min_incoming_confirmations, @@ -375,6 +384,9 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { } } case BlockhashStore: + if jb.BlockhashStoreSpec.EVMChainID == nil { + return errors.New("evm chain id must be defined") + } var specID int32 sql := `INSERT INTO blockhash_store_specs (coordinator_v1_address, coordinator_v2_address, coordinator_v2_plus_address, trusted_blockhash_store_address, trusted_blockhash_store_batch_size, wait_blocks, lookback_blocks, blockhash_store_address, poll_period, run_timeout, evm_chain_id, from_addresses, created_at, updated_at) VALUES (:coordinator_v1_address, :coordinator_v2_address, :coordinator_v2_plus_address, :trusted_blockhash_store_address, :trusted_blockhash_store_batch_size, :wait_blocks, :lookback_blocks, :blockhash_store_address, :poll_period, :run_timeout, :evm_chain_id, :from_addresses, NOW(), NOW()) @@ -384,6 +396,9 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { } jb.BlockhashStoreSpecID = &specID case BlockHeaderFeeder: + if jb.BlockHeaderFeederSpec.EVMChainID == nil { + return errors.New("evm chain id must be defined") + } var specID int32 sql := `INSERT INTO block_header_feeder_specs (coordinator_v1_address, coordinator_v2_address, coordinator_v2_plus_address, wait_blocks, lookback_blocks, blockhash_store_address, batch_blockhash_store_address, poll_period, run_timeout, evm_chain_id, from_addresses, get_blockhashes_batch_size, store_blockhashes_batch_size, created_at, updated_at) VALUES (:coordinator_v1_address, :coordinator_v2_address, :coordinator_v2_plus_address, :wait_blocks, :lookback_blocks, :blockhash_store_address, :batch_blockhash_store_address, :poll_period, :run_timeout, :evm_chain_id, :from_addresses, :get_blockhashes_batch_size, :store_blockhashes_batch_size, NOW(), NOW()) @@ -393,6 +408,9 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { } jb.BlockHeaderFeederSpecID = &specID case LegacyGasStationServer: + if jb.LegacyGasStationServerSpec.EVMChainID == nil { + return errors.New("evm chain id must be defined") + } var specID int32 sql := `INSERT INTO legacy_gas_station_server_specs (forwarder_address, evm_chain_id, ccip_chain_selector, from_addresses, created_at, updated_at) VALUES (:forwarder_address, :evm_chain_id, :ccip_chain_selector, :from_addresses, NOW(), NOW()) @@ -402,6 +420,9 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { } jb.LegacyGasStationServerSpecID = &specID case LegacyGasStationSidecar: + if jb.LegacyGasStationSidecarSpec.EVMChainID == nil { + return errors.New("evm chain id must be defined") + } var specID int32 sql := `INSERT INTO legacy_gas_station_sidecar_specs (forwarder_address, off_ramp_address, lookback_blocks, poll_period, run_timeout, evm_chain_id, ccip_chain_selector, created_at, updated_at) VALUES (:forwarder_address, :off_ramp_address, :lookback_blocks, :poll_period, :run_timeout, :evm_chain_id, :ccip_chain_selector, NOW(), NOW()) @@ -456,7 +477,7 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { // ValidateKeyStoreMatch confirms that the key has a valid match in the keystore func ValidateKeyStoreMatch(spec *OCR2OracleSpec, keyStore keystore.Master, key string) error { - if spec.PluginType == Mercury { + if spec.PluginType == types.Mercury { _, err := keyStore.CSA().Get(key) if err != nil { return errors.Errorf("no CSA key matching: %q", key) diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index 72a20a476e3..da670f99a79 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -169,6 +169,7 @@ func TestRunner(t *testing.T) { jb := makeOCRJobSpecFromToml(t, fmt.Sprintf(` type = "offchainreporting" schemaVersion = 1 + evmChainID = "0" observationSource = """ ds1 [type=bridge name="%s"]; """ @@ -434,6 +435,7 @@ answer1 [type=median index=0]; schemaVersion = 1 contractAddress = "%s" isBootstrapPeer = false + evmChainID = "0" observationSource = """ ds1 [type=http method=GET url="%s" allowunrestrictednetworkaccess="true" %s]; ds1_parse [type=jsonparse path="USD" lax=true]; @@ -471,6 +473,7 @@ ds1 -> ds1_parse; schemaVersion = 1 contractAddress = "%s" isBootstrapPeer = true + evmChainID = "0" ` s = fmt.Sprintf(s, cltest.NewEIP55Address()) jb, err := ocr.ValidatedOracleSpecToml(legacyChains, s) @@ -509,6 +512,7 @@ ds1 -> ds1_parse; contractAddress = "%s" isBootstrapPeer = false observationTimeout = "15s" + evmChainID = "0" observationSource = """ ds1 [type=http method=GET url="%s" allowunrestrictednetworkaccess="true" %s]; ds1_parse [type=jsonparse path="USD" lax=true]; diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index f35aa50ba4d..efa252e4c4d 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -67,7 +67,7 @@ type relayGetter struct { } func (g *relayGetter) Get(id relay.ID) (loop.Relayer, error) { - return evmrelayer.NewLoopRelayAdapter(g.r, g.e), nil + return evmrelayer.NewLoopRelayServerAdapter(g.r, g.e), nil } func TestSpawner_CreateJobDeleteJob(t *testing.T) { diff --git a/core/services/keeper/integration_test.go b/core/services/keeper/integration_test.go index cf36628f6a1..39431063bcd 100644 --- a/core/services/keeper/integration_test.go +++ b/core/services/keeper/integration_test.go @@ -405,6 +405,7 @@ func TestKeeperForwarderEthIntegration(t *testing.T) { c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) // disable reorg protection for this test c.EVM[0].HeadTracker.MaxBufferSize = ptr[uint32](100) // helps prevent missed heads c.EVM[0].Transactions.ForwardersEnabled = ptr(true) // Enable Operator Forwarder flow + c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) }) scopedConfig := evmtest.NewChainScopedConfig(t, config) korm := keeper.NewORM(db, logger.TestLogger(t), scopedConfig.Database()) @@ -430,6 +431,7 @@ func TestKeeperForwarderEthIntegration(t *testing.T) { KeeperSpec: &job.KeeperSpec{ FromAddress: nodeAddressEIP55, ContractAddress: regAddrEIP55, + EVMChainID: (*utils.Big)(testutils.SimulatedChainID), }, SchemaVersion: 1, ForwardingAllowed: true, diff --git a/core/services/keeper/upkeep_executer_test.go b/core/services/keeper/upkeep_executer_test.go index c971152df3a..702633e1d08 100644 --- a/core/services/keeper/upkeep_executer_test.go +++ b/core/services/keeper/upkeep_executer_test.go @@ -72,7 +72,9 @@ func setup(t *testing.T, estimator gas.EvmFeeEstimator, overrideFn func(c *chain }) db := pgtest.NewSqlxDB(t) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := evmtest.NewEthClientMock(t) + ethClient.On("ConfiguredChainID").Return(cfg.EVMConfigs()[0].ChainID.ToInt()).Maybe() + ethClient.On("IsL2").Return(false).Maybe() ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Maybe().Return(&evmtypes.Head{Number: 1, Hash: utils.NewHash()}, nil) txm := txmmocks.NewMockEvmTxManager(t) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{TxManager: txm, DB: db, Client: ethClient, KeyStore: keyStore.Eth(), GeneralConfig: cfg, GasEstimator: estimator}) @@ -81,6 +83,7 @@ func setup(t *testing.T, estimator gas.EvmFeeEstimator, overrideFn func(c *chain ch := evmtest.MustGetDefaultChain(t, legacyChains) orm := keeper.NewORM(db, logger.TestLogger(t), ch.Config().Database()) registry, job := cltest.MustInsertKeeperRegistry(t, db, orm, keyStore.Eth(), 0, 1, 20) + lggr := logger.TestLogger(t) executer := keeper.NewUpkeepExecuter(job, orm, jpv2.Pr, ethClient, ch.HeadBroadcaster(), ch.GasEstimator(), lggr, ch.Config().Keeper(), job.KeeperSpec.FromAddress.Address()) upkeep := cltest.MustInsertUpkeepForRegistry(t, db, ch.Config().Database(), registry) @@ -122,7 +125,10 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { t.Parallel() t.Run("runs upkeep on triggering block number", func(t *testing.T) { - db, config, ethMock, executer, registry, upkeep, job, jpv2, txm, _, _, _ := setup(t, mockEstimator(t), nil) + db, config, ethMock, executer, registry, upkeep, job, jpv2, txm, _, _, _ := setup(t, mockEstimator(t), + func(c *chainlink.Config, s *chainlink.Secrets) { + c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + }) gasLimit := 5_000_000 + config.Keeper().Registry().PerformGasOverhead() @@ -165,6 +171,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { runTest := func(t *testing.T, eip1559 bool) { db, config, ethMock, executer, registry, upkeep, job, jpv2, txm, _, _, _ := setup(t, mockEstimator(t), func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = &eip1559 + c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) }) gasLimit := 5_000_000 + config.Keeper().Registry().PerformGasOverhead() @@ -215,10 +222,12 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { }) t.Run("errors if submission key not found", func(t *testing.T) { - _, _, ethMock, executer, registry, _, job, jpv2, _, keyStore, _, _ := setup(t, mockEstimator(t), nil) + _, _, ethMock, executer, registry, _, job, jpv2, _, keyStore, _, _ := setup(t, mockEstimator(t), func(c *chainlink.Config, s *chainlink.Secrets) { + c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + }) // replace expected key with random one - _, err := keyStore.Eth().Create(&cltest.FixtureChainID) + _, err := keyStore.Eth().Create(testutils.SimulatedChainID) require.NoError(t, err) _, err = keyStore.Eth().Delete(job.KeeperSpec.FromAddress.Hex()) require.NoError(t, err) @@ -265,7 +274,9 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { }) t.Run("triggers if heads are skipped but later heads arrive within range", func(t *testing.T) { - db, config, ethMock, executer, registry, upkeep, job, jpv2, txm, _, _, _ := setup(t, mockEstimator(t), nil) + db, config, ethMock, executer, registry, upkeep, job, jpv2, txm, _, _, _ := setup(t, mockEstimator(t), func(c *chainlink.Config, s *chainlink.Secrets) { + c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + }) etxs := []cltest.Awaiter{ cltest.NewAwaiter(), @@ -304,7 +315,10 @@ func Test_UpkeepExecuter_PerformsUpkeep_Error(t *testing.T) { g := gomega.NewWithT(t) - db, _, ethMock, executer, registry, _, _, _, _, _, _, _ := setup(t, mockEstimator(t), nil) + db, _, ethMock, executer, registry, _, _, _, _, _, _, _ := setup(t, mockEstimator(t), + func(c *chainlink.Config, s *chainlink.Secrets) { + c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + }) var wasCalled atomic.Bool registryMock := cltest.NewContractMockReceiver(t, ethMock, keeper.Registry1_1ABI, registry.ContractAddress.Address()) @@ -316,7 +330,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Error(t *testing.T) { executer.OnNewLongestChain(testutils.Context(t), &head) g.Eventually(wasCalled.Load).Should(gomega.Equal(true)) - cltest.AssertCountStays(t, db, "eth_txes", 0) + cltest.AssertCountStays(t, db, "evm.txes", 0) } func ptr[T any](t T) *T { return &t } diff --git a/core/services/keystore/eth.go b/core/services/keystore/eth.go index ca776cf10e1..9909f398bf4 100644 --- a/core/services/keystore/eth.go +++ b/core/services/keystore/eth.go @@ -240,7 +240,7 @@ func (ks *eth) Add(address common.Address, chainID *big.Int, qopts ...pg.QOpt) e // caller must hold lock! func (ks *eth) addKey(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { state := new(ethkey.State) - sql := `INSERT INTO evm_key_states (address, next_nonce, disabled, evm_chain_id, created_at, updated_at) + sql := `INSERT INTO evm.key_states (address, next_nonce, disabled, evm_chain_id, created_at, updated_at) VALUES ($1, 0, false, $2, NOW(), NOW()) RETURNING *;` q := ks.orm.q.WithOpts(qopts...) @@ -267,7 +267,7 @@ func (ks *eth) Enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt func (ks *eth) enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { state := new(ethkey.State) q := ks.orm.q.WithOpts(qopts...) - sql := `UPDATE evm_key_states SET disabled = false, updated_at = NOW() WHERE address = $1 AND evm_chain_id = $2 + sql := `UPDATE evm.key_states SET disabled = false, updated_at = NOW() WHERE address = $1 AND evm_chain_id = $2 RETURNING *;` if err := q.Get(state, sql, address, chainID.String()); err != nil { return errors.Wrap(err, "failed to enable state") @@ -291,7 +291,7 @@ func (ks *eth) Disable(address common.Address, chainID *big.Int, qopts ...pg.QOp func (ks *eth) disable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { state := new(ethkey.State) q := ks.orm.q.WithOpts(qopts...) - sql := `UPDATE evm_key_states SET disabled = false, updated_at = NOW() WHERE address = $1 AND evm_chain_id = $2 + sql := `UPDATE evm.key_states SET disabled = false, updated_at = NOW() WHERE address = $1 AND evm_chain_id = $2 RETURNING id, next_nonce, address, evm_chain_id, disabled, created_at, updated_at;` if err := q.Get(state, sql, address, chainID.String()); err != nil { return errors.Wrap(err, "failed to enable state") @@ -305,7 +305,7 @@ func (ks *eth) disable(address common.Address, chainID *big.Int, qopts ...pg.QOp // Reset the key/chain nonce to the given one func (ks *eth) Reset(address common.Address, chainID *big.Int, nonce int64, qopts ...pg.QOpt) error { q := ks.orm.q.WithOpts(qopts...) - res, err := q.Exec(`UPDATE evm_key_states SET next_nonce = $1 WHERE address = $2 AND evm_chain_id = $3`, nonce, address, chainID.String()) + res, err := q.Exec(`UPDATE evm.key_states SET next_nonce = $1 WHERE address = $2 AND evm_chain_id = $3`, nonce, address, chainID.String()) if err != nil { return errors.Wrap(err, "failed to reset state") } @@ -337,7 +337,7 @@ func (ks *eth) Delete(id string) (ethkey.KeyV2, error) { return ethkey.KeyV2{}, err } err = ks.safeRemoveKey(key, func(tx pg.Queryer) error { - _, err2 := tx.Exec(`DELETE FROM evm_key_states WHERE address = $1`, key.Address) + _, err2 := tx.Exec(`DELETE FROM evm.key_states WHERE address = $1`, key.Address) return err2 }) if err != nil { @@ -587,7 +587,7 @@ func (ks *eth) XXXTestingOnlySetState(state ethkey.State) { panic(fmt.Sprintf("key not found with ID %s", state.KeyID())) } *existingState = state - sql := `UPDATE evm_key_states SET address = :address, next_nonce = :next_nonce, is_disabled = :is_disabled, evm_chain_id = :evm_chain_id, updated_at = NOW() + sql := `UPDATE evm.key_states SET address = :address, next_nonce = :next_nonce, is_disabled = :is_disabled, evm_chain_id = :evm_chain_id, updated_at = NOW() WHERE address = :address;` _, err := ks.orm.q.NamedExec(sql, state) if err != nil { @@ -669,7 +669,7 @@ func (ks *eth) addWithNonce(key ethkey.KeyV2, chainID *big.Int, nonce int64, isD defer ks.lock.Unlock() err = ks.safeAddKey(key, func(tx pg.Queryer) (merr error) { state := new(ethkey.State) - sql := `INSERT INTO evm_key_states (address, next_nonce, disabled, evm_chain_id, created_at, updated_at) + sql := `INSERT INTO evm.key_states (address, next_nonce, disabled, evm_chain_id, created_at, updated_at) VALUES ($1, $2, $3, $4, NOW(), NOW()) RETURNING *;` if err = ks.orm.q.Get(state, sql, key.Address, nonce, isDisabled, chainID); err != nil { return errors.Wrap(err, "failed to insert evm_key_state") diff --git a/core/services/keystore/eth_test.go b/core/services/keystore/eth_test.go index 678f11ea503..78131bec133 100644 --- a/core/services/keystore/eth_test.go +++ b/core/services/keystore/eth_test.go @@ -38,10 +38,10 @@ func Test_EthKeyStore(t *testing.T) { reset := func() { keyStore.ResetXXXTestOnly() require.NoError(t, utils.JustError(db.Exec("DELETE FROM encrypted_key_rings"))) - require.NoError(t, utils.JustError(db.Exec("DELETE FROM evm_key_states"))) + require.NoError(t, utils.JustError(db.Exec("DELETE FROM evm.key_states"))) require.NoError(t, keyStore.Unlock(cltest.Password)) } - const statesTableName = "evm_key_states" + const statesTableName = "evm.key_states" t.Run("Create / GetAll / Get", func(t *testing.T) { defer reset() @@ -104,7 +104,7 @@ func Test_EthKeyStore(t *testing.T) { cltest.AssertCount(t, db, statesTableName, 0) }) - t.Run("Delete removes key even if eth_txes are present", func(t *testing.T) { + t.Run("Delete removes key even if evm.txes are present", func(t *testing.T) { defer reset() key, err := ethKeyStore.Create(&cltest.FixtureChainID) require.NoError(t, err) @@ -170,7 +170,7 @@ func Test_EthKeyStore(t *testing.T) { require.NoError(t, err) key2, err := ethKeyStore.Create(big.NewInt(1337)) require.NoError(t, err) - testutils.AssertCount(t, db, "evm_key_states", 2) + testutils.AssertCount(t, db, "evm.key_states", 2) keys, err := ethKeyStore.GetAll() require.NoError(t, err) assert.Len(t, keys, 2) @@ -363,7 +363,7 @@ func Test_EthKeyStore_E2E(t *testing.T) { reset := func() { keyStore.ResetXXXTestOnly() require.NoError(t, utils.JustError(db.Exec("DELETE FROM encrypted_key_rings"))) - require.NoError(t, utils.JustError(db.Exec("DELETE FROM evm_key_states"))) + require.NoError(t, utils.JustError(db.Exec("DELETE FROM evm.key_states"))) require.NoError(t, keyStore.Unlock(cltest.Password)) } @@ -552,10 +552,10 @@ func Test_EthKeyStore_EnsureKeys(t *testing.T) { keyStore := cltest.NewKeyStore(t, db, cfg.Database()) ks := keyStore.Eth() - testutils.AssertCount(t, db, "evm_key_states", 0) + testutils.AssertCount(t, db, "evm.key_states", 0) err := ks.EnsureKeys(testutils.FixtureChainID, testutils.SimulatedChainID) require.NoError(t, err) - testutils.AssertCount(t, db, "evm_key_states", 2) + testutils.AssertCount(t, db, "evm.key_states", 2) keys, err := ks.GetAll() require.NoError(t, err) assert.Len(t, keys, 2) @@ -570,7 +570,7 @@ func Test_EthKeyStore_EnsureKeys(t *testing.T) { // Add one enabled key _, err := ks.Create(testutils.FixtureChainID) require.NoError(t, err) - testutils.AssertCount(t, db, "evm_key_states", 1) + testutils.AssertCount(t, db, "evm.key_states", 1) keys, err := ks.GetAll() require.NoError(t, err) assert.Len(t, keys, 1) @@ -578,7 +578,7 @@ func Test_EthKeyStore_EnsureKeys(t *testing.T) { // this adds one more key for the additional chain err = ks.EnsureKeys(testutils.FixtureChainID, testutils.SimulatedChainID) require.NoError(t, err) - testutils.AssertCount(t, db, "evm_key_states", 2) + testutils.AssertCount(t, db, "evm.key_states", 2) keys, err = ks.GetAll() require.NoError(t, err) assert.Len(t, keys, 2) @@ -593,7 +593,7 @@ func Test_EthKeyStore_EnsureKeys(t *testing.T) { // Add one enabled key k, err := ks.Create(testutils.FixtureChainID) require.NoError(t, err) - testutils.AssertCount(t, db, "evm_key_states", 1) + testutils.AssertCount(t, db, "evm.key_states", 1) keys, err := ks.GetAll() require.NoError(t, err) assert.Len(t, keys, 1) @@ -605,7 +605,7 @@ func Test_EthKeyStore_EnsureKeys(t *testing.T) { // this does nothing err = ks.EnsureKeys(testutils.FixtureChainID) require.NoError(t, err) - testutils.AssertCount(t, db, "evm_key_states", 1) + testutils.AssertCount(t, db, "evm.key_states", 1) keys, err = ks.GetAll() require.NoError(t, err) assert.Len(t, keys, 1) @@ -728,7 +728,7 @@ func Test_IncrementNextSequence(t *testing.T) { err = ks.IncrementNextSequence(evmAddr1, testutils.FixtureChainID, evmtypes.Nonce(randNonce)) require.NoError(t, err) var nonce int64 - require.NoError(t, db.Get(&nonce, `SELECT next_nonce FROM evm_key_states WHERE address = $1 AND evm_chain_id = $2`, addr1, testutils.FixtureChainID.String())) + require.NoError(t, db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 AND evm_chain_id = $2`, addr1, testutils.FixtureChainID.String())) assert.Equal(t, randNonce+1, nonce) err = ks.IncrementNextSequence(evmAddr1, testutils.SimulatedChainID, evmtypes.Nonce(randNonce+1)) @@ -745,7 +745,7 @@ func Test_IncrementNextSequence(t *testing.T) { assert.Contains(t, err.Error(), fmt.Sprintf("key with address %s does not exist", randAddr2.Hex())) // verify it didnt get changed by any erroring calls - require.NoError(t, db.Get(&nonce, `SELECT next_nonce FROM evm_key_states WHERE address = $1 AND evm_chain_id = $2`, addr1, testutils.FixtureChainID.String())) + require.NoError(t, db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 AND evm_chain_id = $2`, addr1, testutils.FixtureChainID.String())) assert.Equal(t, randNonce+1, nonce) } @@ -768,7 +768,7 @@ func Test_EthKeyStore_Delete(t *testing.T) { require.NoError(t, ks.Add(addr1, testutils.SimulatedChainID)) require.NoError(t, ks.Enable(addr1, testutils.SimulatedChainID)) - testutils.AssertCount(t, db, "evm_key_states", 4) + testutils.AssertCount(t, db, "evm.key_states", 4) keys, err := ks.GetAll() require.NoError(t, err) assert.Len(t, keys, 3) @@ -781,7 +781,7 @@ func Test_EthKeyStore_Delete(t *testing.T) { require.NoError(t, err) assert.Equal(t, addr1, deletedK.Address) - testutils.AssertCount(t, db, "evm_key_states", 2) + testutils.AssertCount(t, db, "evm.key_states", 2) keys, err = ks.GetAll() require.NoError(t, err) assert.Len(t, keys, 2) diff --git a/core/services/keystore/master.go b/core/services/keystore/master.go index 4a8333d8448..ab4c3256c5c 100644 --- a/core/services/keystore/master.go +++ b/core/services/keystore/master.go @@ -51,7 +51,6 @@ type Master interface { StarkNet() StarkNet VRF() VRF Unlock(password string) error - Migrate(vrfPassword string, f DefaultEVMChainIDFunc) error IsEmpty() (bool, error) } @@ -151,93 +150,6 @@ func (ks *master) IsEmpty() (bool, error) { return count == 0, nil } -func (ks *master) Migrate(vrfPssword string, f DefaultEVMChainIDFunc) error { - ks.lock.Lock() - defer ks.lock.Unlock() - if ks.isLocked() { - return ErrLocked - } - csaKeys, err := ks.csa.GetV1KeysAsV2() - if err != nil { - return err - } - for _, csaKey := range csaKeys { - if _, exists := ks.keyRing.CSA[csaKey.ID()]; exists { - continue - } - ks.logger.Debugf("Migrating CSA key %s", csaKey.ID()) - ks.keyRing.CSA[csaKey.ID()] = csaKey - } - ocrKeys, err := ks.ocr.GetV1KeysAsV2() - if err != nil { - return err - } - for _, ocrKey := range ocrKeys { - if _, exists := ks.keyRing.OCR[ocrKey.ID()]; exists { - continue - } - ks.logger.Debugf("Migrating OCR key %s", ocrKey.ID()) - ks.keyRing.OCR[ocrKey.ID()] = ocrKey - } - p2pKeys, err := ks.p2p.GetV1KeysAsV2() - if err != nil { - return err - } - for _, p2pKey := range p2pKeys { - if _, exists := ks.keyRing.P2P[p2pKey.ID()]; exists { - continue - } - ks.logger.Debugf("Migrating P2P key %s", p2pKey.ID()) - ks.keyRing.P2P[p2pKey.ID()] = p2pKey - } - vrfKeys, err := ks.vrf.GetV1KeysAsV2(vrfPssword) - if err != nil { - return err - } - for _, vrfKey := range vrfKeys { - if _, exists := ks.keyRing.VRF[vrfKey.ID()]; exists { - continue - } - ks.logger.Debugf("Migrating VRF key %s", vrfKey.ID()) - ks.keyRing.VRF[vrfKey.ID()] = vrfKey - } - if err = ks.keyManager.save(); err != nil { - return err - } - ethKeys, nonces, fundings, err := ks.eth.getV1KeysAsV2() - if err != nil { - return err - } - if len(ethKeys) > 0 { - chainID, err := f() - if err != nil { - return errors.Wrapf(err, `%d legacy eth keys detected, but no default EVM chain ID was specified - -PLEASE READ THIS ADDITIONAL INFO - -If you are running Chainlink with EVM.Enabled=false and don't care about EVM keys at all, you can run the following SQL to remove any lingering eth keys that may have been autogenerated by an older version of Chainlink, and boot the node again: - -pqsl> TRUNCATE keys; - -WARNING: This will PERMANENTLY AND IRRECOVERABLY delete any legacy eth keys, so please be absolutely sure this is what you want before you run this. Consider taking a database backup first`, len(ethKeys)) - } - for i, ethKey := range ethKeys { - if _, exists := ks.keyRing.Eth[ethKey.ID()]; exists { - continue - } - ks.logger.Debugf("Migrating Eth key %s (and pegging to chain ID %s)", ethKey.ID(), chainID.String()) - // Note that V1 keys that were "funding" will be migrated as "disabled" - if err = ks.eth.addWithNonce(ethKey, chainID, nonces[i], fundings[i]); err != nil { - return err - } - if err = ks.keyManager.save(); err != nil { - return err - } - } - } - return nil -} - type keyManager struct { orm ksORM scryptParams utils.ScryptParams diff --git a/core/services/keystore/mocks/master.go b/core/services/keystore/mocks/master.go index ec55dc21089..e8b4775d662 100644 --- a/core/services/keystore/mocks/master.go +++ b/core/services/keystore/mocks/master.go @@ -116,20 +116,6 @@ func (_m *Master) IsEmpty() (bool, error) { return r0, r1 } -// Migrate provides a mock function with given fields: vrfPassword, f -func (_m *Master) Migrate(vrfPassword string, f keystore.DefaultEVMChainIDFunc) error { - ret := _m.Called(vrfPassword, f) - - var r0 error - if rf, ok := ret.Get(0).(func(string, keystore.DefaultEVMChainIDFunc) error); ok { - r0 = rf(vrfPassword, f) - } else { - r0 = ret.Error(0) - } - - return r0 -} - // OCR provides a mock function with given fields: func (_m *Master) OCR() keystore.OCR { ret := _m.Called() diff --git a/core/services/keystore/orm.go b/core/services/keystore/orm.go index d71b8378532..1396b544205 100644 --- a/core/services/keystore/orm.go +++ b/core/services/keystore/orm.go @@ -67,8 +67,8 @@ func (orm ksORM) getEncryptedKeyRing() (kr encryptedKeyRing, err error) { func (orm ksORM) loadKeyStates() (*keyStates, error) { ks := newKeyStates() var ethkeystates []*ethkey.State - if err := orm.q.Select(ðkeystates, `SELECT id, address, evm_chain_id, next_nonce, disabled, created_at, updated_at FROM evm_key_states`); err != nil { - return ks, errors.Wrap(err, "error loading evm_key_states from DB") + if err := orm.q.Select(ðkeystates, `SELECT id, address, evm_chain_id, next_nonce, disabled, created_at, updated_at FROM evm.key_states`); err != nil { + return ks, errors.Wrap(err, "error loading evm.key_states from DB") } for _, state := range ethkeystates { ks.add(state) @@ -76,20 +76,20 @@ func (orm ksORM) loadKeyStates() (*keyStates, error) { return ks, nil } -// getNextNonce returns evm_key_states.next_nonce for the given address +// getNextNonce returns evm.key_states.next_nonce for the given address func (orm ksORM) getNextNonce(address common.Address, chainID *big.Int, qopts ...pg.QOpt) (nonce int64, err error) { q := orm.q.WithOpts(qopts...) - err = q.Get(&nonce, "SELECT next_nonce FROM evm_key_states WHERE address = $1 AND evm_chain_id = $2 AND disabled = false", address, chainID.String()) + err = q.Get(&nonce, "SELECT next_nonce FROM evm.key_states WHERE address = $1 AND evm_chain_id = $2 AND disabled = false", address, chainID.String()) if errors.Is(err, sql.ErrNoRows) { return 0, errors.Wrapf(sql.ErrNoRows, "key with address %s is not enabled for chain %s", address.Hex(), chainID.String()) } return nonce, errors.Wrap(err, "failed to load next nonce") } -// incrementNextNonce increments evm_key_states.next_nonce by 1 +// incrementNextNonce increments evm.key_states.next_nonce by 1 func (orm ksORM) incrementNextNonce(address common.Address, chainID *big.Int, currentNonce int64, qopts ...pg.QOpt) (incrementedNonce int64, err error) { q := orm.q.WithOpts(qopts...) - err = q.Get(&incrementedNonce, "UPDATE evm_key_states SET next_nonce = next_nonce + 1, updated_at = NOW() WHERE address = $1 AND next_nonce = $2 AND evm_chain_id = $3 AND disabled = false RETURNING next_nonce", address, currentNonce, chainID.String()) + err = q.Get(&incrementedNonce, "UPDATE evm.key_states SET next_nonce = next_nonce + 1, updated_at = NOW() WHERE address = $1 AND next_nonce = $2 AND evm_chain_id = $3 AND disabled = false RETURNING next_nonce", address, currentNonce, chainID.String()) return incrementedNonce, errors.Wrap(err, "IncrementNextNonce failed to update keys") } diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 2a8fea38efe..2d1ff41ac12 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -265,7 +265,7 @@ func (d *Delegate) cleanupEVM(jb job.Job, q pg.Queryer, relayID relay.ID) error // an inconsistent state. This assumes UnregisterFilter will return nil if the filter wasn't found // at all (no rows deleted). spec := jb.OCR2OracleSpec - chain, err := d.legacyChains.Get(relayID.ChainID.String()) + chain, err := d.legacyChains.Get(relayID.ChainID) if err != nil { d.lggr.Error("cleanupEVM: failed to chain get chain %s", "err", relayID.ChainID, err) return nil @@ -274,12 +274,12 @@ func (d *Delegate) cleanupEVM(jb job.Job, q pg.Queryer, relayID relay.ID) error var filters []string switch spec.PluginType { - case job.OCR2VRF: + 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 job.OCR2Keeper: + case types.OCR2Keeper: filters, err = ocr2keeper.FilterNamesFromSpec20(spec) if err != nil { d.lggr.Errorw("failed to derive ocr2keeper filter names from spec", "err", err, "spec", spec) @@ -345,7 +345,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceC if rid.Network == relay.EVM { lggr = logger.Sugared(lggr.With("evmChainID", rid.ChainID)) - chain, err2 := d.legacyChains.Get(rid.ChainID.String()) + chain, err2 := d.legacyChains.Get(rid.ChainID) if err2 != nil { return nil, fmt.Errorf("ServicesForSpec: could not get EVM chain %s: %w", rid.ChainID, err2) } @@ -405,22 +405,22 @@ func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceC ctx := lggrCtx.ContextWithValues(context.Background()) switch spec.PluginType { - case job.Mercury: + case types.Mercury: return d.newServicesMercury(ctx, lggr, jb, runResults, bootstrapPeers, kb, ocrDB, lc, ocrLogger) - case job.Median: + case types.Median: return d.newServicesMedian(ctx, lggr, jb, runResults, bootstrapPeers, kb, ocrDB, lc, ocrLogger) - case job.DKG: + case types.DKG: return d.newServicesDKG(lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger) - case job.OCR2VRF: + case types.OCR2VRF: return d.newServicesOCR2VRF(lggr, jb, runResults, bootstrapPeers, kb, ocrDB, lc) - case job.OCR2Keeper: + case types.OCR2Keeper: return d.newServicesOCR2Keepers(lggr, jb, runResults, bootstrapPeers, kb, ocrDB, lc, ocrLogger) - case job.OCR2Functions: + case types.Functions: const ( _ int32 = iota thresholdPluginId @@ -437,7 +437,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceC func GetEVMEffectiveTransmitterID(jb *job.Job, chain evm.Chain, lggr logger.SugaredLogger) (string, error) { spec := jb.OCR2OracleSpec - if spec.PluginType == job.Mercury { + if spec.PluginType == types.Mercury { return spec.TransmitterID.String, nil } @@ -448,7 +448,7 @@ func GetEVMEffectiveTransmitterID(jb *job.Job, chain evm.Chain, lggr logger.Suga if err != nil { return "", err } - if len(sendingKeys) > 1 && spec.PluginType != job.OCR2VRF { + if len(sendingKeys) > 1 && spec.PluginType != types.OCR2VRF { return "", errors.New("only ocr2 vrf should have more than 1 sending key") } spec.TransmitterID = null.StringFrom(sendingKeys[0]) @@ -509,18 +509,19 @@ func (d *Delegate) newServicesMercury( if err != nil { return nil, fmt.Errorf("failed to get relay %s is it enabled?: %w", spec.Relay, err) } - chain, err := d.legacyChains.Get(rid.ChainID.String()) + chain, err := d.legacyChains.Get(rid.ChainID) if err != nil { return nil, fmt.Errorf("mercury services: failed to get chain %s: %w", rid.ChainID, err) } - mercuryProvider, err2 := relayer.NewMercuryProvider(ctx, + provider, err2 := relayer.NewPluginProvider(ctx, types.RelayArgs{ ExternalJobID: jb.ExternalJobID, JobID: spec.ID, ContractID: spec.ContractID, New: d.isNewlyCreatedJob, RelayConfig: spec.RelayConfig.Bytes(), + ProviderType: string(spec.PluginType), }, types.PluginArgs{ TransmitterID: transmitterID, PluginConfig: spec.PluginConfig.Bytes(), @@ -529,6 +530,11 @@ func (d *Delegate) newServicesMercury( return nil, err2 } + mercuryProvider, ok := provider.(types.MercuryProvider) + if !ok { + return nil, errors.New("could not coerce PluginProvider to MercuryProvider") + } + oracleArgsNoPlugin := libocr2.MercuryOracleArgs{ BinaryNetworkEndpointFactory: d.peerWrapper.Peer2, V2Bootstrappers: bootstrapPeers, @@ -618,7 +624,7 @@ func (d *Delegate) newServicesDKG( return nil, fmt.Errorf("DKG services: expected EVM relayer got %s", rid.Network) } - chain, err2 := d.legacyChains.Get(rid.ChainID.String()) + 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) } @@ -686,7 +692,7 @@ func (d *Delegate) newServicesOCR2VRF( if rid.Network != relay.EVM { return nil, fmt.Errorf("VRF services: expected EVM relayer got %s", rid.Network) } - chain, err2 := d.legacyChains.Get(rid.ChainID.String()) + 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) } @@ -912,7 +918,7 @@ func (d *Delegate) newServicesOCR2Keepers21( return nil, fmt.Errorf("keeper2 services: expected EVM relayer got %s", rid.Network) } - chain, err2 := d.legacyChains.Get(rid.ChainID.String()) + chain, err2 := d.legacyChains.Get(rid.ChainID) if err2 != nil { return nil, fmt.Errorf("keeper2 services: failed to get chain %s: %w", rid.ChainID, err2) } @@ -1025,7 +1031,7 @@ func (d *Delegate) newServicesOCR2Keepers20( if rid.Network != relay.EVM { return nil, fmt.Errorf("keepers2.0 services: expected EVM relayer got %s", rid.Network) } - chain, err2 := d.legacyChains.Get(rid.ChainID.String()) + chain, err2 := d.legacyChains.Get(rid.ChainID) if err2 != nil { return nil, fmt.Errorf("keepers2.0 services: failed to get chain (%s): %w", rid.ChainID, err2) } @@ -1160,7 +1166,7 @@ func (d *Delegate) newServicesOCR2Functions( if rid.Network != relay.EVM { return nil, fmt.Errorf("functions services: expected EVM relayer got %s", rid.Network) } - chain, err := d.legacyChains.Get(rid.ChainID.String()) + chain, err := d.legacyChains.Get(rid.ChainID) if err != nil { return nil, fmt.Errorf("functions services: failed to get chain %s: %w", rid.ChainID, err) } diff --git a/core/services/ocr2/delegate_test.go b/core/services/ocr2/delegate_test.go index e78af2e19b4..97c9faa44d4 100644 --- a/core/services/ocr2/delegate_test.go +++ b/core/services/ocr2/delegate_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-relay/pkg/types" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -49,7 +50,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { type testCase struct { name string - pluginType job.OCR2PluginType + pluginType types.OCR2PluginType transmitterID null.String sendingKeys []any expectedError bool @@ -75,7 +76,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { testCases := []testCase{ { name: "mercury plugin should just return transmitterID", - pluginType: job.Mercury, + pluginType: types.Mercury, transmitterID: null.StringFrom("Mercury transmitterID"), expectedTransmitterID: "Mercury transmitterID", }, @@ -91,7 +92,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { }, { name: "when transmitterID is not defined and plugin is ocr2vrf, it should allow>1 sendingKeys and set transmitterID to the first one", - pluginType: job.OCR2VRF, + pluginType: types.OCR2VRF, sendingKeys: []any{"0x7e57000000000000000000000000000000000000", "0x7e57000000000000000000000000000000000001", "0x7e57000000000000000000000000000000000002"}, expectedTransmitterID: "0x7e57000000000000000000000000000000000000", }, @@ -109,7 +110,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { }, { name: "when forwarders are enabled and when transmitterID is not defined, it should use first sendingKey to retrieve forwarder address", - pluginType: job.OCR2VRF, + pluginType: types.OCR2VRF, forwardingEnabled: true, sendingKeys: []any{"0x7e57000000000000000000000000000000000001", "0x7e57000000000000000000000000000000000002"}, getForwarderForEOAArg: common.HexToAddress("0x7e57000000000000000000000000000000000001"), @@ -117,7 +118,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { }, { 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: job.OCR2VRF, + pluginType: types.OCR2VRF, forwardingEnabled: true, sendingKeys: []any{"0x7e57000000000000000000000000000000000001", "0x7e57000000000000000000000000000000000002"}, getForwarderForEOAArg: common.HexToAddress("0x7e57000000000000000000000000000000000001"), diff --git a/core/services/ocr2/models/models.go b/core/services/ocr2/models/models.go index 970c0aa7e0a..4d3b8bf532c 100644 --- a/core/services/ocr2/models/models.go +++ b/core/services/ocr2/models/models.go @@ -1,11 +1,8 @@ package models type MercuryCredentials struct { - URL string - Username string - Password string -} - -func (mc *MercuryCredentials) Validate() bool { - return mc.URL != "" && mc.Username != "" && mc.Password != "" + LegacyURL string + URL string + Username string + Password string } diff --git a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go index bedfdc92d19..c376213ed13 100644 --- a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go +++ b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go @@ -192,11 +192,13 @@ func StartNewChainWithContracts(t *testing.T, nClients int) (*bind.TransactOpts, var handleOracleFulfillmentSelector [4]byte copy(handleOracleFulfillmentSelector[:], handleOracleFulfillmentSelectorSlice[:4]) functionsRouterConfig := functions_router.FunctionsRouterConfig{ - MaxConsumersPerSubscription: uint16(100), - AdminFee: big.NewInt(0), - HandleOracleFulfillmentSelector: handleOracleFulfillmentSelector, - MaxCallbackGasLimits: []uint32{300_000, 500_000, 1_000_000}, - GasForCallExactCheck: 5000, + MaxConsumersPerSubscription: uint16(100), + AdminFee: big.NewInt(0), + HandleOracleFulfillmentSelector: handleOracleFulfillmentSelector, + MaxCallbackGasLimits: []uint32{300_000, 500_000, 1_000_000}, + GasForCallExactCheck: 5000, + SubscriptionDepositMinimumRequests: 10, + SubscriptionDepositJuels: big.NewInt(9 * 1e18), // 9 LINK } routerAddress, _, routerContract, err := functions_router.DeployFunctionsRouter(owner, b, linkAddr, functionsRouterConfig) require.NoError(t, err) @@ -214,7 +216,6 @@ func StartNewChainWithContracts(t *testing.T, nClients int) (*bind.TransactOpts, // Deploy Coordinator contract (matches updateConfig() in FunctionsBilling.sol) coordinatorConfig := functions_coordinator.FunctionsBillingConfig{ - MaxCallbackGasLimit: uint32(450_000), FeedStalenessSeconds: uint32(86_400), GasOverheadBeforeCallback: uint32(325_000), GasOverheadAfterCallback: uint32(50_000), diff --git a/core/services/ocr2/plugins/functions/reporting.go b/core/services/ocr2/plugins/functions/reporting.go index 7f532439c6a..9f6c6848edf 100644 --- a/core/services/ocr2/plugins/functions/reporting.go +++ b/core/services/ocr2/plugins/functions/reporting.go @@ -4,7 +4,9 @@ import ( "context" "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" + "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "google.golang.org/protobuf/proto" @@ -117,6 +119,21 @@ func (f FunctionsReportingPluginFactory) NewReportingPlugin(rpConfig types.Repor return &plugin, info, nil } +// Check if requestCoordinator can be included together with reportCoordinator. +// Return new reportCoordinator (if previous was nil) and error. +func ShouldIncludeCoordinator(requestCoordinator *common.Address, reportCoordinator *common.Address) (*common.Address, error) { + if requestCoordinator == nil || *requestCoordinator == (common.Address{}) { + return reportCoordinator, errors.New("missing/zero request coordinator address") + } + if reportCoordinator == nil { + return requestCoordinator, nil + } + if *reportCoordinator != *requestCoordinator { + return reportCoordinator, errors.New("coordinator contract address mismatch") + } + return reportCoordinator, nil +} + // Query() complies with ReportingPlugin func (r *functionsReporting) Query(ctx context.Context, ts types.ReportTimestamp) (types.Query, error) { r.logger.Debug("FunctionsReporting Query start", commontypes.LogFields{ @@ -132,8 +149,21 @@ func (r *functionsReporting) Query(ctx context.Context, ts types.ReportTimestamp queryProto := encoding.Query{} var idStrs []string + var reportCoordinator *common.Address for _, result := range results { result := result + if r.contractVersion == 1 { + reportCoordinator, err = ShouldIncludeCoordinator(result.CoordinatorContractAddress, reportCoordinator) + if err != nil { + r.logger.Debug("FunctionsReporting Query: skipping request with mismatched coordinator contract address", commontypes.LogFields{ + "requestID": formatRequestId(result.RequestID[:]), + "requestCoordinator": result.CoordinatorContractAddress, + "reportCoordinator": reportCoordinator, + "error": err, + }) + continue + } + } queryProto.RequestIDs = append(queryProto.RequestIDs, result.RequestID[:]) idStrs = append(idStrs, formatRequestId(result.RequestID[:])) } @@ -288,6 +318,7 @@ func (r *functionsReporting) Report(ctx context.Context, ts types.ReportTimestam var allAggregated []*encoding.ProcessedRequest var allIdStrs []string var totalCallbackGas uint32 + var reportCoordinator *common.Address for _, reqId := range uniqueQueryIds { observations := reqIdToObservationList[reqId] if !CanAggregate(r.genericConfig.N, r.genericConfig.F, observations) { @@ -330,6 +361,20 @@ func (r *functionsReporting) Report(ctx context.Context, ts types.ReportTimestam "requestID": reqId, "nObservations": len(observations), }) + if r.contractVersion == 1 { + var requestCoordinator common.Address + requestCoordinator.SetBytes(aggregated.CoordinatorContract) + reportCoordinator, err = ShouldIncludeCoordinator(&requestCoordinator, reportCoordinator) + if err != nil { + r.logger.Error("FunctionsReporting Report: skipping request with mismatched coordinator contract address", commontypes.LogFields{ + "requestID": reqId, + "requestCoordinator": requestCoordinator, + "reportCoordinator": reportCoordinator, + "error": err, + }) + continue + } + } allAggregated = append(allAggregated, aggregated) allIdStrs = append(allIdStrs, reqId) } diff --git a/core/services/ocr2/plugins/functions/reporting_test.go b/core/services/ocr2/plugins/functions/reporting_test.go index e08a0aca7a0..6d5126c9390 100644 --- a/core/services/ocr2/plugins/functions/reporting_test.go +++ b/core/services/ocr2/plugins/functions/reporting_test.go @@ -134,6 +134,26 @@ func TestFunctionsReporting_Query(t *testing.T) { require.Equal(t, reqs[1].RequestID[:], queryProto.RequestIDs[1]) } +func TestFunctionsReporting_Query_HandleCoordinatorMismatch(t *testing.T) { + t.Parallel() + const batchSize = 10 + plugin, orm, _ := preparePlugin(t, batchSize, 1, 1000000) + reqs := []functions_srv.Request{newRequest(), newRequest()} + reqs[0].CoordinatorContractAddress = &common.Address{1} + reqs[1].CoordinatorContractAddress = &common.Address{2} + orm.On("FindOldestEntriesByState", functions_srv.RESULT_READY, uint32(batchSize), mock.Anything).Return(reqs, nil) + + q, err := plugin.Query(testutils.Context(t), types.ReportTimestamp{}) + require.NoError(t, err) + + queryProto := &encoding.Query{} + err = proto.Unmarshal(q, queryProto) + require.NoError(t, err) + require.Equal(t, 1, len(queryProto.RequestIDs)) + require.Equal(t, reqs[0].RequestID[:], queryProto.RequestIDs[0]) + // reqs[1] should be excluded from this query because it has a different coordinator address +} + func TestFunctionsReporting_Observation(t *testing.T) { t.Parallel() plugin, orm, _ := preparePlugin(t, 10, 0, 0) @@ -239,10 +259,10 @@ func TestFunctionsReporting_Report_WithGasLimitAndMetadata(t *testing.T) { reqId1, reqId2, reqId3 := newRequestID(), newRequestID(), newRequestID() compResult := []byte("aaa") gasLimit1, gasLimit2 := uint32(100_000), uint32(200_000) - coordinatorContract1, coordinatorContract2 := common.Address{1}, common.Address{2} + coordinatorContract := common.Address{1} meta1, meta2 := []byte("meta1"), []byte("meta2") - procReq1 := newProcessedRequestWithMeta(reqId1, compResult, []byte{}, gasLimit1, coordinatorContract1[:], meta1) - procReq2 := newProcessedRequestWithMeta(reqId2, compResult, []byte{}, gasLimit2, coordinatorContract2[:], meta2) + procReq1 := newProcessedRequestWithMeta(reqId1, compResult, []byte{}, gasLimit1, coordinatorContract[:], meta1) + procReq2 := newProcessedRequestWithMeta(reqId2, compResult, []byte{}, gasLimit2, coordinatorContract[:], meta2) query := newMarshalledQuery(t, reqId1, reqId2, reqId3, reqId1, reqId2) // duplicates should be ignored obs := []types.AttributedObservation{ @@ -262,18 +282,48 @@ func TestFunctionsReporting_Report_WithGasLimitAndMetadata(t *testing.T) { require.Equal(t, reqId1[:], decoded[0].RequestID) require.Equal(t, compResult, decoded[0].Result) require.Equal(t, []byte{}, decoded[0].Error) - require.Equal(t, coordinatorContract1[:], decoded[0].CoordinatorContract) + require.Equal(t, coordinatorContract[:], decoded[0].CoordinatorContract) require.Equal(t, meta1, decoded[0].OnchainMetadata) // CallbackGasLimit is not ABI-encoded require.Equal(t, reqId2[:], decoded[1].RequestID) require.Equal(t, compResult, decoded[1].Result) require.Equal(t, []byte{}, decoded[1].Error) - require.Equal(t, coordinatorContract2[:], decoded[1].CoordinatorContract) + require.Equal(t, coordinatorContract[:], decoded[1].CoordinatorContract) require.Equal(t, meta2, decoded[1].OnchainMetadata) // CallbackGasLimit is not ABI-encoded } +func TestFunctionsReporting_Report_HandleCoordinatorMismatch(t *testing.T) { + t.Parallel() + plugin, _, codec := preparePlugin(t, 10, 1, 300000) + reqId1, reqId2, reqId3 := newRequestID(), newRequestID(), newRequestID() + compResult, meta := []byte("aaa"), []byte("meta") + coordinatorContractA, coordinatorContractB := common.Address{1}, common.Address{2} + procReq1 := newProcessedRequestWithMeta(reqId1, compResult, []byte{}, 0, coordinatorContractA[:], meta) + procReq2 := newProcessedRequestWithMeta(reqId2, compResult, []byte{}, 0, coordinatorContractB[:], meta) + procReq3 := newProcessedRequestWithMeta(reqId3, compResult, []byte{}, 0, coordinatorContractA[:], meta) + + query := newMarshalledQuery(t, reqId1, reqId2, reqId3, reqId1, reqId2) // duplicates should be ignored + obs := []types.AttributedObservation{ + newObservation(t, 1, procReq2, procReq3, procReq1), + newObservation(t, 2, procReq1, procReq2, procReq3), + newObservation(t, 3, procReq3, procReq1, procReq2), + } + + produced, reportBytes, err := plugin.Report(testutils.Context(t), types.ReportTimestamp{}, query, obs) + require.True(t, produced) + require.NoError(t, err) + + decoded, err := codec.DecodeReport(reportBytes) + require.NoError(t, err) + require.Equal(t, 2, len(decoded)) + + require.Equal(t, reqId1[:], decoded[0].RequestID) + require.Equal(t, reqId3[:], decoded[1].RequestID) + // reqId2 should be excluded from this report because it has a different coordinator address +} + func TestFunctionsReporting_Report_CallbackGasLimitExceeded(t *testing.T) { t.Parallel() plugin, _, codec := preparePlugin(t, 10, 1, 200000) @@ -438,3 +488,34 @@ func TestFunctionsReporting_ShouldTransmitAcceptedReport(t *testing.T) { require.NoError(t, err) require.True(t, should) } + +func TestFunctionsReporting_ShouldIncludeCoordinator(t *testing.T) { + t.Parallel() + + zeroAddr, coord1, coord2 := &common.Address{}, &common.Address{1}, &common.Address{2} + + // should never pass nil requestCoordinator + newCoord, err := functions.ShouldIncludeCoordinator(nil, nil) + require.Error(t, err) + require.Nil(t, newCoord) + + // should never pass zero requestCoordinator + newCoord, err = functions.ShouldIncludeCoordinator(zeroAddr, nil) + require.Error(t, err) + require.Nil(t, newCoord) + + // overwrite nil reportCoordinator + newCoord, err = functions.ShouldIncludeCoordinator(coord1, nil) + require.NoError(t, err) + require.Equal(t, coord1, newCoord) + + // same address is fine + newCoord, err = functions.ShouldIncludeCoordinator(coord1, newCoord) + require.NoError(t, err) + require.Equal(t, coord1, newCoord) + + // different address is not accepted + newCoord, err = functions.ShouldIncludeCoordinator(coord2, newCoord) + require.Error(t, err) + require.Equal(t, coord1, newCoord) +} diff --git a/core/services/ocr2/plugins/median/services.go b/core/services/ocr2/plugins/median/services.go index 8ff97c2cc56..e435ee747f5 100644 --- a/core/services/ocr2/plugins/median/services.go +++ b/core/services/ocr2/plugins/median/services.go @@ -3,6 +3,7 @@ package median import ( "context" "encoding/json" + "errors" "fmt" "time" @@ -67,12 +68,13 @@ func NewMedianServices(ctx context.Context, } spec := jb.OCR2OracleSpec - provider, err := relayer.NewMedianProvider(ctx, types.RelayArgs{ + provider, err := relayer.NewPluginProvider(ctx, types.RelayArgs{ ExternalJobID: jb.ExternalJobID, JobID: spec.ID, ContractID: spec.ContractID, New: isNewlyCreatedJob, RelayConfig: spec.RelayConfig.Bytes(), + ProviderType: string(spec.PluginType), }, types.PluginArgs{ TransmitterID: spec.TransmitterID.String, PluginConfig: spec.PluginConfig.Bytes(), @@ -80,6 +82,12 @@ func NewMedianServices(ctx context.Context, if err != nil { return } + + medianProvider, ok := provider.(types.MedianProvider) + if !ok { + return nil, errors.New("could not coerce PluginProvider to MedianProvider") + } + srvs = append(srvs, provider) argsNoPlugin.ContractTransmitter = provider.ContractTransmitter() argsNoPlugin.ContractConfigTracker = provider.ContractConfigTracker() @@ -113,11 +121,11 @@ func NewMedianServices(ctx context.Context, abort() return } - median := loop.NewMedianService(lggr, telem, cmdFn, provider, dataSource, juelsPerFeeCoinSource, errorLog) + median := loop.NewMedianService(lggr, telem, cmdFn, medianProvider, dataSource, juelsPerFeeCoinSource, errorLog) argsNoPlugin.ReportingPluginFactory = median srvs = append(srvs, median) } else { - argsNoPlugin.ReportingPluginFactory, err = NewPlugin(lggr).NewMedianFactory(ctx, provider, dataSource, juelsPerFeeCoinSource, errorLog) + argsNoPlugin.ReportingPluginFactory, err = NewPlugin(lggr).NewMedianFactory(ctx, medianProvider, dataSource, juelsPerFeeCoinSource, errorLog) if err != nil { err = fmt.Errorf("failed to create median factory: %w", err) abort() diff --git a/core/services/ocr2/plugins/mercury/helpers_test.go b/core/services/ocr2/plugins/mercury/helpers_test.go index e93f161916a..ddb521ff9ca 100644 --- a/core/services/ocr2/plugins/mercury/helpers_test.go +++ b/core/services/ocr2/plugins/mercury/helpers_test.go @@ -22,7 +22,14 @@ import ( "go.uber.org/zap/zaptest/observer" "github.com/smartcontractkit/libocr/commontypes" + "github.com/smartcontractkit/libocr/offchainreporting2/chains/evmutil" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/keystest" + "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" @@ -30,17 +37,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" - "github.com/smartcontractkit/chainlink/v2/core/utils" - - relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" - - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/keystest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/store/models" + "github.com/smartcontractkit/chainlink/v2/core/utils" ) var _ pb.MercuryServer = &mercuryServer{} @@ -51,13 +51,14 @@ type request struct { } type mercuryServer struct { - privKey ed25519.PrivateKey - reqsCh chan request - t *testing.T + privKey ed25519.PrivateKey + reqsCh chan request + t *testing.T + buildReport func() []byte } -func NewMercuryServer(t *testing.T, privKey ed25519.PrivateKey, reqsCh chan request) *mercuryServer { - return &mercuryServer{privKey, reqsCh, t} +func NewMercuryServer(t *testing.T, privKey ed25519.PrivateKey, reqsCh chan request, buildReport func() []byte) *mercuryServer { + return &mercuryServer{privKey, reqsCh, t, buildReport} } func (s *mercuryServer) Transmit(ctx context.Context, req *pb.TransmitRequest) (*pb.TransmitResponse, error) { @@ -85,9 +86,12 @@ func (s *mercuryServer) LatestReport(ctx context.Context, lrr *pb.LatestReportRe out.Report = new(pb.Report) out.Report.FeedId = lrr.FeedId - price := big.NewInt(123456789) - encodedPrice, _ := relaymercury.EncodeValueInt192(price) - out.Report.Price = encodedPrice + report := s.buildReport() + payload, err := mercury.PayloadTypes.Pack(evmutil.RawReportContext(ocrtypes.ReportContext{}), report, [][32]byte{}, [][32]byte{}, [32]byte{}) + if err != nil { + panic(err) + } + out.Report.Payload = payload return out, nil } diff --git a/core/services/ocr2/plugins/mercury/integration_test.go b/core/services/ocr2/plugins/mercury/integration_test.go index b75855b8db5..aab1cadc5a5 100644 --- a/core/services/ocr2/plugins/mercury/integration_test.go +++ b/core/services/ocr2/plugins/mercury/integration_test.go @@ -25,7 +25,7 @@ import ( "github.com/shopspring/decimal" "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" - ocr3confighelper "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/wsrpc/credentials" "github.com/stretchr/testify/assert" @@ -34,6 +34,9 @@ import ( "go.uber.org/zap/zaptest/observer" relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" + relaycodecv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" + relaycodecv2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" + relaycodecv3 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v3" "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" @@ -64,7 +67,7 @@ var ( } rawReportingPluginConfig = relaymercury.OffchainConfig{ ExpirationWindow: 1, - BaseUSDFeeCents: 100, + BaseUSDFee: decimal.NewFromInt(100), } ) @@ -149,7 +152,13 @@ func TestIntegration_MercuryV1(t *testing.T) { reqs := make(chan request) serverKey := csakey.MustNewV2XXXTestingOnly(big.NewInt(-1)) serverPubKey := serverKey.PublicKey - srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs) + srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs, func() []byte { + report, err := (&reportcodecv1.ReportCodec{}).BuildReport(relaycodecv1.ReportFields{BenchmarkPrice: big.NewInt(234567), Bid: big.NewInt(1), Ask: big.NewInt(1), CurrentBlockHash: make([]byte, 32)}) + if err != nil { + panic(err) + } + return report + }) clientCSAKeys := make([]csakey.KeyV2, n+1) clientPubKeys := make([]ed25519.PublicKey, n+1) for i := 0; i < n+1; i++ { @@ -494,7 +503,13 @@ func TestIntegration_MercuryV2(t *testing.T) { reqs := make(chan request) serverKey := csakey.MustNewV2XXXTestingOnly(big.NewInt(-1)) serverPubKey := serverKey.PublicKey - srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs) + srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs, func() []byte { + report, err := (&reportcodecv2.ReportCodec{}).BuildReport(relaycodecv2.ReportFields{BenchmarkPrice: big.NewInt(234567), LinkFee: big.NewInt(1), NativeFee: big.NewInt(1)}) + if err != nil { + panic(err) + } + return report + }) clientCSAKeys := make([]csakey.KeyV2, n+1) clientPubKeys := make([]ed25519.PublicKey, n+1) for i := 0; i < n+1; i++ { @@ -686,7 +701,7 @@ func TestIntegration_MercuryV2(t *testing.T) { continue // already saw all oracles for this feed } - expectedFee := relaymercury.CalculateFee(big.NewInt(123456789), rawReportingPluginConfig.BaseUSDFeeCents) + expectedFee := relaymercury.CalculateFee(big.NewInt(234567), rawReportingPluginConfig.BaseUSDFee) expectedExpiresAt := reportElems["observationsTimestamp"].(uint32) + rawReportingPluginConfig.ExpirationWindow assert.GreaterOrEqual(t, int(reportElems["observationsTimestamp"].(uint32)), int(testStartTimeStamp)) @@ -766,7 +781,13 @@ func TestIntegration_MercuryV3(t *testing.T) { reqs := make(chan request) serverKey := csakey.MustNewV2XXXTestingOnly(big.NewInt(-1)) serverPubKey := serverKey.PublicKey - srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs) + srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs, func() []byte { + report, err := (&reportcodecv3.ReportCodec{}).BuildReport(relaycodecv3.ReportFields{BenchmarkPrice: big.NewInt(234567), Bid: big.NewInt(1), Ask: big.NewInt(1), LinkFee: big.NewInt(1), NativeFee: big.NewInt(1)}) + if err != nil { + panic(err) + } + return report + }) clientCSAKeys := make([]csakey.KeyV2, n+1) clientPubKeys := make([]ed25519.PublicKey, n+1) for i := 0; i < n+1; i++ { @@ -962,7 +983,7 @@ func TestIntegration_MercuryV3(t *testing.T) { continue // already saw all oracles for this feed } - expectedFee := relaymercury.CalculateFee(big.NewInt(123456789), rawReportingPluginConfig.BaseUSDFeeCents) + expectedFee := relaymercury.CalculateFee(big.NewInt(234567), rawReportingPluginConfig.BaseUSDFee) expectedExpiresAt := reportElems["observationsTimestamp"].(uint32) + rawReportingPluginConfig.ExpirationWindow assert.GreaterOrEqual(t, int(reportElems["observationsTimestamp"].(uint32)), int(testStartTimeStamp)) diff --git a/core/services/ocr2/plugins/mercury/plugin.go b/core/services/ocr2/plugins/mercury/plugin.go index 64336548a1e..05e7e968f8b 100644 --- a/core/services/ocr2/plugins/mercury/plugin.go +++ b/core/services/ocr2/plugins/mercury/plugin.go @@ -67,7 +67,7 @@ func NewServices( runResults, chEnhancedTelem, chainHeadTracker, - ocr2Provider.ContractTransmitter(), + ocr2Provider.MercuryServerFetcher(), pluginConfig.InitialBlockNumber.Ptr(), feedID, ) @@ -87,7 +87,7 @@ func NewServices( lggr, runResults, chEnhancedTelem, - ocr2Provider.ContractTransmitter(), + ocr2Provider.MercuryServerFetcher(), *pluginConfig.LinkFeedID, *pluginConfig.NativeFeedID, ) @@ -107,7 +107,7 @@ func NewServices( lggr, runResults, chEnhancedTelem, - ocr2Provider.ContractTransmitter(), + ocr2Provider.MercuryServerFetcher(), *pluginConfig.LinkFeedID, *pluginConfig.NativeFeedID, ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go index 9a7d9c5dcc7..87b46c9785b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go @@ -29,11 +29,15 @@ const ( blockHistorySize = int64(256) ) +var ( + BlockSubscriberServiceName = "BlockSubscriber" +) + type BlockSubscriber struct { - sync utils.StartStopOnce + utils.StartStopOnce + threadCtrl utils.ThreadControl + mu sync.RWMutex - ctx context.Context - cancel context.CancelFunc hb httypes.HeadBroadcaster lp logpoller.LogPoller headC chan *evmtypes.Head @@ -53,6 +57,7 @@ var _ ocr2keepers.BlockSubscriber = &BlockSubscriber{} func NewBlockSubscriber(hb httypes.HeadBroadcaster, lp logpoller.LogPoller, lggr logger.Logger) *BlockSubscriber { return &BlockSubscriber{ + threadCtrl: utils.NewThreadControl(), hb: hb, lp: lp, headC: make(chan *evmtypes.Head, channelSize), @@ -81,8 +86,8 @@ func (bs *BlockSubscriber) getBlockRange(ctx context.Context) ([]uint64, error) return blocks, nil } -func (bs *BlockSubscriber) initializeBlocks(blocks []uint64) error { - logpollerBlocks, err := bs.lp.GetBlocksRange(bs.ctx, blocks, pg.WithParentCtx(bs.ctx)) +func (bs *BlockSubscriber) initializeBlocks(ctx context.Context, blocks []uint64) error { + logpollerBlocks, err := bs.lp.GetBlocksRange(ctx, blocks) if err != nil { return err } @@ -127,67 +132,61 @@ func (bs *BlockSubscriber) cleanup() { bs.lggr.Infof("lastClearedBlock is set to %d", bs.lastClearedBlock) } -func (bs *BlockSubscriber) Start(_ context.Context) error { - bs.lggr.Info("block subscriber started.") - return bs.sync.StartOnce("BlockSubscriber", func() error { - bs.mu.Lock() - defer bs.mu.Unlock() - bs.ctx, bs.cancel = context.WithCancel(context.Background()) - // initialize the blocks map with the recent blockSize blocks - blocks, err := bs.getBlockRange(bs.ctx) - if err != nil { - bs.lggr.Errorf("failed to get block range", err) - } - err = bs.initializeBlocks(blocks) - if err != nil { - bs.lggr.Errorf("failed to get log poller blocks", err) - } - - _, bs.unsubscribe = bs.hb.Subscribe(&headWrapper{headC: bs.headC, lggr: bs.lggr}) +func (bs *BlockSubscriber) initialize(ctx context.Context) { + bs.mu.Lock() + defer bs.mu.Unlock() + // initialize the blocks map with the recent blockSize blocks + blocks, err := bs.getBlockRange(ctx) + if err != nil { + bs.lggr.Errorf("failed to get block range", err) + } + err = bs.initializeBlocks(ctx, blocks) + if err != nil { + bs.lggr.Errorf("failed to get log poller blocks", err) + } + _, bs.unsubscribe = bs.hb.Subscribe(&headWrapper{headC: bs.headC, lggr: bs.lggr}) +} +func (bs *BlockSubscriber) Start(ctx context.Context) error { + return bs.StartOnce(BlockSubscriberServiceName, func() error { + bs.lggr.Info("block subscriber started.") + bs.initialize(ctx) // poll from head broadcaster channel and push to subscribers - { - go func(ctx context.Context) { - for { - select { - case h := <-bs.headC: - if h != nil { - bs.processHead(h) - } - case <-ctx.Done(): - return + bs.threadCtrl.Go(func(ctx context.Context) { + for { + select { + case h := <-bs.headC: + if h != nil { + bs.processHead(h) } + case <-ctx.Done(): + return } - }(bs.ctx) - } - - // clean up block maps - { - go func(ctx context.Context) { - ticker := time.NewTicker(cleanUpInterval) - for { - select { - case <-ticker.C: - bs.cleanup() - case <-ctx.Done(): - ticker.Stop() - return - } + } + }) + // cleanup old blocks + bs.threadCtrl.Go(func(ctx context.Context) { + ticker := time.NewTicker(cleanUpInterval) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + bs.cleanup() + case <-ctx.Done(): + return } - }(bs.ctx) - } + } + }) return nil }) } func (bs *BlockSubscriber) Close() error { - bs.lggr.Info("stop block subscriber") - return bs.sync.StopOnce("BlockSubscriber", func() error { - bs.mu.Lock() - defer bs.mu.Unlock() - - bs.cancel() + return bs.StopOnce(BlockSubscriberServiceName, func() error { + bs.lggr.Info("stop block subscriber") + bs.threadCtrl.Close() bs.unsubscribe() return nil }) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go index 19dfa7d9281..23fcf3f6695 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go @@ -158,7 +158,7 @@ func TestBlockSubscriber_InitializeBlocks(t *testing.T) { bs := NewBlockSubscriber(hb, lp, lggr) bs.blockHistorySize = historySize bs.blockSize = blockSize - err := bs.initializeBlocks(tc.Blocks) + err := bs.initializeBlocks(testutils.Context(t), tc.Blocks) if tc.Error != nil { assert.Equal(t, tc.Error.Error(), err.Error()) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger.go index ea0c4a31f37..79273479596 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger.go @@ -16,7 +16,7 @@ type triggerWrapper = automation_utils_2_1.KeeperRegistryBase21LogTrigger var ErrABINotParsable = fmt.Errorf("error parsing abi") -// according to the upkeep type of the given id. +// PackTrigger packs the trigger data according to the upkeep type of the given id. it will remove the first 4 bytes of function selector. func PackTrigger(id *big.Int, trig triggerWrapper) ([]byte, error) { var trigger []byte var err error diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/utils.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/utils.go index 25003055a3b..6a31b938fc6 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/core/utils.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/utils.go @@ -19,14 +19,14 @@ func GetTxBlock(ctx context.Context, client client.Client, txHash common.Hash) ( if strings.Contains(err.Error(), "not yet been implemented") { // workaround for simulated chains // Exploratory: fix this properly (e.g. in the simulated backend) - receipt, err1 := client.TransactionReceipt(ctx, txHash) + r, err1 := client.TransactionReceipt(ctx, txHash) if err1 != nil { return nil, common.Hash{}, err1 } - if receipt.Status != 1 { + if r.Status != 1 { return nil, common.Hash{}, nil } - return receipt.BlockNumber, receipt.BlockHash, nil + return r.BlockNumber, r.BlockHash, nil } return nil, common.Hash{}, err } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder.go index f68289044ec..239de099c01 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder.go @@ -87,7 +87,7 @@ func (e reportEncoder) Encode(results ...ocr2keepers.CheckResult) ([]byte, error return e.packer.PackReport(report) } -// Extract the plugin will call this function to accept/transmit reports +// Extract extracts a slice of reported upkeeps (upkeep id, trigger, and work id) from raw bytes. the plugin will call this function to accept/transmit reports. func (e reportEncoder) Extract(raw []byte) ([]ocr2keepers.ReportedUpkeep, error) { report, err := e.packer.UnpackReport(raw) if err != nil { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go index 9774ef4d968..1f36cadb4d7 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go @@ -42,7 +42,7 @@ const ( MercuryUnmarshalError PipelineExecutionState = 6 InvalidMercuryRequest PipelineExecutionState = 7 InvalidMercuryResponse PipelineExecutionState = 8 // this will only happen if Mercury server sends bad responses - CheckBlockTooNew PipelineExecutionState = 9 + UpkeepNotAuthorized PipelineExecutionState = 9 ) type UpkeepInfo = iregistry21.KeeperRegistryBase21UpkeepInfo @@ -51,8 +51,9 @@ type Packer interface { UnpackCheckResult(payload ocr2keepers.UpkeepPayload, raw string) (ocr2keepers.CheckResult, error) UnpackCheckCallbackResult(callbackResp []byte) (PipelineExecutionState, bool, []byte, uint8, *big.Int, error) UnpackPerformResult(raw string) (PipelineExecutionState, bool, error) - UnpackUpkeepInfo(id *big.Int, raw string) (UpkeepInfo, error) UnpackLogTriggerConfig(raw []byte) (automation_utils_2_1.LogTriggerConfig, error) PackReport(report automation_utils_2_1.KeeperRegistryBase21Report) ([]byte, error) UnpackReport(raw []byte) (automation_utils_2_1.KeeperRegistryBase21Report, error) + PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) + UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go index c710b31291f..824a98172bd 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go @@ -66,6 +66,21 @@ func (p *abiPacker) UnpackCheckResult(payload ocr2keepers.UpkeepPayload, raw str return result, nil } +func (p *abiPacker) PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) { + return p.abi.Pack("getUpkeepPrivilegeConfig", upkeepId) +} + +func (p *abiPacker) UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) { + out, err := p.abi.Methods["getUpkeepPrivilegeConfig"].Outputs.UnpackValues(resp) + if err != nil { + return nil, fmt.Errorf("%w: unpack getUpkeepPrivilegeConfig return", err) + } + + bts := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return bts, nil +} + func (p *abiPacker) UnpackCheckCallbackResult(callbackResp []byte) (PipelineExecutionState, bool, []byte, uint8, *big.Int, error) { out, err := p.abi.Methods["checkCallback"].Outputs.UnpackValues(callbackResp) if err != nil { @@ -94,22 +109,6 @@ func (p *abiPacker) UnpackPerformResult(raw string) (PipelineExecutionState, boo return NoPipelineError, *abi.ConvertType(out[0], new(bool)).(*bool), nil } -func (p *abiPacker) UnpackUpkeepInfo(id *big.Int, raw string) (UpkeepInfo, error) { - b, err := hexutil.Decode(raw) - if err != nil { - return UpkeepInfo{}, err - } - - out, err := p.abi.Methods["getUpkeep"].Outputs.UnpackValues(b) - if err != nil { - return UpkeepInfo{}, fmt.Errorf("%w: unpack getUpkeep return: %s", err, raw) - } - - info := *abi.ConvertType(out[0], new(UpkeepInfo)).(*UpkeepInfo) - - return info, nil -} - // UnpackLogTriggerConfig unpacks the log trigger config from the given raw data func (p *abiPacker) UnpackLogTriggerConfig(raw []byte) (automation_utils_2_1.LogTriggerConfig, error) { var cfg automation_utils_2_1.LogTriggerConfig diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go index ccc84765baa..b333a695bf8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go @@ -1,6 +1,7 @@ package encoding import ( + "encoding/json" "fmt" "math/big" "strings" @@ -355,6 +356,97 @@ func TestPacker_PackReport_UnpackReport(t *testing.T) { assert.Equal(t, hexutil.Encode(res), expected) } +func TestPacker_PackGetUpkeepPrivilegeConfig(t *testing.T) { + tests := []struct { + name string + upkeepId *big.Int + raw []byte + errored bool + }{ + { + name: "happy path", + upkeepId: func() *big.Int { + id, _ := new(big.Int).SetString("52236098515066839510538748191966098678939830769967377496848891145101407612976", 10) + + return id + }(), + raw: func() []byte { + b, _ := hexutil.Decode("0x19d97a94737c9583000000000000000000000001ea8ed6d0617dd5b3b87374020efaf030") + + return b + }(), + errored: false, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + packer, err := newPacker() + require.NoError(t, err, "valid packer required for test") + + b, err := packer.PackGetUpkeepPrivilegeConfig(test.upkeepId) + + if !test.errored { + require.NoError(t, err, "no error expected from packing") + + assert.Equal(t, test.raw, b, "raw bytes for output should match expected") + } else { + assert.NotNil(t, err, "error expected from packing function") + } + }) + } +} + +func TestPacker_UnpackGetUpkeepPrivilegeConfig(t *testing.T) { + tests := []struct { + name string + raw []byte + errored bool + }{ + { + name: "happy path", + raw: func() []byte { + b, _ := hexutil.Decode("0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000177b226d657263757279456e61626c6564223a747275657d000000000000000000") + + return b + }(), + errored: false, + }, + { + name: "error empty config", + raw: func() []byte { + b, _ := hexutil.Decode("0x") + + return b + }(), + errored: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + packer, err := newPacker() + require.NoError(t, err, "valid packer required for test") + + b, err := packer.UnpackGetUpkeepPrivilegeConfig(test.raw) + + if !test.errored { + require.NoError(t, err, "should unpack bytes from abi encoded value") + + // the actual struct to unmarshal into is not available to this + // package so basic json encoding is the limit of the following test + var data map[string]interface{} + err = json.Unmarshal(b, &data) + + assert.NoError(t, err, "packed data should unmarshal using json encoding") + assert.Equal(t, []byte(`{"mercuryEnabled":true}`), b) + } else { + assert.NotNil(t, err, "error expected from unpack function") + } + }) + } +} + func newPacker() (*abiPacker, error) { keepersABI, err := abi.JSON(strings.NewReader(iregistry21.IKeeperRegistryMasterABI)) if err != nil { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time.go index 3af93f873c1..9fc35dd84be 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time.go @@ -11,7 +11,7 @@ import ( ) var ( - defaultSampleSize = int64(200) + defaultSampleSize = int64(10000) defaultBlockTime = time.Second * 1 ) @@ -34,39 +34,28 @@ func (r *blockTimeResolver) BlockTime(ctx context.Context, blockSampleSize int64 if err != nil { return 0, fmt.Errorf("failed to get latest block from poller: %w", err) } - if latest < blockSampleSize { + if latest <= blockSampleSize { return defaultBlockTime, nil } - blockTimes, err := r.getSampleTimestamps(ctx, blockSampleSize, latest) + start, end := latest-blockSampleSize, latest + startTime, endTime, err := r.getSampleTimestamps(ctx, uint64(start), uint64(end)) if err != nil { return 0, err } - var sumDiff time.Duration - for i := range blockTimes { - if i != int(blockSampleSize-1) { - sumDiff += blockTimes[i].Sub(blockTimes[i+1]) - } - } - - return sumDiff / time.Duration(blockSampleSize-1), nil + return endTime.Sub(startTime) / time.Duration(blockSampleSize), nil } -func (r *blockTimeResolver) getSampleTimestamps(ctx context.Context, blockSampleSize, latest int64) ([]time.Time, error) { - blockSample := make([]uint64, blockSampleSize) - for i := range blockSample { - blockSample[i] = uint64(latest - blockSampleSize + int64(i)) - } - blocks, err := r.poller.GetBlocksRange(ctx, blockSample) +func (r *blockTimeResolver) getSampleTimestamps(ctx context.Context, start, end uint64) (time.Time, time.Time, error) { + blocks, err := r.poller.GetBlocksRange(ctx, []uint64{start, end}) if err != nil { - return nil, fmt.Errorf("failed to get block range from poller: %w", err) + return time.Time{}, time.Time{}, fmt.Errorf("failed to get block range from poller: %w", err) } sort.Slice(blocks, func(i, j int) bool { - return blocks[i].BlockNumber > blocks[j].BlockNumber + return blocks[i].BlockNumber < blocks[j].BlockNumber }) - blockTimes := make([]time.Time, blockSampleSize) - for i, b := range blocks { - blockTimes[i] = b.BlockTimestamp + if len(blocks) < 2 { + return time.Time{}, time.Time{}, fmt.Errorf("failed to fetch blocks %d, %d from log poller", start, end) } - return blockTimes, nil + return blocks[0].BlockTimestamp, blocks[1].BlockTimestamp, nil } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go index 55437ff6721..0ad9990e185 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go @@ -52,10 +52,8 @@ func TestBlockTimeResolver_BlockTime(t *testing.T) { 20, nil, []logpoller.LogPollerBlock{ - {BlockTimestamp: now.Add(-time.Second * (2 * 4)), BlockNumber: 1}, - {BlockTimestamp: now.Add(-time.Second * (2 * 3)), BlockNumber: 2}, - {BlockTimestamp: now.Add(-time.Second * (2 * 2)), BlockNumber: 3}, - {BlockTimestamp: now.Add(-time.Second * 2), BlockNumber: 4}, + {BlockTimestamp: now.Add(-time.Second * (2 * 4)), BlockNumber: 16}, + {BlockTimestamp: now, BlockNumber: 20}, }, nil, 2 * time.Second, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/factory.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/factory.go index 0db15da0f32..4b3fa8cb404 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/factory.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/factory.go @@ -36,6 +36,8 @@ type LogTriggersOptions struct { BlockRateLimit rate.Limit // blockLimitBurst is the burst upper limit on the range of blocks the we fetch logs for. BlockLimitBurst int + // Finality depth is the number of blocks to wait before considering a block final. + FinalityDepth int64 } func NewOptions(finalityDepth int64) LogTriggersOptions { @@ -49,8 +51,8 @@ func NewOptions(finalityDepth int64) LogTriggersOptions { func (o *LogTriggersOptions) Defaults(finalityDepth int64) { if o.LookbackBlocks == 0 { lookbackBlocks := int64(200) - if lookbackBlocks < int64(finalityDepth) { - lookbackBlocks = int64(finalityDepth) + if lookbackBlocks < finalityDepth { + lookbackBlocks = finalityDepth } o.LookbackBlocks = lookbackBlocks } @@ -63,4 +65,7 @@ func (o *LogTriggersOptions) Defaults(finalityDepth int64) { if o.BlockRateLimit == 0 { o.BlockRateLimit = rate.Every(o.ReadInterval) } + if o.FinalityDepth == 0 { + o.FinalityDepth = finalityDepth + } } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/filter.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/filter.go index db1cb43d2c3..44780cbc4b1 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/filter.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/filter.go @@ -46,6 +46,7 @@ func (f upkeepFilter) Clone() upkeepFilter { } } +// Select returns a slice of logs which match the upkeep filter. func (f upkeepFilter) Select(logs ...logpoller.Log) []logpoller.Log { var selected []logpoller.Log for _, log := range logs { @@ -56,6 +57,7 @@ func (f upkeepFilter) Select(logs ...logpoller.Log) []logpoller.Log { return selected } +// match returns a bool indicating if the log's topics data matches selector and indexed topics in upkeep filter. func (f upkeepFilter) match(log logpoller.Log) bool { filters := f.topics[1:] selector := f.selector @@ -65,7 +67,7 @@ func (f upkeepFilter) match(log logpoller.Log) bool { return true } - for i, f := range filters { + for i, filter := range filters { // bitwise AND the selector with the index to check // if the filter is needed mask := uint8(1 << uint8(i)) @@ -76,7 +78,7 @@ func (f upkeepFilter) match(log logpoller.Log) bool { // log doesn't have enough topics return false } - if !bytes.Equal(f.Bytes(), log.Topics[i+1]) { + if !bytes.Equal(filter.Bytes(), log.Topics[i+1]) { return false } } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/log_packer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/log_packer.go index 363f06ffa5d..49bc9b19d4f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/log_packer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/log_packer.go @@ -22,7 +22,7 @@ func NewLogEventsPacker(utilsABI abi.ABI) *logEventsPacker { } func (p *logEventsPacker) PackLogData(log logpoller.Log) ([]byte, error) { - topics := [][32]byte{} + var topics [][32]byte for _, topic := range log.GetTopics() { topics = append(topics, topic) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go index 6b89dfd0e72..b62fb370847 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go @@ -22,9 +22,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( + LogProviderServiceName = "LogEventProvider" + ErrHeadNotAvailable = fmt.Errorf("head not available") ErrBlockLimitExceeded = fmt.Errorf("block limit exceeded") @@ -78,9 +81,10 @@ var _ LogEventProviderTest = &logEventProvider{} // logEventProvider manages log filters for upkeeps and enables to read the log events. type logEventProvider struct { - lggr logger.Logger + utils.StartStopOnce + threadCtrl utils.ThreadControl - cancel context.CancelFunc + lggr logger.Logger poller logpoller.LogPoller @@ -99,8 +103,9 @@ type logEventProvider struct { func NewLogProvider(lggr logger.Logger, poller logpoller.LogPoller, packer LogDataPacker, filterStore UpkeepFilterStore, opts LogTriggersOptions) *logEventProvider { return &logEventProvider{ - packer: packer, + threadCtrl: utils.NewThreadControl(), lggr: lggr.Named("KeepersRegistry.LogEventProvider"), + packer: packer, buffer: newLogEventBuffer(lggr, int(opts.LookbackBlocks), maxLogsPerBlock, maxLogsPerUpkeepInBlock), poller: poller, opts: opts, @@ -109,33 +114,22 @@ func NewLogProvider(lggr logger.Logger, poller logpoller.LogPoller, packer LogDa } func (p *logEventProvider) Start(context.Context) error { - ctx, cancel := context.WithCancel(context.Background()) + return p.StartOnce(LogProviderServiceName, func() error { - p.lock.Lock() - if p.cancel != nil { - p.lock.Unlock() - cancel() // Cancel the created context - return errors.New("already started") - } - p.cancel = cancel - p.lock.Unlock() + readQ := make(chan []*big.Int, readJobQueueSize) - readQ := make(chan []*big.Int, readJobQueueSize) + p.lggr.Infow("starting log event provider", "readInterval", p.opts.ReadInterval, "readMaxBatchSize", readMaxBatchSize, "readers", readerThreads) - p.lggr.Infow("starting log event provider", "readInterval", p.opts.ReadInterval, "readMaxBatchSize", readMaxBatchSize, "readers", readerThreads) + for i := 0; i < readerThreads; i++ { + p.threadCtrl.Go(func(ctx context.Context) { + p.startReader(ctx, readQ) + }) + } - { // start readers - go func(ctx context.Context) { - for i := 0; i < readerThreads; i++ { - go p.startReader(ctx, readQ) - } - }(ctx) - } + p.threadCtrl.Go(func(ctx context.Context) { + lggr := p.lggr.With("where", "scheduler") - { // start scheduler - lggr := p.lggr.With("where", "scheduler") - go func(ctx context.Context) { - err := p.scheduleReadJobs(ctx, func(ids []*big.Int) { + p.scheduleReadJobs(ctx, func(ids []*big.Int) { select { case readQ <- ids: case <-ctx.Done(): @@ -143,31 +137,21 @@ func (p *logEventProvider) Start(context.Context) error { lggr.Warnw("readQ is full, dropping ids", "ids", ids) } }) - if err != nil { - lggr.Warnw("stopped scheduling read jobs with error", "err", err) - } - lggr.Debug("stopped scheduling read jobs") - }(ctx) - } + }) - return nil + return nil + }) } func (p *logEventProvider) Close() error { - p.lock.Lock() - defer p.lock.Unlock() - - if cancel := p.cancel; cancel != nil { - p.cancel = nil - cancel() - } else { - return errors.New("already stopped") - } - return nil + return p.StopOnce(LogProviderServiceName, func() error { + p.threadCtrl.Close() + return nil + }) } -func (p *logEventProvider) Name() string { - return p.lggr.Name() +func (p *logEventProvider) HealthReport() map[string]error { + return map[string]error{LogProviderServiceName: p.Healthy()} } func (p *logEventProvider) GetLatestPayloads(ctx context.Context) ([]ocr2keepers.UpkeepPayload, error) { @@ -233,7 +217,7 @@ func (p *logEventProvider) CurrentPartitionIdx() uint64 { } // scheduleReadJobs starts a scheduler that pushed ids to readQ for reading logs in the background. -func (p *logEventProvider) scheduleReadJobs(pctx context.Context, execute func([]*big.Int)) error { +func (p *logEventProvider) scheduleReadJobs(pctx context.Context, execute func([]*big.Int)) { ctx, cancel := context.WithCancel(pctx) defer cancel() @@ -261,7 +245,7 @@ func (p *logEventProvider) scheduleReadJobs(pctx context.Context, execute func([ partitionIdx++ atomic.StoreUint64(&p.currentPartitionIdx, partitionIdx) case <-ctx.Done(): - return ctx.Err() + return } } } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go index 52acb392e0e..ab816adb1b3 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go @@ -18,8 +18,7 @@ import ( var ( // LogRetention is the amount of time to retain logs for. LogRetention = 24 * time.Hour - // When adding a filter in log poller, backfill is done for this number of blocks - // from latest + // LogBackfillBuffer is the number of blocks from the latest block for which backfill is done when adding a filter in log poller LogBackfillBuffer = 100 ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go index 47070d71aed..db22886cbb7 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go @@ -193,7 +193,7 @@ func TestLogEventProvider_ScheduleReadJobs(t *testing.T) { reads := make(chan []*big.Int, 100) go func(ctx context.Context) { - _ = p.scheduleReadJobs(ctx, func(ids []*big.Int) { + p.scheduleReadJobs(ctx, func(ids []*big.Int) { select { case reads <- ids: default: diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go index 31de875d021..c5b06701737 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io" + "math" "math/big" "sort" "sync" @@ -25,6 +26,8 @@ import ( ) var ( + LogRecovererServiceName = "LogRecoverer" + // RecoveryInterval is the interval at which the recovery scanning processing is triggered RecoveryInterval = 5 * time.Second // RecoveryCacheTTL is the time to live for the recovery cache @@ -38,6 +41,8 @@ var ( // recoveryLogsBuffer is the number of blocks to be used as a safety buffer when reading logs recoveryLogsBuffer = int64(200) recoveryLogsBurst = int64(500) + // blockTimeUpdateCadence is the cadence at which the chain's blocktime is re-calculated + blockTimeUpdateCadence = 10 * time.Minute ) type LogRecoverer interface { @@ -54,9 +59,10 @@ type visitedRecord struct { } type logRecoverer struct { - lggr logger.Logger + utils.StartStopOnce + threadCtrl utils.ThreadControl - cancel context.CancelFunc + lggr logger.Logger lookbackBlocks *atomic.Int64 blockTime *atomic.Int64 @@ -67,30 +73,38 @@ type logRecoverer struct { pending []ocr2keepers.UpkeepPayload visited map[string]visitedRecord - filterStore UpkeepFilterStore - states core.UpkeepStateReader - packer LogDataPacker - poller logpoller.LogPoller - client client.Client + filterStore UpkeepFilterStore + states core.UpkeepStateReader + packer LogDataPacker + poller logpoller.LogPoller + client client.Client + blockTimeResolver *blockTimeResolver + + finalityDepth int64 } var _ LogRecoverer = &logRecoverer{} func NewLogRecoverer(lggr logger.Logger, poller logpoller.LogPoller, client client.Client, stateStore core.UpkeepStateReader, packer LogDataPacker, filterStore UpkeepFilterStore, opts LogTriggersOptions) *logRecoverer { rec := &logRecoverer{ - lggr: lggr.Named("LogRecoverer"), + lggr: lggr.Named(LogRecovererServiceName), + + threadCtrl: utils.NewThreadControl(), blockTime: &atomic.Int64{}, lookbackBlocks: &atomic.Int64{}, interval: opts.ReadInterval * 5, - pending: make([]ocr2keepers.UpkeepPayload, 0), - visited: make(map[string]visitedRecord), - poller: poller, - filterStore: filterStore, - states: stateStore, - packer: packer, - client: client, + pending: make([]ocr2keepers.UpkeepPayload, 0), + visited: make(map[string]visitedRecord), + poller: poller, + filterStore: filterStore, + states: stateStore, + packer: packer, + client: client, + blockTimeResolver: newBlockTimeResolver(poller), + + finalityDepth: opts.FinalityDepth, } rec.lookbackBlocks.Store(opts.LookbackBlocks) @@ -99,68 +113,75 @@ func NewLogRecoverer(lggr logger.Logger, poller logpoller.LogPoller, client clie return rec } -func (r *logRecoverer) Start(pctx context.Context) error { - ctx, cancel := context.WithCancel(context.Background()) - - r.lock.Lock() - if r.cancel != nil { - r.lock.Unlock() - cancel() // Cancel the created context - return errors.New("already started") - } - r.cancel = cancel - r.lock.Unlock() - - blockTimeResolver := newBlockTimeResolver(r.poller) - blockTime, err := blockTimeResolver.BlockTime(ctx, defaultSampleSize) - if err != nil { - // TODO: TBD exit or just log a warning - // return fmt.Errorf("failed to compute block time: %w", err) - r.lggr.Warnw("failed to compute block time", "err", err) - } - if blockTime > 0 { - r.blockTime.Store(int64(blockTime)) - } +// Start starts the log recoverer, which runs 3 threads in the background: +// 1. Recovery thread: scans for logs that were missed by the log poller +// 2. Cleanup thread: cleans up the cache of logs that were already processed +// 3. Block time thread: updates the block time of the chain +func (r *logRecoverer) Start(ctx context.Context) error { + return r.StartOnce(LogRecovererServiceName, func() error { + r.updateBlockTime(ctx) - r.lggr.Infow("starting log recoverer", "blockTime", r.blockTime.Load(), "lookbackBlocks", r.lookbackBlocks.Load(), "interval", r.interval) + r.lggr.Infow("starting log recoverer", "blockTime", r.blockTime.Load(), "lookbackBlocks", r.lookbackBlocks.Load(), "interval", r.interval) - { - go func(ctx context.Context, interval time.Duration) { - ticker := time.NewTicker(interval) - defer ticker.Stop() - gcTicker := time.NewTicker(utils.WithJitter(GCInterval)) - defer gcTicker.Stop() + r.threadCtrl.Go(func(ctx context.Context) { + recoveryTicker := time.NewTicker(r.interval) + defer recoveryTicker.Stop() for { select { - case <-ticker.C: + case <-recoveryTicker.C: if err := r.recover(ctx); err != nil { r.lggr.Warnw("failed to recover logs", "err", err) } - case <-gcTicker.C: + case <-ctx.Done(): + return + } + } + }) + + r.threadCtrl.Go(func(ctx context.Context) { + cleanupTicker := time.NewTicker(utils.WithJitter(GCInterval)) + defer cleanupTicker.Stop() + + for { + select { + case <-cleanupTicker.C: r.clean(ctx) - gcTicker.Reset(utils.WithJitter(GCInterval)) + cleanupTicker.Reset(utils.WithJitter(GCInterval)) case <-ctx.Done(): return } } - }(ctx, r.interval) - } + }) - return nil + r.threadCtrl.Go(func(ctx context.Context) { + blockTimeTicker := time.NewTicker(blockTimeUpdateCadence) + defer blockTimeTicker.Stop() + + for { + select { + case <-blockTimeTicker.C: + r.updateBlockTime(ctx) + blockTimeTicker.Reset(utils.WithJitter(blockTimeUpdateCadence)) + case <-ctx.Done(): + return + } + } + }) + + return nil + }) } func (r *logRecoverer) Close() error { - r.lock.Lock() - defer r.lock.Unlock() + return r.StopOnce(LogRecovererServiceName, func() error { + r.threadCtrl.Close() + return nil + }) +} - if cancel := r.cancel; cancel != nil { - r.cancel = nil - cancel() - } else { - return errors.New("already stopped") - } - return nil +func (r *logRecoverer) HealthReport() map[string]error { + return map[string]error{LogRecovererServiceName: r.Healthy()} } func (r *logRecoverer) GetProposalData(ctx context.Context, proposal ocr2keepers.CoordinatedBlockProposal) ([]byte, error) { @@ -292,7 +313,7 @@ func (r *logRecoverer) GetRecoveryProposals(ctx context.Context) ([]ocr2keepers. r.pending = pending - r.lggr.Debugf("found %d pending payloads", len(pending)) + r.lggr.Debugf("found %d recoverable payloads", len(results)) return results, nil } @@ -336,10 +357,10 @@ func (r *logRecoverer) recover(ctx context.Context) error { // recoverFilter recovers logs for a single upkeep filter. func (r *logRecoverer) recoverFilter(ctx context.Context, f upkeepFilter, startBlock, offsetBlock int64) error { - start := f.lastRePollBlock + start := f.lastRePollBlock + 1 // NOTE: we expect f.lastRePollBlock + 1 <= offsetBlock, as others would have been filtered out // ensure we don't recover logs from before the filter was created - // NOTE: we expect that filter with configUpdateBlock > offsetBlock were already filtered out. if configUpdateBlock := int64(f.configUpdateBlock); start < configUpdateBlock { + // NOTE: we expect that configUpdateBlock <= offsetBlock, as others would have been filtered out start = configUpdateBlock } if start < startBlock { @@ -350,6 +371,7 @@ func (r *logRecoverer) recoverFilter(ctx context.Context, f upkeepFilter, startB // If recoverer is lagging by a lot (more than 100x recoveryLogsBuffer), allow // a range of recoveryLogsBurst // Exploratory: Store lastRePollBlock in DB to prevent bursts during restarts + // (while also taking into account exisitng pending payloads) end = start + recoveryLogsBurst } if end > offsetBlock { @@ -441,7 +463,7 @@ func (r *logRecoverer) populatePending(f upkeepFilter, filteredLogs []logpoller. } // filterFinalizedStates filters out the log upkeeps that have already been completed (performed or ineligible). -func (r *logRecoverer) filterFinalizedStates(f upkeepFilter, logs []logpoller.Log, states []ocr2keepers.UpkeepState) []logpoller.Log { +func (r *logRecoverer) filterFinalizedStates(_ upkeepFilter, logs []logpoller.Log, states []ocr2keepers.UpkeepState) []logpoller.Log { filtered := make([]logpoller.Log, 0) for i, log := range logs { @@ -460,7 +482,16 @@ func (r *logRecoverer) getRecoveryWindow(latest int64) (int64, int64) { lookbackBlocks := r.lookbackBlocks.Load() blockTime := r.blockTime.Load() blocksInDay := int64(24*time.Hour) / blockTime - return latest - blocksInDay, latest - lookbackBlocks + start := latest - blocksInDay + // Exploratory: Instead of subtracting finality depth to account for finalized performs + // keep two pointers of lastRePollBlock for soft and hard finalization, i.e. manage + // unfinalized perform logs better + end := latest - lookbackBlocks - r.finalityDepth + if start > end { + // In this case, allow starting from more than a day behind + start = end + } + return start, end } // getFilterBatch returns a batch of filters that are ready to be recovered. @@ -468,7 +499,7 @@ func (r *logRecoverer) getFilterBatch(offsetBlock int64) []upkeepFilter { filters := r.filterStore.GetFilters(func(f upkeepFilter) bool { // ensure we work only on filters that are ready to be recovered // no need to recover in case f.configUpdateBlock is after offsetBlock - return f.lastRePollBlock <= offsetBlock && int64(f.configUpdateBlock) <= offsetBlock + return f.lastRePollBlock < offsetBlock && int64(f.configUpdateBlock) <= offsetBlock }) sort.Slice(filters, func(i, j int) bool { @@ -650,3 +681,21 @@ func (r *logRecoverer) sortPending(latestBlock uint64) { return shuffledIDs[r.pending[i].WorkID] < shuffledIDs[r.pending[j].WorkID] }) } + +func (r *logRecoverer) updateBlockTime(ctx context.Context) { + blockTime, err := r.blockTimeResolver.BlockTime(ctx, defaultSampleSize) + if err != nil { + r.lggr.Warnw("failed to compute block time", "err", err) + return + } + if blockTime > 0 { + currentBlockTime := r.blockTime.Load() + newBlockTime := int64(blockTime) + if currentBlockTime > 0 && (int64(math.Abs(float64(currentBlockTime-newBlockTime)))*100/currentBlockTime) > 20 { + r.lggr.Warnf("updating blocktime from %d to %d, this change is larger than 20%", currentBlockTime, newBlockTime) + } else { + r.lggr.Debugf("updating blocktime from %d to %d", currentBlockTime, newBlockTime) + } + r.blockTime.Store(newBlockTime) + } +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go index 2654f8f3690..59c4244304a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go @@ -352,7 +352,7 @@ func TestLogRecoverer_Recover(t *testing.T) { nil, nil, []string{"c207451fa897f9bb13b09d54d8655edf0644e027c53521b4a92eafbb64ba4d14"}, - []int64{200, 0, 450}, + []int64{201, 0, 450}, }, { "lastRePollBlock updated with burst when lagging behind", @@ -366,7 +366,7 @@ func TestLogRecoverer_Recover(t *testing.T) { topics: []common.Hash{ common.HexToHash("0x1"), }, - lastRePollBlock: 100, // Should be updated with burst + lastRePollBlock: 99, // Should be updated with burst }, }, []ocr2keepers.UpkeepState{ocr2keepers.UnknownState}, @@ -778,7 +778,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { }, logPoller: &mockLogPoller{ LatestBlockFn: func(qopts ...pg.QOpt) (int64, error) { - return 100, nil + return 300, nil }, }, stateReader: &mockStateReader{ @@ -813,7 +813,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { }, logPoller: &mockLogPoller{ LatestBlockFn: func(qopts ...pg.QOpt) (int64, error) { - return 100, nil + return 300, nil }, }, client: &mockClient{ @@ -853,7 +853,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { }, logPoller: &mockLogPoller{ LatestBlockFn: func(qopts ...pg.QOpt) (int64, error) { - return 100, nil + return 300, nil }, }, client: &mockClient{ @@ -885,7 +885,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { }, logPoller: &mockLogPoller{ LatestBlockFn: func(qopts ...pg.QOpt) (int64, error) { - return 100, nil + return 300, nil }, LogsWithSigsFn: func(start, end int64, eventSigs []common.Hash, address common.Address, qopts ...pg.QOpt) ([]logpoller.Log, error) { return nil, errors.New("logs with sigs boom") @@ -920,7 +920,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { }, logPoller: &mockLogPoller{ LatestBlockFn: func(qopts ...pg.QOpt) (int64, error) { - return 100, nil + return 300, nil }, LogsWithSigsFn: func(start, end int64, eventSigs []common.Hash, address common.Address, qopts ...pg.QOpt) ([]logpoller.Log, error) { return []logpoller.Log{ @@ -968,7 +968,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { }, logPoller: &mockLogPoller{ LatestBlockFn: func(qopts ...pg.QOpt) (int64, error) { - return 100, nil + return 300, nil }, LogsWithSigsFn: func(start, end int64, eventSigs []common.Hash, address common.Address, qopts ...pg.QOpt) ([]logpoller.Log, error) { return []logpoller.Log{ @@ -1019,7 +1019,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { }, logPoller: &mockLogPoller{ LatestBlockFn: func(qopts ...pg.QOpt) (int64, error) { - return 100, nil + return 300, nil }, LogsWithSigsFn: func(start, end int64, eventSigs []common.Hash, address common.Address, qopts ...pg.QOpt) ([]logpoller.Log, error) { return []logpoller.Log{ diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder.go b/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder.go index 9351aa71d65..b14e687b5d1 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder.go @@ -33,7 +33,7 @@ func (b *payloadBuilder) BuildPayloads(ctx context.Context, proposals ...ocr2kee var payload ocr2keepers.UpkeepPayload if b.upkeepList.IsActive(proposal.UpkeepID.BigInt()) { b.lggr.Debugf("building payload for coordinated block proposal %+v", proposal) - checkData := []byte{} + var checkData []byte var err error switch core.GetUpkeepType(proposal.UpkeepID) { case ocr2keepers.LogTrigger: diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go index 6c0ef78bbc4..e75084ff968 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go @@ -184,7 +184,6 @@ func TestNewPayloadBuilder(t *testing.T) { BlockNumber: 1, BlockHash: [32]byte{1}, }, - CheckData: make([]byte, 0), }, }, }, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go index ee0dfb7b252..a4684e67078 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go @@ -41,6 +41,8 @@ const ( ) var ( + RegistryServiceName = "AutomationRegistry" + ErrLogReadFailure = fmt.Errorf("failure reading logs") ErrHeadNotAvailable = fmt.Errorf("head not available") ErrInitializationFailure = fmt.Errorf("failed to initialize registry") @@ -83,6 +85,8 @@ func NewEvmRegistry( finalityDepth uint32, ) *EvmRegistry { return &EvmRegistry{ + ctx: context.Background(), + threadCtrl: utils.NewThreadControl(), lggr: lggr.Named("EvmRegistry"), poller: client.LogPoller(), addr: addr, @@ -124,7 +128,8 @@ type MercuryConfig struct { } type EvmRegistry struct { - sync utils.StartStopOnce + utils.StartStopOnce + threadCtrl utils.ThreadControl lggr logger.Logger poller logpoller.LogPoller addr common.Address @@ -134,13 +139,11 @@ type EvmRegistry struct { abi abi.ABI packer encoding.Packer chLog chan logpoller.Log - reInit *time.Timer mu sync.RWMutex logProcessed map[string]bool active ActiveUpkeepList lastPollBlock int64 ctx context.Context - cancel context.CancelFunc headFunc func(ocr2keepers.BlockKey) runState int runError error @@ -156,109 +159,82 @@ func (r *EvmRegistry) Name() string { } func (r *EvmRegistry) Start(ctx context.Context) error { - return r.sync.StartOnce("AutomationRegistry", func() error { - r.mu.Lock() - defer r.mu.Unlock() - r.ctx, r.cancel = context.WithCancel(context.Background()) - r.reInit = time.NewTimer(refreshInterval) - + return r.StartOnce(RegistryServiceName, func() error { if err := r.registerEvents(r.chainID, r.addr); err != nil { return fmt.Errorf("logPoller error while registering automation events: %w", err) } - // refresh the active upkeep keys; if the reInit timer returns, do it again - { - go func(cx context.Context, tmr *time.Timer, lggr logger.Logger, f func() error) { - err := f() - if err != nil { - lggr.Errorf("failed to initialize upkeeps", err) - } + r.threadCtrl.Go(func(ctx context.Context) { + lggr := r.lggr.With("where", "upkeeps_referesh") + err := r.refreshActiveUpkeeps() + if err != nil { + lggr.Errorf("failed to initialize upkeeps", err) + } + + ticker := time.NewTicker(refreshInterval) + defer ticker.Stop() - for { - select { - case <-tmr.C: - err = f() - if err != nil { - lggr.Errorf("failed to re-initialize upkeeps", err) - } - tmr.Reset(refreshInterval) - case <-cx.Done(): - return + for { + select { + case <-ticker.C: + err = r.refreshActiveUpkeeps() + if err != nil { + lggr.Errorf("failed to refresh upkeeps", err) } + case <-ctx.Done(): + return } - }(r.ctx, r.reInit, r.lggr, r.refreshActiveUpkeeps) - } - - // start polling logs on an interval - { - go func(cx context.Context, lggr logger.Logger, f func() error) { - ticker := time.NewTicker(time.Second) - for { - select { - case <-ticker.C: - err := f() - if err != nil { - lggr.Errorf("failed to poll logs for upkeeps", err) - } - case <-cx.Done(): - ticker.Stop() - return + } + }) + + r.threadCtrl.Go(func(ctx context.Context) { + lggr := r.lggr.With("where", "logs_polling") + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + err := r.pollUpkeepStateLogs() + if err != nil { + lggr.Errorf("failed to poll logs for upkeeps", err) } + case <-ctx.Done(): + return } - }(r.ctx, r.lggr, r.pollUpkeepStateLogs) - } - - // run process to process logs from log channel - { - go func(cx context.Context, ch chan logpoller.Log, lggr logger.Logger, f func(logpoller.Log) error) { - for { - select { - case l := <-ch: - err := f(l) - if err != nil { - lggr.Errorf("failed to process log for upkeep", err) - } - case <-cx.Done(): - return + } + }) + + r.threadCtrl.Go(func(ctx context.Context) { + lggr := r.lggr.With("where", "logs_processing") + ch := r.chLog + + for { + select { + case l := <-ch: + err := r.processUpkeepStateLog(l) + if err != nil { + lggr.Errorf("failed to process log for upkeep", err) } + case <-ctx.Done(): + return } - }(r.ctx, r.chLog, r.lggr, r.processUpkeepStateLog) - } + } + }) - r.runState = 1 return nil }) } func (r *EvmRegistry) Close() error { - return r.sync.StopOnce("AutomationRegistry", func() error { - r.mu.Lock() - defer r.mu.Unlock() - r.cancel() - r.runState = 0 - r.runError = nil + return r.StopOnce(RegistryServiceName, func() error { + r.threadCtrl.Close() return nil }) } -func (r *EvmRegistry) Ready() error { - r.mu.RLock() - defer r.mu.RUnlock() - - if r.runState == 1 { - return nil - } - return r.sync.Ready() -} - func (r *EvmRegistry) HealthReport() map[string]error { - r.mu.RLock() - defer r.mu.RUnlock() - - if r.runState > 1 { - r.sync.SvcErrBuffer.Append(fmt.Errorf("failed run state: %w", r.runError)) - } - return map[string]error{r.Name(): r.sync.Healthy()} + return map[string]error{RegistryServiceName: r.Healthy()} } func (r *EvmRegistry) refreshActiveUpkeeps() error { @@ -484,9 +460,9 @@ func RegistryUpkeepFilterName(addr common.Address) string { return logpoller.FilterName("KeeperRegistry Events", addr.String()) } -func (r *EvmRegistry) registerEvents(chainID uint64, addr common.Address) error { - // Add log filters for the log poller so that it can poll and find the logs that - // we need +// registerEvents registers upkeep state events from keeper registry on log poller +func (r *EvmRegistry) registerEvents(_ uint64, addr common.Address) error { + // Add log filters for the log poller so that it can poll and find the logs that we need return r.poller.RegisterFilter(logpoller.Filter{ Name: RegistryUpkeepFilterName(addr), EventSigs: upkeepStateEvents, @@ -494,7 +470,7 @@ func (r *EvmRegistry) registerEvents(chainID uint64, addr common.Address) error }) } -// Removes an upkeepID from active list and unregisters the log filter for log upkeeps +// removeFromActive removes an upkeepID from active list and unregisters the log filter for log upkeeps func (r *EvmRegistry) removeFromActive(id *big.Int) { r.active.Remove(id) @@ -565,6 +541,7 @@ func (r *EvmRegistry) getLatestIDsFromContract(ctx context.Context) ([]*big.Int, return ids, nil } +// updateTriggerConfig updates the trigger config for an upkeep. it will re-register a filter for this upkeep. func (r *EvmRegistry) updateTriggerConfig(id *big.Int, cfg []byte, logBlock uint64) error { uid := &ocr2keepers.UpkeepIdentifier{} uid.FromBigInt(id) @@ -596,7 +573,7 @@ func (r *EvmRegistry) updateTriggerConfig(id *big.Int, cfg []byte, logBlock uint return nil } -// updateTriggerConfig gets invoked upon changes in the trigger config of an upkeep. +// fetchTriggerConfig fetches trigger config in raw bytes for an upkeep. func (r *EvmRegistry) fetchTriggerConfig(id *big.Int) ([]byte, error) { opts := r.buildCallOpts(r.ctx, nil) cfg, err := r.registry.GetUpkeepTriggerConfig(opts, id) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go index cd77d573f09..b9b04fabe43 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go @@ -98,14 +98,7 @@ func (r *EvmRegistry) getBlockHash(blockNumber *big.Int) (common.Hash, error) { } // verifyCheckBlock checks that the check block and hash are valid, returns the pipeline execution state and retryable -func (r *EvmRegistry) verifyCheckBlock(ctx context.Context, checkBlock, upkeepId *big.Int, checkHash common.Hash) (state encoding.PipelineExecutionState, retryable bool) { - // verify check block number is not in future (can happen when this node is lagging the other members in DON) - latestBlock := r.bs.latestBlock.Load() - if checkBlock.Int64() > int64(latestBlock.Number) { - r.lggr.Warnf("latest block is %d, check block number %s is in future for upkeepId %s", r.bs.latestBlock.Load(), checkBlock, upkeepId) - return encoding.CheckBlockTooNew, true // retryable since the block can be found in future - } - +func (r *EvmRegistry) verifyCheckBlock(_ context.Context, checkBlock, upkeepId *big.Int, checkHash common.Hash) (state encoding.PipelineExecutionState, retryable bool) { var h string var ok bool // verify check block number and hash are valid diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go index ae20ac14df6..152c912f70f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go @@ -85,20 +85,6 @@ func TestRegistry_VerifyCheckBlock(t *testing.T) { retryable bool makeEthCall bool }{ - { - name: "check block number too new", - checkBlock: big.NewInt(500), - latestBlock: ocr2keepers.BlockKey{Number: 400}, - upkeepId: big.NewInt(12345), - checkHash: common.HexToHash("0x5bff03de234fe771ac0d685f9ee0fb0b757ea02ec9e6f10e8e2ee806db1b6b83"), - payload: ocr2keepers.UpkeepPayload{ - UpkeepID: upkeepId, - Trigger: ocr2keepers.NewTrigger(500, common.HexToHash("0x5bff03de234fe771ac0d685f9ee0fb0b757ea02ec9e6f10e8e2ee806db1b6b83")), - WorkID: "work", - }, - state: encoding.CheckBlockTooNew, - retryable: true, - }, { name: "for an invalid check block number, if hash does not match the check hash, return CheckBlockInvalid", checkBlock: big.NewInt(500), @@ -389,7 +375,7 @@ func TestRegistry_CheckUpkeeps(t *testing.T) { BlockNumber: 550, } - trigger0 := ocr2keepers.NewTrigger(590, common.HexToHash("0x1c77db0abe32327cf3ea9de2aadf79876f9e6b6dfcee9d4719a8a2dc8ca289d0")) + trigger0 := ocr2keepers.NewTrigger(575, common.HexToHash("0x1c77db0abe32327cf3ea9de2aadf79876f9e6b6dfcee9d4719a8a2dc8ca289d0")) trigger1 := ocr2keepers.NewLogTrigger(560, common.HexToHash("0x9840e5b709bfccf6a1b44f34c884bc39403f57923f3f5ead6243cc090546b857"), extension1) trigger2 := ocr2keepers.NewLogTrigger(570, common.HexToHash("0x1222d75217e2dd461cc77e4091c37abe76277430d97f1963a822b4e94ebb83fc"), extension2) @@ -429,12 +415,13 @@ func TestRegistry_CheckUpkeeps(t *testing.T) { 550: "0x9840e5b709bfccf6a1b44f34c884bc39403f57923f3f5ead6243cc090546b857", 560: "0x9840e5b709bfccf6a1b44f34c884bc39403f57923f3f5ead6243cc090546b857", 570: "0x1222d75217e2dd461cc77e4091c37abe76277430d97f1963a822b4e94ebb83fc", + 575: "0x9840e5b709bfccf6a1b44f34c884bc39403f57923f3f5ead6243cc090546b857", }, latestBlock: ocr2keepers.BlockKey{Number: 580}, results: []ocr2keepers.CheckResult{ { - PipelineExecutionState: uint8(encoding.CheckBlockTooNew), - Retryable: true, + PipelineExecutionState: uint8(encoding.CheckBlockInvalid), + Retryable: false, Eligible: false, IneligibilityReason: 0, UpkeepID: uid0, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/services.go b/core/services/ocr2/plugins/ocr2keeper/evm21/services.go index 1c666dc7cac..91479b5e619 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/services.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/services.go @@ -28,7 +28,7 @@ import ( type AutomationServices interface { Registry() *EvmRegistry Encoder() ocr2keepers.Encoder - TransmitEventProvider() *transmit.TransmitEventProvider + TransmitEventProvider() *transmit.EventProvider BlockSubscriber() *BlockSubscriber PayloadBuilder() ocr2keepers.PayloadBuilder UpkeepStateStore() upkeepstate.UpkeepStateStore @@ -97,7 +97,7 @@ func New(addr common.Address, client evm.Chain, mc *models.MercuryCredentials, k type automationServices struct { reg *EvmRegistry encoder ocr2keepers.Encoder - transmitEventProvider *transmit.TransmitEventProvider + transmitEventProvider *transmit.EventProvider blockSub *BlockSubscriber payloadBuilder ocr2keepers.PayloadBuilder upkeepState upkeepstate.UpkeepStateStore @@ -117,7 +117,7 @@ func (f *automationServices) Encoder() ocr2keepers.Encoder { return f.encoder } -func (f *automationServices) TransmitEventProvider() *transmit.TransmitEventProvider { +func (f *automationServices) TransmitEventProvider() *transmit.EventProvider { return f.transmitEventProvider } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go index 80ad68cdca1..1651e2251da 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go @@ -66,10 +66,10 @@ type MercuryV03Response struct { } type MercuryV03Report struct { - FeedID string `json:"feedID"` // feed id in hex - ValidFromTimestamp string `json:"validFromTimestamp"` - ObservationsTimestamp string `json:"observationsTimestamp"` - FullReport string `json:"fullReport"` // the actual mercury report of this feed, can be sent to verifier + FeedID []byte `json:"feedID"` // feed id in hex + ValidFromTimestamp uint32 `json:"validFromTimestamp"` + ObservationsTimestamp uint32 `json:"observationsTimestamp"` + FullReport []byte `json:"fullReport"` // the actual mercury report of this feed, can be sent to verifier } type MercuryData struct { @@ -108,6 +108,10 @@ func (r *EvmRegistry) streamsLookup(ctx context.Context, checkResults []ocr2keep // user contract did not revert with StreamsLookup error continue } + if r.mercury.cred == nil { + lggr.Errorf("at block %d upkeep %s tries to access mercury server but mercury credential is not configured", block, upkeepId) + continue + } if len(l.feeds) == 0 { checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonInvalidRevertDataInput) @@ -163,7 +167,7 @@ func (r *EvmRegistry) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup * state, reason, values, retryable, err := r.doMercuryRequest(ctx, lookup, lggr) if err != nil { - lggr.Errorf("upkeep %s retryable %v doMercuryRequest: %v", lookup.upkeepId, retryable, err) + lggr.Errorf("upkeep %s retryable %v doMercuryRequest: %s", lookup.upkeepId, retryable, err.Error()) checkResults[i].Retryable = retryable checkResults[i].PipelineExecutionState = uint8(state) checkResults[i].IneligibilityReason = uint8(reason) @@ -176,7 +180,7 @@ func (r *EvmRegistry) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup * state, retryable, mercuryBytes, err := r.checkCallback(ctx, values, lookup) if err != nil { - lggr.Errorf("at block %d upkeep %s checkCallback err: %v", lookup.block, lookup.upkeepId, err) + lggr.Errorf("at block %d upkeep %s checkCallback err: %s", lookup.block, lookup.upkeepId, err.Error()) checkResults[i].Retryable = retryable checkResults[i].PipelineExecutionState = uint8(state) return @@ -185,7 +189,7 @@ func (r *EvmRegistry) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup * state, needed, performData, failureReason, _, err := r.packer.UnpackCheckCallbackResult(mercuryBytes) if err != nil { - lggr.Errorf("at block %d upkeep %s UnpackCheckCallbackResult err: %v", lookup.block, lookup.upkeepId, err) + lggr.Errorf("at block %d upkeep %s UnpackCheckCallbackResult err: %s", lookup.block, lookup.upkeepId, err.Error()) checkResults[i].PipelineExecutionState = uint8(state) return } @@ -216,22 +220,44 @@ func (r *EvmRegistry) allowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int return encoding.NoPipelineError, encoding.UpkeepFailureReasonNone, false, allowed.(bool), nil } - cfg, err := r.registry.GetUpkeepPrivilegeConfig(opts, upkeepId) + payload, err := r.packer.PackGetUpkeepPrivilegeConfig(upkeepId) + if err != nil { + // pack error, no retryable + r.lggr.Warnf("failed to pack getUpkeepPrivilegeConfig data for upkeepId %s: %s", upkeepId, err) + + return encoding.PackUnpackDecodeFailed, encoding.UpkeepFailureReasonNone, false, false, fmt.Errorf("failed to pack upkeepId: %w", err) + } + + var resultBytes hexutil.Bytes + args := map[string]interface{}{ + "to": r.addr.Hex(), + "data": hexutil.Bytes(payload), + } + + // call checkCallback function at the block which OCR3 has agreed upon + err = r.client.CallContext(opts.Context, &resultBytes, "eth_call", args, opts.BlockNumber) if err != nil { return encoding.RpcFlakyFailure, encoding.UpkeepFailureReasonNone, true, false, fmt.Errorf("failed to get upkeep privilege config: %v", err) } + + cfg, err := r.packer.UnpackGetUpkeepPrivilegeConfig(resultBytes) + if err != nil { + return encoding.PackUnpackDecodeFailed, encoding.UpkeepFailureReasonNone, false, false, fmt.Errorf("failed to get upkeep privilege config: %v", err) + } + if len(cfg) == 0 { r.mercury.allowListCache.Set(upkeepId.String(), false, cache.DefaultExpiration) return encoding.NoPipelineError, encoding.UpkeepFailureReasonMercuryAccessNotAllowed, false, false, fmt.Errorf("upkeep privilege config is empty") } - var a UpkeepPrivilegeConfig - err = json.Unmarshal(cfg, &a) - if err != nil { + var privilegeConfig UpkeepPrivilegeConfig + if err := json.Unmarshal(cfg, &privilegeConfig); err != nil { return encoding.MercuryUnmarshalError, encoding.UpkeepFailureReasonNone, false, false, fmt.Errorf("failed to unmarshal privilege config: %v", err) } - r.mercury.allowListCache.Set(upkeepId.String(), a.MercuryEnabled, cache.DefaultExpiration) - return encoding.NoPipelineError, encoding.UpkeepFailureReasonNone, false, a.MercuryEnabled, nil + + r.mercury.allowListCache.Set(upkeepId.String(), privilegeConfig.MercuryEnabled, cache.DefaultExpiration) + + return encoding.NoPipelineError, encoding.UpkeepFailureReasonNone, false, privilegeConfig.MercuryEnabled, nil } // decodeStreamsLookup decodes the revert error StreamsLookup(string feedParamKey, string[] feeds, string feedParamKey, uint256 time, byte[] extraData) @@ -318,7 +344,6 @@ func (r *EvmRegistry) doMercuryRequest(ctx context.Context, sl *StreamsLookup, l results[m.Index] = m.Bytes[0] } } - lggr.Debugf("upkeep %s retryable %t reqErr %w", sl.upkeepId.String(), retryable && !allSuccess, reqErr) // only retry when not all successful AND none are not retryable return state, encoding.UpkeepFailureReasonNone, results, retryable && !allSuccess, reqErr } @@ -329,7 +354,7 @@ func (r *EvmRegistry) singleFeedRequest(ctx context.Context, ch chan<- MercuryDa sl.feedParamKey: {sl.feeds[index]}, sl.timeParamKey: {sl.time.String()}, } - mercuryURL := r.mercury.cred.URL + mercuryURL := r.mercury.cred.LegacyURL reqUrl := fmt.Sprintf("%s%s%s", mercuryURL, mercuryPathV02, q.Encode()) lggr.Debugf("request URL for upkeep %s feed %s: %s", sl.upkeepId.String(), sl.feeds[index], reqUrl) @@ -385,6 +410,8 @@ func (r *EvmRegistry) singleFeedRequest(ctx context.Context, ch chan<- MercuryDa return fmt.Errorf("at block %s upkeep %s received status code %d for feed %s", sl.time.String(), sl.upkeepId.String(), resp.StatusCode, sl.feeds[index]) } + lggr.Debugf("at block %s upkeep %s received status code %d from mercury v0.2 with BODY=%s", sl.time.String(), sl.upkeepId.String(), resp.StatusCode, hexutil.Encode(body)) + var m MercuryV02Response err1 = json.Unmarshal(body, &m) if err1 != nil { @@ -431,13 +458,14 @@ func (r *EvmRegistry) singleFeedRequest(ctx context.Context, ch chan<- MercuryDa // multiFeedsRequest sends a Mercury v0.3 request for a multi-feed report func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryData, sl *StreamsLookup, lggr logger.Logger) { - q := url.Values{ - feedIDs: {strings.Join(sl.feeds, ",")}, - timestamp: {sl.time.String()}, - } - - reqUrl := fmt.Sprintf("%s%s%s", r.mercury.cred.URL, mercuryBatchPathV03, q.Encode()) - lggr.Debugf("request URL for upkeep %s feed %s: %s", sl.upkeepId.String(), strings.Join(sl.feeds, ","), reqUrl) + // this won't work bc q.Encode() will encode commas as '%2C' but the server is strictly expecting a comma separated list + //q := url.Values{ + // feedIDs: {strings.Join(sl.feeds, ",")}, + // timestamp: {sl.time.String()}, + //} + params := fmt.Sprintf("%s=%s&%s=%s", feedIDs, strings.Join(sl.feeds, ","), timestamp, sl.time.String()) + reqUrl := fmt.Sprintf("%s%s%s", r.mercury.cred.URL, mercuryBatchPathV03, params) + lggr.Debugf("request URL for upkeep %s userId %s: %s", sl.upkeepId.String(), r.mercury.cred.Username, reqUrl) req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) if err != nil { @@ -446,7 +474,7 @@ func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryDa } ts := time.Now().UTC().UnixMilli() - signature := r.generateHMAC(http.MethodGet, mercuryBatchPathV03+q.Encode(), []byte{}, r.mercury.cred.Username, r.mercury.cred.Password, ts) + signature := r.generateHMAC(http.MethodGet, mercuryBatchPathV03+params, []byte{}, r.mercury.cred.Username, r.mercury.cred.Password, ts) req.Header.Set(headerContentType, applicationJson) // username here is often referred to as user id req.Header.Set(headerAuthorization, r.mercury.cred.Username) @@ -465,7 +493,7 @@ func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryDa retryable = false resp, err1 := r.hc.Do(req) if err1 != nil { - lggr.Warnf("at block %s upkeep %s GET request fails from mercury v0.3: %v", sl.time.String(), sl.upkeepId.String(), err1) + lggr.Warnf("at timestamp %s upkeep %s GET request fails from mercury v0.3: %v", sl.time.String(), sl.upkeepId.String(), err1) retryable = true state = encoding.MercuryFlakyFailure return err1 @@ -484,43 +512,50 @@ func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryDa return err1 } - if resp.StatusCode == http.StatusNotFound || resp.StatusCode == http.StatusInternalServerError { - lggr.Warnf("at block %s upkeep %s received status code %d from mercury v0.3", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) + lggr.Infof("at timestamp %s upkeep %s received status code %d from mercury v0.3", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) + if resp.StatusCode == http.StatusUnauthorized { + retryable = false + state = encoding.UpkeepNotAuthorized + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by unauthorized upkeep", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) + } else if resp.StatusCode == http.StatusBadRequest { + retryable = false + state = encoding.InvalidMercuryRequest + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by invalid format of timestamp", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) + } else if resp.StatusCode == http.StatusInternalServerError { retryable = true state = encoding.MercuryFlakyFailure - return errors.New(strconv.FormatInt(int64(resp.StatusCode), 10)) + return fmt.Errorf("%d", http.StatusInternalServerError) + } else if resp.StatusCode == 420 { + // in 0.3, this will happen when missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds + retryable = false + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) } else if resp.StatusCode != http.StatusOK { retryable = false state = encoding.InvalidMercuryRequest - return fmt.Errorf("at block %s upkeep %s received status code %d from mercury v0.3", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) } + lggr.Debugf("at block %s upkeep %s received status code %d from mercury v0.3 with BODY=%s", sl.time.String(), sl.upkeepId.String(), resp.StatusCode, hexutil.Encode(body)) + var response MercuryV03Response err1 = json.Unmarshal(body, &response) if err1 != nil { - lggr.Warnf("at block %s upkeep %s failed to unmarshal body to MercuryV03Response from mercury v0.3: %v", sl.time.String(), sl.upkeepId.String(), err1) + lggr.Warnf("at timestamp %s upkeep %s failed to unmarshal body to MercuryV03Response from mercury v0.3: %v", sl.time.String(), sl.upkeepId.String(), err1) retryable = false state = encoding.MercuryUnmarshalError return err1 } + // in v0.3, if some feeds are not available, the server will only return available feeds, but we need to make sure ALL feeds are retrieved before calling user contract + // hence, retry in this case. retry will help when we send a very new timestamp and reports are not yet generated if len(response.Reports) != len(sl.feeds) { - // this should never happen. if this upkeep does not have permission for any feeds it requests, or if certain feeds are - // missing in mercury server, the mercury server v0.3 should respond with 400s, rather than returning partial results - retryable = false - state = encoding.InvalidMercuryResponse - return fmt.Errorf("at block %s upkeep %s requested %d feeds but received %d reports from mercury v0.3", sl.time.String(), sl.upkeepId.String(), len(sl.feeds), len(response.Reports)) + // TODO: AUTO-5044: calculate what reports are missing and log a warning + retryable = true + state = encoding.MercuryFlakyFailure + return fmt.Errorf("%d", http.StatusNotFound) } var reportBytes [][]byte - var b []byte for _, rsp := range response.Reports { - b, err1 = hexutil.Decode(rsp.FullReport) - if err1 != nil { - lggr.Warnf("upkeep %s block %s failed to decode fullReport %s from mercury v0.3: %v", sl.upkeepId.String(), sl.time.String(), rsp.FullReport, err1) - retryable = false - state = encoding.InvalidMercuryResponse - return err1 - } - reportBytes = append(reportBytes, b) + reportBytes = append(reportBytes, rsp.FullReport) } ch <- MercuryData{ Index: 0, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go index a860f633512..95e81b2e1c8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go @@ -12,6 +12,7 @@ import ( "testing" "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/common/hexutil" "github.com/patrickmn/go-cache" @@ -62,9 +63,10 @@ func setupEVMRegistry(t *testing.T) *EvmRegistry { chLog: make(chan logpoller.Log, 1000), mercury: &MercuryConfig{ cred: &models.MercuryCredentials{ - URL: "https://google.com", - Username: "FakeClientID", - Password: "FakeClientKey", + LegacyURL: "https://google.old.com", + URL: "https://google.com", + Username: "FakeClientID", + Password: "FakeClientKey", }, abi: streamsLookupCompatibleABI, allowListCache: cache.New(defaultAllowListExpiration, allowListCleanupInterval), @@ -183,14 +185,30 @@ func TestEvmRegistry_StreamsLookup(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := setupEVMRegistry(t) + client := new(evmClientMocks.Client) + r.client = client if !tt.cachedAdminCfg && !tt.hasError { - mockReg := mocks.NewRegistry(t) cfg := UpkeepPrivilegeConfig{MercuryEnabled: tt.hasPermission} - b, err := json.Marshal(cfg) - assert.Nil(t, err) - mockReg.On("GetUpkeepPrivilegeConfig", mock.Anything, upkeepId).Return(b, nil) - r.registry = mockReg + bCfg, err := json.Marshal(cfg) + require.Nil(t, err) + + bContractCfg, err := r.abi.Methods["getUpkeepPrivilegeConfig"].Outputs.PackValues([]interface{}{bCfg}) + require.Nil(t, err) + + payload, err := r.abi.Pack("getUpkeepPrivilegeConfig", upkeepId) + require.Nil(t, err) + + args := map[string]interface{}{ + "to": r.addr.Hex(), + "data": hexutil.Bytes(payload), + } + + client.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", args, mock.AnythingOfType("*big.Int")).Return(nil). + Run(func(args mock.Arguments) { + b := args.Get(1).(*hexutil.Bytes) + *b = bContractCfg + }).Once() } if len(tt.blobs) > 0 { @@ -226,13 +244,11 @@ func TestEvmRegistry_StreamsLookup(t *testing.T) { "to": r.addr.Hex(), "data": hexutil.Bytes(payload), } - client := new(evmClientMocks.Client) client.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", args, hexutil.EncodeUint64(uint64(blockNum))).Return(nil). Run(func(args mock.Arguments) { b := args.Get(1).(*hexutil.Bytes) *b = tt.checkCallbackResp }).Once() - r.client = client } got := r.streamsLookup(context.Background(), tt.input) @@ -336,24 +352,59 @@ func TestEvmRegistry_AllowedToUseMercury(t *testing.T) { t.Run(tt.name, func(t *testing.T) { r := setupEVMRegistry(t) + client := new(evmClientMocks.Client) + r.client = client + if tt.cached { r.mercury.allowListCache.Set(upkeepId.String(), tt.allowed, cache.DefaultExpiration) } else { if tt.err != nil { - mockReg := mocks.NewRegistry(t) - mockReg.On("GetUpkeepPrivilegeConfig", mock.Anything, upkeepId).Return(tt.config, tt.ethCallErr) - r.registry = mockReg + bContractCfg, err := r.abi.Methods["getUpkeepPrivilegeConfig"].Outputs.PackValues([]interface{}{tt.config}) + require.Nil(t, err) + + payload, err := r.abi.Pack("getUpkeepPrivilegeConfig", upkeepId) + require.Nil(t, err) + + args := map[string]interface{}{ + "to": r.addr.Hex(), + "data": hexutil.Bytes(payload), + } + + client.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", args, mock.AnythingOfType("*big.Int")). + Return(tt.ethCallErr). + Run(func(args mock.Arguments) { + b := args.Get(1).(*hexutil.Bytes) + *b = bContractCfg + }).Once() } else { - mockReg := mocks.NewRegistry(t) cfg := UpkeepPrivilegeConfig{MercuryEnabled: tt.allowed} - b, err := json.Marshal(cfg) - assert.Nil(t, err) - mockReg.On("GetUpkeepPrivilegeConfig", mock.Anything, upkeepId).Return(b, nil) - r.registry = mockReg + bCfg, err := json.Marshal(cfg) + require.Nil(t, err) + + bContractCfg, err := r.abi.Methods["getUpkeepPrivilegeConfig"].Outputs.PackValues([]interface{}{bCfg}) + require.Nil(t, err) + + payload, err := r.abi.Pack("getUpkeepPrivilegeConfig", upkeepId) + require.Nil(t, err) + + args := map[string]interface{}{ + "to": r.addr.Hex(), + "data": hexutil.Bytes(payload), + } + + client.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", args, mock.AnythingOfType("*big.Int")).Return(nil). + Run(func(args mock.Arguments) { + b := args.Get(1).(*hexutil.Bytes) + *b = bContractCfg + }).Once() } } - state, reason, retryable, allowed, err := r.allowedToUseMercury(nil, upkeepId) + opts := &bind.CallOpts{ + BlockNumber: big.NewInt(10), + } + + state, reason, retryable, allowed, err := r.allowedToUseMercury(opts, upkeepId) assert.Equal(t, tt.err, err) assert.Equal(t, tt.allowed, allowed) assert.Equal(t, tt.state, state) @@ -665,7 +716,8 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { retryNumber int retryable bool errorMessage string - response MercuryV03Response + firstResponse *MercuryV03Response + response *MercuryV03Response }{ { name: "success - mercury responds in the first try", @@ -676,53 +728,24 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { time: big.NewInt(123456), upkeepId: upkeepId, }, - response: MercuryV03Response{ + response: &MercuryV03Response{ Reports: []MercuryV03Report{ { - FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: "123456", - ObservationsTimestamp: "123456", - FullReport: "0xab2123dc00000012", + FeedID: hexutil.MustDecode("0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"), + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: hexutil.MustDecode("0xab2123dc00000012"), }, { - FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: "123458", - ObservationsTimestamp: "123458", - FullReport: "0xab2123dc00000016", + FeedID: hexutil.MustDecode("0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"), + ValidFromTimestamp: 123458, + ObservationsTimestamp: 123458, + FullReport: hexutil.MustDecode("0xab2123dc00000016"), }, }, }, statusCode: http.StatusOK, }, - { - name: "success - retry for 404", - lookup: &StreamsLookup{ - feedParamKey: feedIDs, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: timestamp, - time: big.NewInt(123456), - upkeepId: upkeepId, - }, - retryNumber: 1, - statusCode: http.StatusNotFound, - lastStatusCode: http.StatusOK, - response: MercuryV03Response{ - Reports: []MercuryV03Report{ - { - FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: "123456", - ObservationsTimestamp: "123456", - FullReport: "0xab2123dc00000012", - }, - { - FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: "123458", - ObservationsTimestamp: "123458", - FullReport: "0xab2123dc00000012", - }, - }, - }, - }, { name: "success - retry for 500", lookup: &StreamsLookup{ @@ -735,19 +758,19 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { retryNumber: 2, statusCode: http.StatusInternalServerError, lastStatusCode: http.StatusOK, - response: MercuryV03Response{ + response: &MercuryV03Response{ Reports: []MercuryV03Report{ { - FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: "123456", - ObservationsTimestamp: "123456", - FullReport: "0xab2123dc00000012", + FeedID: hexutil.MustDecode("0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"), + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: hexutil.MustDecode("0xab2123dc00000012"), }, { - FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: "123458", - ObservationsTimestamp: "123458", - FullReport: "0xab2123dc00000019", + FeedID: hexutil.MustDecode("0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"), + ValidFromTimestamp: 123458, + ObservationsTimestamp: 123458, + FullReport: hexutil.MustDecode("0xab2123dc00000019"), }, }, }, @@ -762,9 +785,9 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { upkeepId: upkeepId, }, retryNumber: totalAttempt, - statusCode: http.StatusNotFound, + statusCode: http.StatusInternalServerError, retryable: true, - errorMessage: "All attempts fail:\n#1: 404\n#2: 404\n#3: 404", + errorMessage: "All attempts fail:\n#1: 500\n#2: 500\n#3: 500", }, { name: "failure - returns retryable and then non-retryable", @@ -776,12 +799,24 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { upkeepId: upkeepId, }, retryNumber: 1, - statusCode: http.StatusNotFound, - lastStatusCode: http.StatusBadGateway, - errorMessage: "All attempts fail:\n#1: 404\n#2: at block 123456 upkeep 123456789 received status code 502 from mercury v0.3", + statusCode: http.StatusInternalServerError, + lastStatusCode: http.StatusUnauthorized, + errorMessage: "All attempts fail:\n#1: 500\n#2: at timestamp 123456 upkeep 123456789 received status code 401 from mercury v0.3, most likely this is caused by unauthorized upkeep", + }, + { + name: "failure - returns status code 420 not retryable", + lookup: &StreamsLookup{ + feedParamKey: feedIDs, + feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + timeParamKey: timestamp, + time: big.NewInt(123456), + upkeepId: upkeepId, + }, + statusCode: 420, + errorMessage: "All attempts fail:\n#1: at timestamp 123456 upkeep 123456789 received status code 420 from mercury v0.3, most likely this is caused by missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds", }, { - name: "failure - returns not retryable", + name: "failure - returns status code 502 not retryable", lookup: &StreamsLookup{ feedParamKey: feedIDs, feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, @@ -790,10 +825,10 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { upkeepId: upkeepId, }, statusCode: http.StatusBadGateway, - errorMessage: "All attempts fail:\n#1: at block 123456 upkeep 123456789 received status code 502 from mercury v0.3", + errorMessage: "All attempts fail:\n#1: at timestamp 123456 upkeep 123456789 received status code 502 from mercury v0.3", }, { - name: "failure - reports length does not match feeds length", + name: "success - retry when reports length does not match feeds length", lookup: &StreamsLookup{ feedParamKey: feedIDs, feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, @@ -801,18 +836,34 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { time: big.NewInt(123456), upkeepId: upkeepId, }, - response: MercuryV03Response{ + firstResponse: &MercuryV03Response{ Reports: []MercuryV03Report{ { - FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: "123456", - ObservationsTimestamp: "123456", - FullReport: "0xab2123dc00000012", + FeedID: hexutil.MustDecode("0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"), + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: hexutil.MustDecode("0xab2123dc00000012"), }, }, }, - statusCode: http.StatusOK, - errorMessage: "All attempts fail:\n#1: at block 123456 upkeep 123456789 requested 2 feeds but received 1 reports from mercury v0.3", + response: &MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: hexutil.MustDecode("0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"), + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: hexutil.MustDecode("0xab2123dc00000012"), + }, + { + FeedID: hexutil.MustDecode("0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"), + ValidFromTimestamp: 123458, + ObservationsTimestamp: 123458, + FullReport: hexutil.MustDecode("0xab2123dc00000019"), + }, + }, + }, + retryNumber: 1, + statusCode: http.StatusOK, }, } @@ -830,17 +881,33 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { } hc.On("Do", mock.Anything).Return(resp, nil).Once() } else if tt.retryNumber < totalAttempt { - retryResp := &http.Response{ - StatusCode: tt.statusCode, - Body: io.NopCloser(bytes.NewReader(b)), - } - hc.On("Do", mock.Anything).Return(retryResp, nil).Times(tt.retryNumber) + if tt.firstResponse != nil && tt.response != nil { + b0, err := json.Marshal(tt.firstResponse) + assert.Nil(t, err) + resp0 := &http.Response{ + StatusCode: tt.statusCode, + Body: io.NopCloser(bytes.NewReader(b0)), + } + b1, err := json.Marshal(tt.response) + assert.Nil(t, err) + resp1 := &http.Response{ + StatusCode: tt.statusCode, + Body: io.NopCloser(bytes.NewReader(b1)), + } + hc.On("Do", mock.Anything).Return(resp0, nil).Once().On("Do", mock.Anything).Return(resp1, nil).Once() + } else { + retryResp := &http.Response{ + StatusCode: tt.statusCode, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(retryResp, nil).Times(tt.retryNumber) - resp := &http.Response{ - StatusCode: tt.lastStatusCode, - Body: io.NopCloser(bytes.NewReader(b)), + resp := &http.Response{ + StatusCode: tt.lastStatusCode, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Once() } - hc.On("Do", mock.Anything).Return(resp, nil).Once() } else { resp := &http.Response{ StatusCode: tt.statusCode, @@ -862,11 +929,8 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { } else { assert.Nil(t, m.Error) var reports [][]byte - var report []byte for _, rsp := range tt.response.Reports { - report, err = hexutil.Decode(rsp.FullReport) - assert.Nil(t, err) - reports = append(reports, report) + reports = append(reports, rsp.FullReport) } assert.Equal(t, reports, m.Bytes) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go index a8c4ce93ad8..b0ae2a7bf63 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go @@ -18,11 +18,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) -var _ ocr2keepers.TransmitEventProvider = &TransmitEventProvider{} +var _ ocr2keepers.TransmitEventProvider = &EventProvider{} type logParser func(registry *iregistry21.IKeeperRegistryMaster, log logpoller.Log) (transmitEventLog, error) -type TransmitEventProvider struct { +type EventProvider struct { sync utils.StartStopOnce mu sync.RWMutex runState int @@ -40,7 +40,7 @@ type TransmitEventProvider struct { cache transmitEventCache } -func TransmitEventProviderFilterName(addr common.Address) string { +func EventProviderFilterName(addr common.Address) string { return logpoller.FilterName("KeepersRegistry TransmitEventProvider", addr) } @@ -50,7 +50,7 @@ func NewTransmitEventProvider( registryAddress common.Address, client evmclient.Client, lookbackBlocks int64, -) (*TransmitEventProvider, error) { +) (*EventProvider, error) { var err error contract, err := iregistry21.NewIKeeperRegistryMaster(registryAddress, client) @@ -58,7 +58,7 @@ func NewTransmitEventProvider( return nil, err } err = logPoller.RegisterFilter(logpoller.Filter{ - Name: TransmitEventProviderFilterName(contract.Address()), + Name: EventProviderFilterName(contract.Address()), EventSigs: []common.Hash{ // These are the events that are emitted when a node transmits a report iregistry21.IKeeperRegistryMasterUpkeepPerformed{}.Topic(), // Happy path: report performed the upkeep @@ -74,7 +74,7 @@ func NewTransmitEventProvider( return nil, err } - return &TransmitEventProvider{ + return &EventProvider{ logger: logger, logPoller: logPoller, registryAddress: registryAddress, @@ -86,11 +86,11 @@ func NewTransmitEventProvider( }, nil } -func (c *TransmitEventProvider) Name() string { +func (c *EventProvider) Name() string { return c.logger.Name() } -func (c *TransmitEventProvider) Start(ctx context.Context) error { +func (c *EventProvider) Start(_ context.Context) error { return c.sync.StartOnce("AutomationTransmitEventProvider", func() error { c.mu.Lock() defer c.mu.Unlock() @@ -100,7 +100,7 @@ func (c *TransmitEventProvider) Start(ctx context.Context) error { }) } -func (c *TransmitEventProvider) Close() error { +func (c *EventProvider) Close() error { return c.sync.StopOnce("AutomationRegistry", func() error { c.mu.Lock() defer c.mu.Unlock() @@ -111,7 +111,7 @@ func (c *TransmitEventProvider) Close() error { }) } -func (c *TransmitEventProvider) Ready() error { +func (c *EventProvider) Ready() error { c.mu.RLock() defer c.mu.RUnlock() @@ -121,7 +121,7 @@ func (c *TransmitEventProvider) Ready() error { return c.sync.Ready() } -func (c *TransmitEventProvider) HealthReport() map[string]error { +func (c *EventProvider) HealthReport() map[string]error { c.mu.RLock() defer c.mu.RUnlock() @@ -131,7 +131,7 @@ func (c *TransmitEventProvider) HealthReport() map[string]error { return map[string]error{c.Name(): c.sync.Healthy()} } -func (c *TransmitEventProvider) GetLatestEvents(ctx context.Context) ([]ocr2keepers.TransmitEvent, error) { +func (c *EventProvider) GetLatestEvents(ctx context.Context) ([]ocr2keepers.TransmitEvent, error) { end, err := c.logPoller.LatestBlock(pg.WithParentCtx(ctx)) if err != nil { return nil, fmt.Errorf("%w: failed to get latest block from log poller", err) @@ -159,8 +159,8 @@ func (c *TransmitEventProvider) GetLatestEvents(ctx context.Context) ([]ocr2keep } // processLogs will parse the unseen logs and return the corresponding transmit events. -func (c *TransmitEventProvider) processLogs(latestBlock int64, logs ...logpoller.Log) ([]ocr2keepers.TransmitEvent, error) { - vals := []ocr2keepers.TransmitEvent{} +func (c *EventProvider) processLogs(latestBlock int64, logs ...logpoller.Log) ([]ocr2keepers.TransmitEvent, error) { + var vals []ocr2keepers.TransmitEvent for _, log := range logs { k := c.logKey(log) @@ -214,7 +214,7 @@ func (c *TransmitEventProvider) processLogs(latestBlock int64, logs ...logpoller return vals, nil } -func (c *TransmitEventProvider) logKey(log logpoller.Log) string { +func (c *EventProvider) logKey(log logpoller.Log) string { logExt := ocr2keepers.LogTriggerExtension{ TxHash: log.TxHash, Index: uint32(log.LogIndex), diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider.go index 8e08008eca4..5cb60d5dc1d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider.go @@ -26,7 +26,7 @@ func NewUpkeepProvider(activeUpkeeps ActiveUpkeepList, bs *BlockSubscriber, lp l } } -func (p *upkeepProvider) GetActiveUpkeeps(ctx context.Context) ([]ocr2keepers.UpkeepPayload, error) { +func (p *upkeepProvider) GetActiveUpkeeps(_ context.Context) ([]ocr2keepers.UpkeepPayload, error) { latestBlock := p.bs.latestBlock.Load() if latestBlock == nil { return nil, fmt.Errorf("no latest block found when fetching active upkeeps") @@ -35,7 +35,7 @@ func (p *upkeepProvider) GetActiveUpkeeps(ctx context.Context) ([]ocr2keepers.Up for _, uid := range p.activeUpkeeps.View(ocr2keepers.ConditionTrigger) { payload, err := core.NewUpkeepPayload( uid, - ocr2keepers.NewTrigger(ocr2keepers.BlockNumber(latestBlock.Number), latestBlock.Hash), + ocr2keepers.NewTrigger(latestBlock.Number, latestBlock.Hash), nil, ) if err != nil { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm.go index 94a16f23dfe..5db2f8bd0f3 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm.go @@ -34,16 +34,40 @@ func NewORM(chainID *big.Int, db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) * } } -// InsertUpkeepState is idempotent and sets upkeep state values in db -func (o *orm) InsertUpkeepState(state persistedStateRecord, qopts ...pg.QOpt) error { +// BatchInsertRecords is idempotent and sets upkeep state values in db +func (o *orm) BatchInsertRecords(state []persistedStateRecord, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) - query := `INSERT INTO evm_upkeep_states (evm_chain_id, work_id, completion_state, block_number, inserted_at, upkeep_id, ineligibility_reason) - VALUES ($1::NUMERIC, $2, $3, $4, $5, $6::NUMERIC, $7) - ON CONFLICT (evm_chain_id, work_id) - DO NOTHING` + if len(state) == 0 { + return nil + } + + type row struct { + EvmChainId *utils.Big + WorkId string + CompletionState uint8 + BlockNumber int64 + InsertedAt time.Time + UpkeepId *utils.Big + IneligibilityReason uint8 + } + + var rows []row + for _, record := range state { + rows = append(rows, row{ + EvmChainId: o.chainID, + WorkId: record.WorkID, + CompletionState: record.CompletionState, + BlockNumber: record.BlockNumber, + InsertedAt: record.InsertedAt, + UpkeepId: record.UpkeepID, + IneligibilityReason: record.IneligibilityReason, + }) + } - return q.ExecQ(query, o.chainID, state.WorkID, state.CompletionState, state.BlockNumber, state.InsertedAt, state.UpkeepID, state.IneligibilityReason) + return q.ExecQNamed(`INSERT INTO evm.upkeep_states +(evm_chain_id, work_id, completion_state, block_number, inserted_at, upkeep_id, ineligibility_reason) VALUES +(:evm_chain_id, :work_id, :completion_state, :block_number, :inserted_at, :upkeep_id, :ineligibility_reason) ON CONFLICT (evm_chain_id, work_id) DO NOTHING`, rows) } // SelectStatesByWorkIDs searches the data store for stored states for the @@ -52,7 +76,7 @@ func (o *orm) SelectStatesByWorkIDs(workIDs []string, qopts ...pg.QOpt) (states q := o.q.WithOpts(qopts...) err = q.Select(&states, `SELECT upkeep_id, work_id, completion_state, block_number, ineligibility_reason, inserted_at - FROM evm_upkeep_states + FROM evm.upkeep_states WHERE work_id = ANY($1) AND evm_chain_id = $2::NUMERIC`, pq.Array(workIDs), o.chainID) if err != nil { @@ -65,7 +89,7 @@ func (o *orm) SelectStatesByWorkIDs(workIDs []string, qopts ...pg.QOpt) (states // DeleteExpired prunes stored states older than to the provided time func (o *orm) DeleteExpired(expired time.Time, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) - _, err := q.Exec(`DELETE FROM evm_upkeep_states WHERE inserted_at <= $1 AND evm_chain_id::NUMERIC = $2`, expired, o.chainID) + _, err := q.Exec(`DELETE FROM evm.upkeep_states WHERE inserted_at <= $1 AND evm_chain_id::NUMERIC = $2`, expired, o.chainID) return err } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm_test.go index c816627e92c..54ca7285dd0 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm_test.go @@ -21,16 +21,18 @@ func TestInsertSelectDelete(t *testing.T) { db := pgtest.NewSqlxDB(t) orm := NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) - inserted := persistedStateRecord{ - UpkeepID: utils.NewBig(big.NewInt(2)), - WorkID: "0x1", - CompletionState: 100, - BlockNumber: 2, - IneligibilityReason: 2, - InsertedAt: time.Now(), + inserted := []persistedStateRecord{ + { + UpkeepID: utils.NewBig(big.NewInt(2)), + WorkID: "0x1", + CompletionState: 100, + BlockNumber: 2, + IneligibilityReason: 2, + InsertedAt: time.Now(), + }, } - err := orm.InsertUpkeepState(inserted) + err := orm.BatchInsertRecords(inserted) require.NoError(t, err, "no error expected from insert") diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner.go index 11a498d63cd..9ce9a10ac73 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner.go @@ -62,7 +62,7 @@ func (s *performedEventsScanner) Start(_ context.Context) error { }) } -// implements io.Closer, does nothing upon close +// Close implements io.Closer and does nothing func (s *performedEventsScanner) Close() error { return nil } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go index 3b37b58d03d..cd123212376 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go @@ -2,7 +2,6 @@ package upkeepstate import ( "context" - "errors" "fmt" "io" "math/big" @@ -18,14 +17,18 @@ import ( ) const ( + UpkeepStateStoreServiceName = "UpkeepStateStore" // CacheExpiration is the amount of time that we keep a record in the cache. CacheExpiration = 24 * time.Hour // GCInterval is the amount of time between cache cleanups. GCInterval = 2 * time.Hour + // flushCadence is the amount of time between flushes to the DB. + flushCadence = 30 * time.Second + concurrentBatchCalls = 10 ) type ORM interface { - InsertUpkeepState(persistedStateRecord, ...pg.QOpt) error + BatchInsertRecords([]persistedStateRecord, ...pg.QOpt) error SelectStatesByWorkIDs([]string, ...pg.QOpt) ([]persistedStateRecord, error) DeleteExpired(time.Time, ...pg.QOpt) error } @@ -39,7 +42,9 @@ type UpkeepStateStore interface { } var ( - _ UpkeepStateStore = &upkeepStateStore{} + _ UpkeepStateStore = &upkeepStateStore{} + newTickerFn = time.NewTicker + batchSize = 1000 ) // upkeepStateRecord is a record that we save in a local cache. @@ -54,97 +59,115 @@ type upkeepStateRecord struct { // It stores the state of ineligible upkeeps in a local, in-memory cache. // In addition, performed events are fetched by the scanner on demand. type upkeepStateStore struct { - // dependencies + utils.StartStopOnce + threadCtrl utils.ThreadControl + orm ORM lggr logger.Logger scanner PerformedLogsScanner - // configuration retention time.Duration cleanCadence time.Duration mu sync.RWMutex cache map[string]*upkeepStateRecord - // service values - cancel context.CancelFunc + pendingRecords []persistedStateRecord + sem chan struct{} + batchSize int } // NewUpkeepStateStore creates a new state store func NewUpkeepStateStore(orm ORM, lggr logger.Logger, scanner PerformedLogsScanner) *upkeepStateStore { return &upkeepStateStore{ - orm: orm, - lggr: lggr.Named("UpkeepStateStore"), - cache: map[string]*upkeepStateRecord{}, - scanner: scanner, - retention: CacheExpiration, - cleanCadence: GCInterval, + orm: orm, + lggr: lggr.Named(UpkeepStateStoreServiceName), + cache: map[string]*upkeepStateRecord{}, + scanner: scanner, + retention: CacheExpiration, + cleanCadence: GCInterval, + threadCtrl: utils.NewThreadControl(), + pendingRecords: []persistedStateRecord{}, + sem: make(chan struct{}, concurrentBatchCalls), + batchSize: batchSize, } } // Start starts the upkeep state store. -// it does background cleanup of the cache. +// it does background cleanup of the cache every GCInterval, +// and flush records to DB every flushCadence. func (u *upkeepStateStore) Start(pctx context.Context) error { - if u.retention == 0 { - return errors.New("pruneDepth must be greater than zero") - } - - u.mu.Lock() - if u.cancel != nil { - u.mu.Unlock() - return fmt.Errorf("already started") - } - - ctx, cancel := context.WithCancel(context.Background()) - - u.cancel = cancel - u.mu.Unlock() - - if err := u.scanner.Start(ctx); err != nil { - return fmt.Errorf("failed to start scanner") - } + return u.StartOnce(UpkeepStateStoreServiceName, func() error { + if err := u.scanner.Start(pctx); err != nil { + return fmt.Errorf("failed to start scanner") + } - u.lggr.Debug("Starting upkeep state store") + u.lggr.Debug("Starting upkeep state store") - { - go func(ctx context.Context) { + u.threadCtrl.Go(func(ctx context.Context) { ticker := time.NewTicker(utils.WithJitter(u.cleanCadence)) defer ticker.Stop() + flushTicker := newTickerFn(utils.WithJitter(flushCadence)) + defer flushTicker.Stop() + for { select { case <-ticker.C: if err := u.cleanup(ctx); err != nil { u.lggr.Errorw("unable to clean old state values", "err", err) } - ticker.Reset(utils.WithJitter(u.cleanCadence)) + case <-flushTicker.C: + u.flush(ctx) + flushTicker.Reset(utils.WithJitter(flushCadence)) case <-ctx.Done(): - + u.flush(ctx) + return } } - }(ctx) - } - - return nil + }) + return nil + }) } -// Close stops the service of pruning stale data; implements io.Closer -func (u *upkeepStateStore) Close() error { +func (u *upkeepStateStore) flush(ctx context.Context) { + cloneRecords := make([]persistedStateRecord, len(u.pendingRecords)) + u.mu.Lock() - defer u.mu.Unlock() + copy(cloneRecords, u.pendingRecords) + u.pendingRecords = []persistedStateRecord{} + u.mu.Unlock() - if cancel := u.cancel; cancel != nil { - u.cancel = nil - cancel() - } else { - return fmt.Errorf("already stopped") - } - if err := u.scanner.Close(); err != nil { - return fmt.Errorf("failed to start scanner") + for i := 0; i < len(cloneRecords); i += u.batchSize { + end := i + u.batchSize + if end > len(cloneRecords) { + end = len(cloneRecords) + } + + batch := cloneRecords[i:end] + + u.sem <- struct{}{} + + go func() { + if err := u.orm.BatchInsertRecords(batch, pg.WithParentCtx(ctx)); err != nil { + u.lggr.Errorw("error inserting records", "err", err) + } + <-u.sem + }() } +} - return nil +// Close stops the service of pruning stale data; implements io.Closer +func (u *upkeepStateStore) Close() error { + return u.StopOnce(UpkeepStateStoreServiceName, func() error { + u.threadCtrl.Close() + return nil + }) +} + +func (u *upkeepStateStore) HealthReport() map[string]error { + return map[string]error{UpkeepStateStoreServiceName: u.Healthy()} } // SelectByWorkIDs returns the current state of the upkeep for the provided ids. @@ -200,13 +223,15 @@ func (u *upkeepStateStore) upsertStateRecord(ctx context.Context, workID string, u.cache[workID] = record - return u.orm.InsertUpkeepState(persistedStateRecord{ + u.pendingRecords = append(u.pendingRecords, persistedStateRecord{ UpkeepID: utils.NewBig(upkeepID), WorkID: record.workID, CompletionState: uint8(record.state), IneligibilityReason: reason, InsertedAt: record.addedAt, - }, pg.WithParentCtx(ctx)) + }) + + return nil } // fetchPerformed fetches all performed logs from the scanner to populate the cache. diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go index fd2e6464239..49851b584e8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go @@ -220,29 +220,23 @@ func TestUpkeepStateStore_SetSelectIntegration(t *testing.T) { } tests := []struct { - name string - queryIDs []string - storedValues []storedValue - expected []ocr2keepers.UpkeepState + name string + flushSize int + expectedWrites int + queryIDs []string + storedValues []storedValue + expected []ocr2keepers.UpkeepState }{ { - name: "querying non-stored workIDs on empty db returns unknown state results", - queryIDs: []string{"0x1", "0x2", "0x3", "0x4"}, - expected: []ocr2keepers.UpkeepState{ - ocr2keepers.UnknownState, - ocr2keepers.UnknownState, - ocr2keepers.UnknownState, - ocr2keepers.UnknownState, - }, - }, - { - name: "querying non-stored workIDs on db with values returns unknown state results", - queryIDs: []string{"0x1", "0x2", "0x3", "0x4"}, + name: "querying non-stored workIDs on db with values returns unknown state results", + queryIDs: []string{"0x1", "0x2", "0x3", "0x4"}, + flushSize: 10, + expectedWrites: 1, storedValues: []storedValue{ - {result: makeTestResult(1, "0x11", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(2, "0x22", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(3, "0x33", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(4, "0x44", false, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(1, "0x11", false, 1), state: ocr2keepers.Performed}, + {result: makeTestResult(2, "0x22", false, 1), state: ocr2keepers.Performed}, + {result: makeTestResult(3, "0x33", false, 1), state: ocr2keepers.Performed}, + {result: makeTestResult(4, "0x44", false, 1), state: ocr2keepers.Performed}, }, expected: []ocr2keepers.UpkeepState{ ocr2keepers.UnknownState, @@ -252,13 +246,15 @@ func TestUpkeepStateStore_SetSelectIntegration(t *testing.T) { }, }, { - name: "querying workIDs with non-stored values returns valid results", - queryIDs: []string{"0x1", "0x2", "0x3", "0x4"}, + name: "storing eligible values is a noop", + queryIDs: []string{"0x1", "0x2", "0x3", "0x4"}, + flushSize: 4, + expectedWrites: 1, storedValues: []storedValue{ - {result: makeTestResult(5, "0x1", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(6, "0x2", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(7, "0x3", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(8, "0x44", false, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(9, "0x1", false, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(10, "0x2", false, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(11, "0x3", false, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(12, "0x4", true, 1), state: ocr2keepers.Performed}, // gets inserted }, expected: []ocr2keepers.UpkeepState{ ocr2keepers.Ineligible, @@ -268,31 +264,43 @@ func TestUpkeepStateStore_SetSelectIntegration(t *testing.T) { }, }, { - name: "storing eligible values is a noop", - queryIDs: []string{"0x1", "0x2", "0x3", "0x4"}, + name: "provided state on setupkeepstate is currently ignored for eligible check results", + queryIDs: []string{"0x1", "0x2"}, + flushSize: 1, + expectedWrites: 1, storedValues: []storedValue{ - {result: makeTestResult(9, "0x1", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(10, "0x2", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(11, "0x3", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(12, "0x4", true, 1), state: ocr2keepers.Performed}, + {result: makeTestResult(13, "0x1", true, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(14, "0x2", false, 1), state: ocr2keepers.Performed}, // gets inserted }, expected: []ocr2keepers.UpkeepState{ - ocr2keepers.Ineligible, - ocr2keepers.Ineligible, - ocr2keepers.Ineligible, ocr2keepers.UnknownState, + ocr2keepers.Ineligible, }, }, { - name: "provided state on setupkeepstate is currently ignored for eligible check results", - queryIDs: []string{"0x1", "0x2"}, + name: "provided state outside the flush batch isn't registered in the db", + queryIDs: []string{"0x1", "0x2", "0x3", "0x4", "0x5", "0x6", "0x7", "0x8"}, + flushSize: 3, + expectedWrites: 2, storedValues: []storedValue{ {result: makeTestResult(13, "0x1", true, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(14, "0x2", false, 1), state: ocr2keepers.Performed}, + {result: makeTestResult(14, "0x2", false, 1), state: ocr2keepers.Performed}, // gets inserted + {result: makeTestResult(15, "0x3", true, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(16, "0x4", false, 1), state: ocr2keepers.Performed}, // gets inserted + {result: makeTestResult(17, "0x5", true, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(18, "0x6", false, 1), state: ocr2keepers.Performed}, // gets inserted + {result: makeTestResult(19, "0x7", true, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(20, "0x8", false, 1), state: ocr2keepers.Performed}, // gets inserted }, expected: []ocr2keepers.UpkeepState{ ocr2keepers.UnknownState, ocr2keepers.Ineligible, + ocr2keepers.UnknownState, + ocr2keepers.Ineligible, + ocr2keepers.UnknownState, + ocr2keepers.Ineligible, + ocr2keepers.UnknownState, + ocr2keepers.Ineligible, }, }, } @@ -301,17 +309,48 @@ func TestUpkeepStateStore_SetSelectIntegration(t *testing.T) { t.Run(test.name, func(t *testing.T) { ctx := testutils.Context(t) + tickerCh := make(chan time.Time) + + oldNewTickerFn := newTickerFn + oldFlushSize := batchSize + newTickerFn = func(d time.Duration) *time.Ticker { + t := time.NewTicker(d) + t.C = tickerCh + return t + } + batchSize = test.flushSize + defer func() { + newTickerFn = oldNewTickerFn + batchSize = oldFlushSize + }() + lggr, observedLogs := logger.TestLoggerObserved(t, zapcore.ErrorLevel) chainID := testutils.FixtureChainID db := pgtest.NewSqlxDB(t) - orm := NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) + realORM := NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) + insertFinished := make(chan struct{}, 1) + orm := &wrappedORM{ + BatchInsertRecordsFn: func(records []persistedStateRecord, opt ...pg.QOpt) error { + err := realORM.BatchInsertRecords(records, opt...) + insertFinished <- struct{}{} + return err + }, + SelectStatesByWorkIDsFn: func(strings []string, opt ...pg.QOpt) ([]persistedStateRecord, error) { + return realORM.SelectStatesByWorkIDs(strings, opt...) + }, + DeleteExpiredFn: func(t time.Time, opt ...pg.QOpt) error { + return realORM.DeleteExpired(t, opt...) + }, + } scanner := &mockScanner{} store := NewUpkeepStateStore(orm, lggr, scanner) + require.NoError(t, store.Start(ctx)) + t.Cleanup(func() { t.Log("cleaning up database") - if _, err := db.Exec(`DELETE FROM evm_upkeep_states`); err != nil { + if _, err := db.Exec(`DELETE FROM evm.upkeep_states`); err != nil { t.Logf("error in cleanup: %s", err) } }) @@ -320,6 +359,13 @@ func TestUpkeepStateStore_SetSelectIntegration(t *testing.T) { require.NoError(t, store.SetUpkeepState(context.Background(), insert.result, insert.state), "storing states should not produce an error") } + tickerCh <- time.Now() + + // if this test inserts data, wait for the insert to complete before proceeding + for i := 0; i < test.expectedWrites; i++ { + <-insertFinished + } + // empty the cache before doing selects to force a db lookup store.cache = make(map[string]*upkeepStateRecord) @@ -332,10 +378,50 @@ func TestUpkeepStateStore_SetSelectIntegration(t *testing.T) { observedLogs.TakeAll() require.Equal(t, 0, observedLogs.Len()) + + require.NoError(t, store.Close()) }) } } +func TestUpkeepStateStore_emptyDB(t *testing.T) { + t.Run("querying non-stored workIDs on empty db returns unknown state results", func(t *testing.T) { + lggr, observedLogs := logger.TestLoggerObserved(t, zapcore.ErrorLevel) + chainID := testutils.FixtureChainID + db := pgtest.NewSqlxDB(t) + realORM := NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) + insertFinished := make(chan struct{}, 1) + orm := &wrappedORM{ + BatchInsertRecordsFn: func(records []persistedStateRecord, opt ...pg.QOpt) error { + err := realORM.BatchInsertRecords(records, opt...) + insertFinished <- struct{}{} + return err + }, + SelectStatesByWorkIDsFn: func(strings []string, opt ...pg.QOpt) ([]persistedStateRecord, error) { + return realORM.SelectStatesByWorkIDs(strings, opt...) + }, + DeleteExpiredFn: func(t time.Time, opt ...pg.QOpt) error { + return realORM.DeleteExpired(t, opt...) + }, + } + scanner := &mockScanner{} + store := NewUpkeepStateStore(orm, lggr, scanner) + + states, err := store.SelectByWorkIDs(context.Background(), []string{"0x1", "0x2", "0x3", "0x4"}...) + assert.NoError(t, err) + assert.Equal(t, []ocr2keepers.UpkeepState{ + ocr2keepers.UnknownState, + ocr2keepers.UnknownState, + ocr2keepers.UnknownState, + ocr2keepers.UnknownState, + }, states) + + observedLogs.TakeAll() + + require.Equal(t, 0, observedLogs.Len()) + }) +} + func TestUpkeepStateStore_Upsert(t *testing.T) { db := pgtest.NewSqlxDB(t) ctx := testutils.Context(t) @@ -475,7 +561,7 @@ func (_m *mockORM) setErr(err error) { _m.err = err } -func (_m *mockORM) InsertUpkeepState(state persistedStateRecord, _ ...pg.QOpt) error { +func (_m *mockORM) BatchInsertRecords(state []persistedStateRecord, _ ...pg.QOpt) error { return nil } @@ -498,3 +584,21 @@ func (_m *mockORM) DeleteExpired(tm time.Time, _ ...pg.QOpt) error { return _m.err } + +type wrappedORM struct { + BatchInsertRecordsFn func([]persistedStateRecord, ...pg.QOpt) error + SelectStatesByWorkIDsFn func([]string, ...pg.QOpt) ([]persistedStateRecord, error) + DeleteExpiredFn func(time.Time, ...pg.QOpt) error +} + +func (o *wrappedORM) BatchInsertRecords(r []persistedStateRecord, q ...pg.QOpt) error { + return o.BatchInsertRecordsFn(r, q...) +} + +func (o *wrappedORM) SelectStatesByWorkIDs(ids []string, q ...pg.QOpt) ([]persistedStateRecord, error) { + return o.SelectStatesByWorkIDsFn(ids, q...) +} + +func (o *wrappedORM) DeleteExpired(t time.Time, q ...pg.QOpt) error { + return o.DeleteExpiredFn(t, q...) +} diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go index 6ce8b0aa8cf..61748e83ae8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go @@ -7,6 +7,7 @@ import ( "encoding/json" "fmt" "math/big" + "net/http" "strings" "sync" "testing" @@ -29,15 +30,18 @@ import ( "github.com/stretchr/testify/require" "github.com/umbracle/ethgo/abi" + relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" automationForwarderLogic "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_forwarder_logic" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/basic_upkeep_contract" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/dummy_protocol_wrapper" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" registrylogica21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_logic_a_wrapper_2_1" registrylogicb21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_logic_b_wrapper_2_1" registry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_triggered_streams_lookup_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_upkeep_counter_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/mock_v3_aggregator_contract" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -46,6 +50,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper" + evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) @@ -57,7 +62,7 @@ func TestFilterNamesFromSpec21(t *testing.T) { address := common.HexToAddress(hexutil.Encode(b)) spec := &job.OCR2OracleSpec{ - PluginType: job.OCR2Keeper, + PluginType: relaytypes.OCR2Keeper, ContractID: address.String(), // valid contract addr } @@ -69,7 +74,7 @@ func TestFilterNamesFromSpec21(t *testing.T) { assert.Equal(t, logpoller.FilterName("KeeperRegistry Events", address), names[1]) spec = &job.OCR2OracleSpec{ - PluginType: job.OCR2Keeper, + PluginType: relaytypes.OCR2Keeper, ContractID: "0x5431", // invalid contract addr } _, err = ocr2keeper.FilterNamesFromSpec21(spec) @@ -109,7 +114,7 @@ func TestIntegration_KeeperPluginConditionalUpkeep(t *testing.T) { require.NoError(t, err) registry := deployKeeper21Registry(t, steve, backend, linkAddr, linkFeedAddr, gasFeedAddr) - nodes := setupNodes(t, nodeKeys, registry, backend, steve) + nodes, _ := setupNodes(t, nodeKeys, registry, backend, steve) <-time.After(time.Second * 5) @@ -194,10 +199,9 @@ func TestIntegration_KeeperPluginLogUpkeep(t *testing.T) { require.NoError(t, err) linkFeedAddr, _, _, err := mock_v3_aggregator_contract.DeployMockV3AggregatorContract(steve, backend, 18, big.NewInt(2000000000000000000)) require.NoError(t, err) - registry := deployKeeper21Registry(t, steve, backend, linkAddr, linkFeedAddr, gasFeedAddr) - - nodes := setupNodes(t, nodeKeys, registry, backend, steve) + registry := deployKeeper21Registry(t, steve, backend, linkAddr, linkFeedAddr, gasFeedAddr) + nodes, _ := setupNodes(t, nodeKeys, registry, backend, steve) upkeeps := 1 _, err = linkToken.Transfer(sergey, carrol.From, big.NewInt(0).Mul(oneHunEth, big.NewInt(int64(upkeeps+1)))) @@ -253,6 +257,124 @@ func TestIntegration_KeeperPluginLogUpkeep(t *testing.T) { }) } +func TestIntegration_KeeperPluginLogUpkeep_Retry(t *testing.T) { + g := gomega.NewWithT(t) + + // setup blockchain + linkOwner := testutils.MustNewSimTransactor(t) // owns all the link + registryOwner := testutils.MustNewSimTransactor(t) // registry owner + upkeepOwner := testutils.MustNewSimTransactor(t) // upkeep owner + genesisData := core.GenesisAlloc{ + linkOwner.From: {Balance: assets.Ether(10000).ToInt()}, + registryOwner.From: {Balance: assets.Ether(10000).ToInt()}, + upkeepOwner.From: {Balance: assets.Ether(10000).ToInt()}, + } + + // Generate 5 keys for nodes (1 bootstrap + 4 ocr nodes) and fund them with ether + var nodeKeys [5]ethkey.KeyV2 + for i := int64(0); i < 5; i++ { + nodeKeys[i] = cltest.MustGenerateRandomKey(t) + genesisData[nodeKeys[i].Address] = core.GenesisAccount{Balance: assets.Ether(1000).ToInt()} + } + + backend := cltest.NewSimulatedBackend(t, genesisData, uint32(ethconfig.Defaults.Miner.GasCeil)) + stopMining := cltest.Mine(backend, 3*time.Second) // Should be greater than deltaRound since we cannot access old blocks on simulated blockchain + defer stopMining() + + // Deploy registry + linkAddr, _, linkToken, err := link_token_interface.DeployLinkToken(linkOwner, backend) + require.NoError(t, err) + + gasFeedAddr, _, _, err := mock_v3_aggregator_contract.DeployMockV3AggregatorContract(registryOwner, backend, 18, big.NewInt(60000000000)) + require.NoError(t, err) + + linkFeedAddr, _, _, err := mock_v3_aggregator_contract.DeployMockV3AggregatorContract(registryOwner, backend, 18, big.NewInt(2000000000000000000)) + require.NoError(t, err) + + registry := deployKeeper21Registry(t, registryOwner, backend, linkAddr, linkFeedAddr, gasFeedAddr) + + nodes, mercuryServer := setupNodes(t, nodeKeys, registry, backend, registryOwner) + + const upkeepCount = 10 + const mercuryFailCount = upkeepCount * 3 * 2 + + // testing with the mercury server involves mocking responses. currently, + // there is not a way to connect a mercury call to an upkeep id (though we + // could add custom headers) so the test must be fairly basic and just + // count calls before switching to successes + var ( + mu sync.Mutex + count int + ) + + mercuryServer.RegisterHandler(func(w http.ResponseWriter, r *http.Request) { + mu.Lock() + defer mu.Unlock() + + count++ + + _ = r.ParseForm() + + t.Logf("MercuryHTTPServe:RequestURI: %s", r.RequestURI) + + for key, value := range r.Form { + t.Logf("MercuryHTTPServe:FormValue: key: %s; value: %s;", key, value) + } + + // the streams lookup retries against the remote server 3 times before + // returning a result as retryable. + // the simulation here should force the streams lookup process to return + // retryable 2 times. + // the total count of failures should be (upkeepCount * 3 * tryCount) + if count <= mercuryFailCount { + w.WriteHeader(http.StatusNotFound) + + return + } + + // start sending success messages + output := `{"chainlinkBlob":"0x0001c38d71fed6c320b90e84b6f559459814d068e2a1700adc931ca9717d4fe70000000000000000000000000000000000000000000000000000000001a80b52b4bf1233f9cb71144a253a1791b202113c4ab4a92fa1b176d684b4959666ff8200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001004254432d5553442d415242495452554d2d544553544e4554000000000000000000000000000000000000000000000000000000000000000000000000645570be000000000000000000000000000000000000000000000000000002af2b818dc5000000000000000000000000000000000000000000000000000002af2426faf3000000000000000000000000000000000000000000000000000002af32dc209700000000000000000000000000000000000000000000000000000000012130f8df0a9745bb6ad5e2df605e158ba8ad8a33ef8a0acf9851f0f01668a3a3f2b68600000000000000000000000000000000000000000000000000000000012130f60000000000000000000000000000000000000000000000000000000000000002c4a7958dce105089cf5edb68dad7dcfe8618d7784eb397f97d5a5fade78c11a58275aebda478968e545f7e3657aba9dcbe8d44605e4c6fde3e24edd5e22c94270000000000000000000000000000000000000000000000000000000000000002459c12d33986018a8959566d145225f0c4a4e61a9a3f50361ccff397899314f0018162cf10cd89897635a0bb62a822355bd199d09f4abe76e4d05261bb44733d"}` + + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(output)) + }) + + defer mercuryServer.Stop() + + _, err = linkToken.Transfer(linkOwner, upkeepOwner.From, big.NewInt(0).Mul(oneHunEth, big.NewInt(int64(upkeepCount+1)))) + require.NoError(t, err) + + backend.Commit() + + feeds, err := newFeedLookupUpkeepController(backend, registryOwner) + require.NoError(t, err, "no error expected from creating a feed lookup controller") + + // deploy multiple upkeeps that listen to a log emitter and need to be + // performed for each log event + _ = feeds.DeployUpkeeps(t, backend, upkeepOwner, upkeepCount) + _ = feeds.RegisterAndFund(t, registry, registryOwner, backend, linkToken) + _ = feeds.EnableMercury(t, backend, registry, registryOwner) + _ = feeds.VerifyEnv(t, backend, registry, registryOwner) + + // start emitting events in a separate go-routine + // feed lookup relies on a single contract event log to perform multiple + // listener contracts + go func() { + // only 1 event is necessary to make all 10 upkeeps eligible + _ = feeds.EmitEvents(t, backend, 1, func() { + // pause per emit for expected block production time + time.Sleep(3 * time.Second) + }) + }() + + listener, done := listenPerformed(t, backend, registry, feeds.UpkeepsIds(), int64(1)) + g.Eventually(listener, testutils.WaitTimeout(t)-(5*time.Second), cltest.DBPollingInterval).Should(gomega.BeTrue()) + + done() + + _ = checkPipelineRuns(t, nodes, 1*len(nodes)) // TODO: TBD +} + func waitPipelineRuns(t *testing.T, nodes []Node, n int, timeout, interval time.Duration) { ctx, cancel := context.WithTimeout(testutils.Context(t), timeout) defer cancel() @@ -310,29 +432,37 @@ func listenPerformed(t *testing.T, backend *backends.SimulatedBackend, registry cache := &sync.Map{} ctx, cancel := context.WithCancel(testutils.Context(t)) start := startBlock + go func() { for ctx.Err() == nil { bl := backend.Blockchain().CurrentBlock().Number.Uint64() + sc := make([]bool, len(ids)) for i := range sc { sc[i] = true } + iter, err := registry.FilterUpkeepPerformed(&bind.FilterOpts{ Start: uint64(start), End: &bl, Context: ctx, }, ids, sc) + if ctx.Err() != nil { return } + require.NoError(t, err) + for iter.Next() { if iter.Event != nil { t.Logf("[automation-ocr3 | EvmRegistry] upkeep performed event emitted for id %s", iter.Event.Id.String()) cache.Store(iter.Event.Id.String(), true) } } + require.NoError(t, iter.Close()) + time.Sleep(time.Second) } }() @@ -340,11 +470,14 @@ func listenPerformed(t *testing.T, backend *backends.SimulatedBackend, registry return mapListener(cache, 0), cancel } -func setupNodes(t *testing.T, nodeKeys [5]ethkey.KeyV2, registry *iregistry21.IKeeperRegistryMaster, backend *backends.SimulatedBackend, usr *bind.TransactOpts) []Node { +func setupNodes(t *testing.T, nodeKeys [5]ethkey.KeyV2, registry *iregistry21.IKeeperRegistryMaster, backend *backends.SimulatedBackend, usr *bind.TransactOpts) ([]Node, *SimulatedMercuryServer) { lggr := logger.TestLogger(t) + mServer := NewSimulatedMercuryServer() + mServer.Start() + // Setup bootstrap + oracle nodes bootstrapNodePort := int64(19599) - appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, "bootstrap_keeper_ocr", nodeKeys[0], backend, nil) + appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, "bootstrap_keeper_ocr", nodeKeys[0], backend, nil, mServer) bootstrapNode := Node{ appBootstrap, bootstrapTransmitter, bootstrapKb, } @@ -357,7 +490,7 @@ func setupNodes(t *testing.T, nodeKeys [5]ethkey.KeyV2, registry *iregistry21.IK app, peerID, transmitter, kb := setupNode(t, bootstrapNodePort+i+1, fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, - }) + }, mServer) nodes = append(nodes, Node{ app, transmitter, kb, @@ -430,7 +563,7 @@ func setupNodes(t *testing.T, nodeKeys [5]ethkey.KeyV2, registry *iregistry21.IK "fallbackLinkPrice": big.NewInt(2000000000000000000), "transcoder": testutils.NewAddress(), "registrars": []common.Address{testutils.NewAddress()}, - "upkeepPrivilegeManager": testutils.NewAddress(), + "upkeepPrivilegeManager": usr.From, }, configType) require.NoError(t, err) rawCfg, err := json.Marshal(config.OffchainConfig{ @@ -488,7 +621,7 @@ func setupNodes(t *testing.T, nodeKeys [5]ethkey.KeyV2, registry *iregistry21.IK require.NoError(t, err) backend.Commit() - return nodes + return nodes, mServer } func deployUpkeeps(t *testing.T, backend *backends.SimulatedBackend, carrol, steve *bind.TransactOpts, linkToken *link_token_interface.LinkToken, registry *iregistry21.IKeeperRegistryMaster, n int) ([]*big.Int, []common.Address, []*log_upkeep_counter_wrapper.LogUpkeepCounter) { @@ -591,3 +724,297 @@ func getUpkeepIdFromTx21(t *testing.T, registry *iregistry21.IKeeperRegistryMast require.NoError(t, err) return parsedLog.Id } + +// ------- below this line could be added to a test helpers package +type registerAndFundFunc func(*testing.T, common.Address, *bind.TransactOpts, uint8, []byte) *big.Int + +func registerAndFund( + registry *iregistry21.IKeeperRegistryMaster, + registryOwner *bind.TransactOpts, + backend *backends.SimulatedBackend, + linkToken *link_token_interface.LinkToken, +) registerAndFundFunc { + return func(t *testing.T, upkeepAddr common.Address, upkeepOwner *bind.TransactOpts, trigger uint8, config []byte) *big.Int { + // register the upkeep on the host registry contract + registrationTx, err := registry.RegisterUpkeep( + registryOwner, + upkeepAddr, + 2_500_000, + upkeepOwner.From, + trigger, + []byte{}, + config, + []byte{}, + ) + require.NoError(t, err) + + backend.Commit() + + receipt, err := backend.TransactionReceipt(testutils.Context(t), registrationTx.Hash()) + require.NoError(t, err) + + parsedLog, err := registry.ParseUpkeepRegistered(*receipt.Logs[0]) + require.NoError(t, err) + + upkeepID := parsedLog.Id + + // Fund the upkeep + _, err = linkToken.Approve(upkeepOwner, registry.Address(), oneHunEth) + require.NoError(t, err) + + _, err = registry.AddFunds(upkeepOwner, upkeepID, oneHunEth) + require.NoError(t, err) + + backend.Commit() + + return upkeepID + } +} + +type feedLookupUpkeepController struct { + // address for dummy protocol + logSrcAddr common.Address + // dummy protocol is a log event source + protocol *dummy_protocol_wrapper.DummyProtocol + protocolOwner *bind.TransactOpts + // log trigger listener contracts react to logs produced from protocol + count int + upkeepIds []*big.Int + addresses []common.Address + contracts []*log_triggered_streams_lookup_wrapper.LogTriggeredStreamsLookup + contractsOwner *bind.TransactOpts +} + +func newFeedLookupUpkeepController( + backend *backends.SimulatedBackend, + protocolOwner *bind.TransactOpts, +) (*feedLookupUpkeepController, error) { + addr, _, contract, err := dummy_protocol_wrapper.DeployDummyProtocol(protocolOwner, backend) + if err != nil { + return nil, err + } + + backend.Commit() + + return &feedLookupUpkeepController{ + logSrcAddr: addr, + protocol: contract, + protocolOwner: protocolOwner, + }, nil +} + +func (c *feedLookupUpkeepController) DeployUpkeeps( + t *testing.T, + backend *backends.SimulatedBackend, + owner *bind.TransactOpts, + count int, +) error { + addresses := make([]common.Address, count) + contracts := make([]*log_triggered_streams_lookup_wrapper.LogTriggeredStreamsLookup, count) + + // deploy n upkeep contracts + for x := 0; x < count; x++ { + addr, _, contract, err := log_triggered_streams_lookup_wrapper.DeployLogTriggeredStreamsLookup( + owner, + backend, + false, + false, + ) + + if err != nil { + require.NoError(t, err, "test dependent on contract deployment") + + return err + } + + addresses[x] = addr + contracts[x] = contract + } + + backend.Commit() + + c.count = count + c.addresses = addresses + c.contracts = contracts + c.contractsOwner = owner + + return nil +} + +func (c *feedLookupUpkeepController) RegisterAndFund( + t *testing.T, + registry *iregistry21.IKeeperRegistryMaster, + registryOwner *bind.TransactOpts, + backend *backends.SimulatedBackend, + linkToken *link_token_interface.LinkToken, +) error { + ids := make([]*big.Int, len(c.contracts)) + + t.Logf("address: %s", c.logSrcAddr.Hex()) + + logTriggerConfigType := abi.MustNewType("tuple(address contractAddress, uint8 filterSelector, bytes32 topic0, bytes32 topic1, bytes32 topic2, bytes32 topic3)") + config, err := abi.Encode(map[string]interface{}{ + "contractAddress": c.logSrcAddr, + "filterSelector": 0, // no indexed topics filtered + "topic0": "0xd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd", // LimitOrderExecuted event for dummy protocol + "topic1": "0x", + "topic2": "0x", + "topic3": "0x", + }, logTriggerConfigType) + + require.NoError(t, err) + + registerFunc := registerAndFund(registry, registryOwner, backend, linkToken) + + for x := range c.contracts { + ids[x] = registerFunc(t, c.addresses[x], c.contractsOwner, 1, config) + } + + c.upkeepIds = ids + + return nil +} + +func (c *feedLookupUpkeepController) EnableMercury( + t *testing.T, + backend *backends.SimulatedBackend, + registry *iregistry21.IKeeperRegistryMaster, + registryOwner *bind.TransactOpts, +) error { + adminBytes, _ := json.Marshal(evm21.UpkeepPrivilegeConfig{ + MercuryEnabled: true, + }) + + for _, id := range c.upkeepIds { + if _, err := registry.SetUpkeepPrivilegeConfig(registryOwner, id, adminBytes); err != nil { + require.NoError(t, err) + + return err + } + + callOpts := &bind.CallOpts{ + Pending: true, + From: registryOwner.From, + Context: context.Background(), + } + + bts, err := registry.GetUpkeepPrivilegeConfig(callOpts, id) + if err != nil { + require.NoError(t, err) + + return err + } + + var checkBytes evm21.UpkeepPrivilegeConfig + if err := json.Unmarshal(bts, &checkBytes); err != nil { + require.NoError(t, err) + + return err + } + + require.True(t, checkBytes.MercuryEnabled) + } + + bl, _ := backend.BlockByHash(testutils.Context(t), backend.Commit()) + t.Logf("block number after mercury enabled: %d", bl.NumberU64()) + + return nil +} + +func (c *feedLookupUpkeepController) VerifyEnv( + t *testing.T, + backend *backends.SimulatedBackend, + registry *iregistry21.IKeeperRegistryMaster, + registryOwner *bind.TransactOpts, +) error { + t.Log("verifying number of active upkeeps") + + ids, err := registry.GetActiveUpkeepIDs(&bind.CallOpts{ + Context: testutils.Context(t), + From: registryOwner.From, + }, big.NewInt(0), big.NewInt(100)) + + require.NoError(t, err) + require.Len(t, ids, c.count, "active upkeep ids does not match count") + require.Len(t, ids, len(c.upkeepIds)) + + t.Log("verifying total number of contracts") + require.Len(t, c.contracts, len(c.upkeepIds), "one contract for each upkeep id expected") + + // call individual contracts to see that they revert + for _, contract := range c.contracts { + _, err := contract.CheckLog(c.contractsOwner, log_triggered_streams_lookup_wrapper.Log{ + Index: big.NewInt(0), + TxIndex: big.NewInt(0), + TxHash: common.HexToHash("0x1"), + BlockNumber: big.NewInt(0), + BlockHash: common.HexToHash("0x14"), + Source: common.HexToAddress("0x2"), + Topics: [][32]byte{ + common.HexToHash("0xd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd"), // matches executedSig and should result in a feedlookup revert + common.HexToHash("0x"), + common.HexToHash("0x"), + common.HexToHash("0x"), + }, + Data: []byte{}, + }, []byte("0x")) + + require.Error(t, err, "check log contract call should revert: %s", err) + } + + return nil +} + +func (c *feedLookupUpkeepController) EmitEvents( + t *testing.T, + backend *backends.SimulatedBackend, + count int, + afterEmit func(), +) error { + ctx := testutils.Context(t) + + for i := 0; i < count && ctx.Err() == nil; i++ { + _, err := c.protocol.ExecuteLimitOrder(c.protocolOwner, big.NewInt(1000), big.NewInt(10000), c.logSrcAddr) + require.NoError(t, err, "no error expected from limit order exec") + + if err != nil { + return err + } + + backend.Commit() + + // verify event was emitted + block, _ := backend.BlockByHash(context.Background(), backend.Commit()) + t.Logf("block number after emit event: %d", block.NumberU64()) + + iter, _ := c.protocol.FilterLimitOrderExecuted( + &bind.FilterOpts{ + Context: testutils.Context(t), + Start: block.NumberU64() - 1, + }, + []*big.Int{big.NewInt(1000)}, + []*big.Int{big.NewInt(10000)}, + []common.Address{c.logSrcAddr}, + ) + + var eventEmitted bool + for iter.Next() { + if iter.Event != nil { + eventEmitted = true + } + } + + require.True(t, eventEmitted, "event expected on backend") + if !eventEmitted { + return fmt.Errorf("event was not emitted") + } + + afterEmit() + } + + return nil +} + +func (c *feedLookupUpkeepController) UpkeepsIds() []*big.Int { + return c.upkeepIds +} diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index 8b7e92c40fe..eea9c1574cf 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -7,7 +7,10 @@ import ( "encoding/json" "fmt" "math/big" + "net/http" + "net/http/httptest" "strings" + "sync" "testing" "time" @@ -56,6 +59,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" + + relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" ) const ( @@ -108,11 +113,12 @@ func setupNode( nodeKey ethkey.KeyV2, backend *backends.SimulatedBackend, p2pV2Bootstrappers []commontypes.BootstrapperLocator, + mercury MercuryEndpoint, ) (chainlink.Application, string, common.Address, ocr2key.KeyBundle) { p2pKey, err := p2pkey.NewV2() require.NoError(t, err) p2paddresses := []string{fmt.Sprintf("127.0.0.1:%d", port)} - config, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("%s%d", dbName, port), func(c *chainlink.Config, s *chainlink.Secrets) { + cfg, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("%s%d", dbName, port), func(c *chainlink.Config, s *chainlink.Secrets) { c.Feature.LogPoller = ptr(true) c.OCR.Enabled = ptr(false) @@ -133,14 +139,15 @@ func setupNode( c.EVM[0].GasEstimator.Mode = ptr("FixedPrice") s.Mercury.Credentials = map[string]toml.MercuryCredentials{ MercuryCredName: { - URL: models.MustSecretURL("https://mercury.chain.link"), - Username: models.NewSecret("username1"), - Password: models.NewSecret("password1"), + LegacyURL: models.MustSecretURL(mercury.URL()), + URL: models.MustSecretURL(mercury.URL()), + Username: models.NewSecret(mercury.Username()), + Password: models.NewSecret(mercury.Password()), }, } }) - app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, backend, nodeKey, p2pKey) + app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, cfg, backend, nodeKey, p2pKey) kb, err := app.GetKeyStore().OCR2().Create(chaintype.EVM) require.NoError(t, err) @@ -162,16 +169,16 @@ type Node struct { func (node *Node) AddJob(t *testing.T, spec string) { c := node.App.GetConfig() - job, err := validate.ValidatedOracleSpecToml(c.OCR2(), c.Insecure(), spec) + jb, err := validate.ValidatedOracleSpecToml(c.OCR2(), c.Insecure(), spec) require.NoError(t, err) - err = node.App.AddJobV2(context.Background(), &job) + err = node.App.AddJobV2(context.Background(), &jb) require.NoError(t, err) } func (node *Node) AddBootstrapJob(t *testing.T, spec string) { - job, err := ocrbootstrap.ValidatedBootstrapSpecToml(spec) + jb, err := ocrbootstrap.ValidatedBootstrapSpecToml(spec) require.NoError(t, err) - err = node.App.AddJobV2(context.Background(), &job) + err = node.App.AddJobV2(context.Background(), &jb) require.NoError(t, err) } @@ -232,7 +239,7 @@ func TestIntegration_KeeperPluginBasic(t *testing.T) { // Setup bootstrap + oracle nodes bootstrapNodePort := int64(19599) - appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, "bootstrap_keeper_ocr", nodeKeys[0], backend, nil) + appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, "bootstrap_keeper_ocr", nodeKeys[0], backend, nil, NewSimulatedMercuryServer()) bootstrapNode := Node{ appBootstrap, bootstrapTransmitter, bootstrapKb, } @@ -245,7 +252,7 @@ func TestIntegration_KeeperPluginBasic(t *testing.T) { app, peerID, transmitter, kb := setupNode(t, bootstrapNodePort+i+1, fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, - }) + }, NewSimulatedMercuryServer()) nodes = append(nodes, Node{ app, transmitter, kb, @@ -492,7 +499,7 @@ func TestIntegration_KeeperPluginForwarderEnabled(t *testing.T) { effectiveTransmitters := make([]common.Address, 0) // Setup bootstrap + oracle nodes bootstrapNodePort := int64(19599) - appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, "bootstrap_keeper_ocr", nodeKeys[0], backend, nil) + appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, "bootstrap_keeper_ocr", nodeKeys[0], backend, nil, NewSimulatedMercuryServer()) bootstrapNode := Node{ appBootstrap, bootstrapTransmitter, bootstrapKb, @@ -506,7 +513,7 @@ func TestIntegration_KeeperPluginForwarderEnabled(t *testing.T) { app, peerID, transmitter, kb := setupNode(t, bootstrapNodePort+i+1, fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, - }) + }, NewSimulatedMercuryServer()) nodeForwarder := setupForwarderForNode(t, app, sergey, backend, transmitter, linkAddr) effectiveTransmitters = append(effectiveTransmitters, nodeForwarder) @@ -705,7 +712,7 @@ func TestFilterNamesFromSpec20(t *testing.T) { address := common.HexToAddress(hexutil.Encode(b)) spec := &job.OCR2OracleSpec{ - PluginType: job.OCR2Keeper, + PluginType: relaytypes.OCR2Keeper, ContractID: address.String(), // valid contract addr } @@ -717,9 +724,78 @@ func TestFilterNamesFromSpec20(t *testing.T) { assert.Equal(t, logpoller.FilterName("EvmRegistry - Upkeep events for", address), names[1]) spec = &job.OCR2OracleSpec{ - PluginType: job.OCR2Keeper, + PluginType: relaytypes.OCR2Keeper, ContractID: "0x5431", // invalid contract addr } _, err = ocr2keeper.FilterNamesFromSpec20(spec) require.ErrorContains(t, err, "not a valid EIP55 formatted address") } + +// ------- below this line could be added to a test helpers package +type MercuryEndpoint interface { + URL() string + Username() string + Password() string + CallCount() int + RegisterHandler(http.HandlerFunc) +} + +type SimulatedMercuryServer struct { + server *httptest.Server + handler http.HandlerFunc + + mu sync.RWMutex + callCount int +} + +func NewSimulatedMercuryServer() *SimulatedMercuryServer { + srv := &SimulatedMercuryServer{ + handler: func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotFound) + }, + } + + srv.server = httptest.NewUnstartedServer(srv) + + return srv +} + +func (ms *SimulatedMercuryServer) URL() string { + return ms.server.URL +} + +func (ms *SimulatedMercuryServer) Username() string { + return "username1" +} + +func (ms *SimulatedMercuryServer) Password() string { + return "password1" +} + +func (ms *SimulatedMercuryServer) CallCount() int { + ms.mu.RLock() + defer ms.mu.RUnlock() + + return ms.callCount +} + +func (ms *SimulatedMercuryServer) RegisterHandler(h http.HandlerFunc) { + ms.handler = h +} + +func (ms *SimulatedMercuryServer) Start() { + ms.server.Start() +} + +func (ms *SimulatedMercuryServer) Stop() { + ms.server.Close() +} + +func (ms *SimulatedMercuryServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { + ms.mu.Lock() + defer ms.mu.Unlock() + + ms.callCount++ + + ms.handler.ServeHTTP(w, r) +} diff --git a/core/services/ocr2/plugins/ocr2keeper/util.go b/core/services/ocr2/plugins/ocr2keeper/util.go index ff1cd0940dd..132afd0d29d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/util.go +++ b/core/services/ocr2/plugins/ocr2keeper/util.go @@ -140,5 +140,5 @@ func FilterNamesFromSpec21(spec *job.OCR2OracleSpec) (names []string, err error) if err != nil { return nil, err } - return []string{kevm21transmit.TransmitEventProviderFilterName(addr.Address()), kevm21.RegistryUpkeepFilterName(addr.Address())}, err + return []string{kevm21transmit.EventProviderFilterName(addr.Address()), kevm21.RegistryUpkeepFilterName(addr.Address())}, err } diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go index 5a32644d0ee..1222ab7b2a4 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go @@ -25,6 +25,7 @@ import ( "github.com/smartcontractkit/ocr2vrf/ocr2vrf" ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" + relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" 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" @@ -1761,7 +1762,7 @@ func TestFilterNamesFromSpec(t *testing.T) { spec := &job.OCR2OracleSpec{ ContractID: beaconAddress.String(), - PluginType: job.OCR2VRF, + PluginType: relaytypes.OCR2VRF, PluginConfig: job.JSONConfig{ "VRFCoordinatorAddress": coordinatorAddress.String(), "DKGContractAddress": dkgAddress.String(), @@ -1775,7 +1776,7 @@ func TestFilterNamesFromSpec(t *testing.T) { assert.Equal(t, logpoller.FilterName("VRF Coordinator", beaconAddress, coordinatorAddress, dkgAddress), names[0]) spec = &job.OCR2OracleSpec{ - PluginType: job.OCR2VRF, + PluginType: relaytypes.OCR2VRF, ContractID: beaconAddress.String(), PluginConfig: nil, // missing coordinator & dkg addresses } diff --git a/core/services/ocr2/plugins/s4/messages_test.go b/core/services/ocr2/plugins/s4/messages_test.go index 78fcabf9899..55c65eec8df 100644 --- a/core/services/ocr2/plugins/s4/messages_test.go +++ b/core/services/ocr2/plugins/s4/messages_test.go @@ -1,14 +1,16 @@ package s4_test import ( + "crypto/ecdsa" "testing" "time" + "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/s4" s4_svc "github.com/smartcontractkit/chainlink/v2/core/services/s4" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -55,6 +57,32 @@ func Test_MarshalUnmarshalQuery(t *testing.T) { require.Equal(t, addressRange, ar) } +func signRow(t *testing.T, row *s4.Row, address common.Address, pk *ecdsa.PrivateKey) { + t.Helper() + + env := &s4_svc.Envelope{ + Address: address.Bytes(), + SlotID: uint(row.Slotid), + Version: row.Version, + Expiration: row.Expiration, + Payload: row.Payload, + } + sig, err := env.Sign(pk) + require.NoError(t, err) + row.Signature = sig +} + +func marshalUnmarshal(t *testing.T, row *s4.Row) *s4.Row { + t.Helper() + + data, err := s4.MarshalRows([]*s4.Row{row}) + require.NoError(t, err) + rows, err := s4.UnmarshalRows(data) + require.NoError(t, err) + require.Len(t, rows, 1) + return rows[0] +} + func Test_VerifySignature(t *testing.T) { t.Parallel() @@ -71,20 +99,24 @@ func Test_VerifySignature(t *testing.T) { for addr[0] != 0 { pk, addr = testutils.NewPrivateKeyAndAddress(t) } - rows := generateTestRows(t, 1, time.Minute) - rows[0].Address = addr.Big().Bytes() - env := &s4_svc.Envelope{ - Address: addr.Bytes(), - SlotID: uint(rows[0].Slotid), - Version: rows[0].Version, - Expiration: rows[0].Expiration, - Payload: rows[0].Payload, - } - sig, err := env.Sign(pk) - assert.NoError(t, err) - rows[0].Signature = sig + row := generateTestRows(t, 1, time.Minute)[0] + row.Address = addr.Big().Bytes() + signRow(t, row, addr, pk) - err = rows[0].VerifySignature() - require.NoError(t, err) + require.NoError(t, row.VerifySignature()) + sameRow := marshalUnmarshal(t, row) + require.NoError(t, sameRow.VerifySignature()) + }) + + t.Run("empty payload", func(t *testing.T) { + pk, addr := testutils.NewPrivateKeyAndAddress(t) + row := generateTestRows(t, 1, time.Minute)[0] + row.Payload = []byte{} + row.Address = addr.Big().Bytes() + signRow(t, row, addr, pk) + + require.NoError(t, row.VerifySignature()) + sameRow := marshalUnmarshal(t, row) + require.NoError(t, sameRow.VerifySignature()) }) } diff --git a/core/services/ocr2/validate/validate.go b/core/services/ocr2/validate/validate.go index ca1ab60deb9..cde1a1f9276 100644 --- a/core/services/ocr2/validate/validate.go +++ b/core/services/ocr2/validate/validate.go @@ -12,6 +12,7 @@ import ( libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" + "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/services/job" dkgconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/config" mercuryconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/mercury/config" @@ -98,20 +99,20 @@ func validateSpec(tree *toml.Tree, spec job.Job) error { } switch spec.OCR2OracleSpec.PluginType { - case job.Median: + case types.Median: if spec.Pipeline.Source == "" { return errors.New("no pipeline specified") } - case job.DKG: + case types.DKG: return validateDKGSpec(spec.OCR2OracleSpec.PluginConfig) - case job.OCR2VRF: + case types.OCR2VRF: return validateOCR2VRFSpec(spec.OCR2OracleSpec.PluginConfig) - case job.OCR2Keeper: + case types.OCR2Keeper: return validateOCR2KeeperSpec(spec.OCR2OracleSpec.PluginConfig) - case job.OCR2Functions: + case types.Functions: // TODO validator for DR-OCR spec: https://app.shortcut.com/chainlinklabs/story/54054/ocr-plugin-for-directrequest-ocr return nil - case job.Mercury: + case types.Mercury: return validateOCR2MercurySpec(spec.OCR2OracleSpec.PluginConfig, *spec.OCR2OracleSpec.FeedID) case "": return errors.New("no plugin specified") diff --git a/core/services/ocrbootstrap/delegate.go b/core/services/ocrbootstrap/delegate.go index b39f9eec6ec..d530797367f 100644 --- a/core/services/ocrbootstrap/delegate.go +++ b/core/services/ocrbootstrap/delegate.go @@ -118,7 +118,7 @@ func (d *Delegate) ServicesForSpec(jobSpec job.Job, qopts ...pg.QOpt) (services if routerFields.ContractVersion != 1 || routerFields.ContractUpdateCheckFrequencySec == 0 { return nil, errors.New("invalid router contract config") } - configProvider, err = relayer.NewFunctionsProvider( + configProvider, err = relayer.NewPluginProvider( ctx, types.RelayArgs{ ExternalJobID: jobSpec.ExternalJobID, @@ -126,6 +126,7 @@ func (d *Delegate) ServicesForSpec(jobSpec job.Job, qopts ...pg.QOpt) (services ContractID: spec.ContractID, RelayConfig: spec.RelayConfig.Bytes(), New: d.isNewlyCreatedJob, + ProviderType: string(types.Functions), }, types.PluginArgs{ PluginConfig: spec.RelayConfig.Bytes(), // contains all necessary fields for config provider diff --git a/core/services/pg/channels.go b/core/services/pg/channels.go index 7b0b768bdab..736cd407962 100644 --- a/core/services/pg/channels.go +++ b/core/services/pg/channels.go @@ -1,8 +1,8 @@ package pg -// Postgres channel to listen for new eth_txes +// Postgres channel to listen for new evm.txes const ( - ChannelInsertOnTx = "insert_on_eth_txes" + ChannelInsertOnTx = "evm.insert_on_txes" ChannelInsertOnCosmosMsg = "insert_on_cosmos_msg" - ChannelInsertOnEVMLogs = "insert_on_evm_logs" + ChannelInsertOnEVMLogs = "evm.insert_on_logs" ) diff --git a/core/services/pipeline/task.estimategas.go b/core/services/pipeline/task.estimategas.go index 967fb7ca034..88c6f6facc3 100644 --- a/core/services/pipeline/task.estimategas.go +++ b/core/services/pipeline/task.estimategas.go @@ -47,12 +47,20 @@ func (t *EstimateGasLimitTask) Type() TaskType { return TaskTypeEstimateGasLimit } +func (t *EstimateGasLimitTask) getEvmChainID() string { + if t.EVMChainID == "" { + t.EVMChainID = "$(jobSpec.evmChainID)" + } + return t.EVMChainID +} + func (t *EstimateGasLimitTask) Run(ctx context.Context, lggr logger.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { var ( fromAddr AddressParam toAddr AddressParam data BytesParam multiplier DecimalParam + chainID StringParam ) err := multierr.Combine( errors.Wrap(ResolveParam(&fromAddr, From(VarExpr(t.From, vars), utils.ZeroAddress)), "from"), @@ -60,14 +68,15 @@ func (t *EstimateGasLimitTask) Run(ctx context.Context, lggr logger.Logger, vars errors.Wrap(ResolveParam(&data, From(VarExpr(t.Data, vars), NonemptyString(t.Data))), "data"), // Default to 1, i.e. exactly what estimateGas suggests errors.Wrap(ResolveParam(&multiplier, From(VarExpr(t.Multiplier, vars), NonemptyString(t.Multiplier), decimal.New(1, 0))), "multiplier"), + errors.Wrap(ResolveParam(&chainID, From(VarExpr(t.getEvmChainID(), vars), NonemptyString(t.getEvmChainID()), "")), "evmChainID"), ) if err != nil { return Result{Error: err}, runInfo } - chain, err := t.legacyChains.Get(t.EVMChainID) + chain, err := t.legacyChains.Get(string(chainID)) if err != nil { - err = fmt.Errorf("%w: %s: %w", ErrInvalidEVMChainID, t.EVMChainID, err) + err = fmt.Errorf("%w: %s: %w", ErrInvalidEVMChainID, chainID, err) return Result{Error: err}, runInfo } diff --git a/core/services/pipeline/task.eth_call.go b/core/services/pipeline/task.eth_call.go index f3c76d404d4..e877e1e90f4 100644 --- a/core/services/pipeline/task.eth_call.go +++ b/core/services/pipeline/task.eth_call.go @@ -55,6 +55,13 @@ func (t *ETHCallTask) Type() TaskType { return TaskTypeETHCall } +func (t *ETHCallTask) getEvmChainID() string { + if t.EVMChainID == "" { + t.EVMChainID = "$(jobSpec.evmChainID)" + } + return t.EVMChainID +} + func (t *ETHCallTask) Run(ctx context.Context, lggr logger.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { _, err := CheckInputs(inputs, -1, -1, 0) if err != nil { @@ -80,7 +87,7 @@ func (t *ETHCallTask) Run(ctx context.Context, lggr logger.Logger, vars Vars, in errors.Wrap(ResolveParam(&gasPrice, From(VarExpr(t.GasPrice, vars), t.GasPrice)), "gasPrice"), errors.Wrap(ResolveParam(&gasTipCap, From(VarExpr(t.GasTipCap, vars), t.GasTipCap)), "gasTipCap"), errors.Wrap(ResolveParam(&gasFeeCap, From(VarExpr(t.GasFeeCap, vars), t.GasFeeCap)), "gasFeeCap"), - errors.Wrap(ResolveParam(&chainID, From(VarExpr(t.EVMChainID, vars), NonemptyString(t.EVMChainID), "")), "evmChainID"), + errors.Wrap(ResolveParam(&chainID, From(VarExpr(t.getEvmChainID(), vars), NonemptyString(t.getEvmChainID()), "")), "evmChainID"), errors.Wrap(ResolveParam(&gasUnlimited, From(VarExpr(t.GasUnlimited, vars), NonemptyString(t.GasUnlimited), false)), "gasUnlimited"), ) if err != nil { diff --git a/core/services/pipeline/task.eth_call_test.go b/core/services/pipeline/task.eth_call_test.go index b8896488e2d..77a10681fb4 100644 --- a/core/services/pipeline/task.eth_call_test.go +++ b/core/services/pipeline/task.eth_call_test.go @@ -56,7 +56,7 @@ func TestETHCallTask(t *testing.T) { "0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF", "", "$(foo)", - "", + "0", "", nil, pipeline.NewVarsFrom(map[string]interface{}{ @@ -76,7 +76,7 @@ func TestETHCallTask(t *testing.T) { "0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF", "", "$(foo)", - "", + "0", "$(gasLimit)", nil, pipeline.NewVarsFrom(map[string]interface{}{ @@ -97,7 +97,7 @@ func TestETHCallTask(t *testing.T) { "0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF", "", "$(foo)", - "", + "0", "", &specGasLimit, pipeline.NewVarsFrom(map[string]interface{}{ @@ -117,7 +117,7 @@ func TestETHCallTask(t *testing.T) { "0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF", "0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF", "$(foo)", - "", + "0", "", nil, pipeline.NewVarsFrom(map[string]interface{}{ @@ -138,7 +138,7 @@ func TestETHCallTask(t *testing.T) { "0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF", "0xThisAintGonnaWork", "$(foo)", - "", + "0", "", nil, pipeline.NewVarsFrom(map[string]interface{}{ @@ -153,7 +153,7 @@ func TestETHCallTask(t *testing.T) { "0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbee", "", "$(foo)", - "", + "0", "", nil, pipeline.NewVarsFrom(map[string]interface{}{ @@ -168,7 +168,7 @@ func TestETHCallTask(t *testing.T) { "0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF", "", "$(foo)", - "", + "0", "", nil, pipeline.NewVarsFrom(map[string]interface{}{ @@ -183,7 +183,7 @@ func TestETHCallTask(t *testing.T) { "0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF", "", "$(foo)", - "", + "0", "", nil, pipeline.NewVarsFrom(map[string]interface{}{ @@ -198,7 +198,7 @@ func TestETHCallTask(t *testing.T) { "0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF", "", "$(foo)", - "", + "0", "", nil, pipeline.NewVarsFrom(map[string]interface{}{ diff --git a/core/services/pipeline/task.eth_tx.go b/core/services/pipeline/task.eth_tx.go index 8761732e4f0..d5d29240652 100644 --- a/core/services/pipeline/task.eth_tx.go +++ b/core/services/pipeline/task.eth_tx.go @@ -56,9 +56,16 @@ func (t *ETHTxTask) Type() TaskType { return TaskTypeETHTx } +func (t *ETHTxTask) getEvmChainID() string { + if t.EVMChainID == "" { + t.EVMChainID = "$(jobSpec.evmChainID)" + } + return t.EVMChainID +} + func (t *ETHTxTask) Run(_ context.Context, lggr logger.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { var chainID StringParam - err := errors.Wrap(ResolveParam(&chainID, From(VarExpr(t.EVMChainID, vars), NonemptyString(t.EVMChainID), "")), "evmChainID") + err := errors.Wrap(ResolveParam(&chainID, From(VarExpr(t.getEvmChainID(), vars), NonemptyString(t.getEvmChainID()), "")), "evmChainID") if err != nil { return Result{Error: err}, runInfo } diff --git a/core/services/pipeline/task.eth_tx_test.go b/core/services/pipeline/task.eth_tx_test.go index d465c16f8fd..a280e6f2720 100644 --- a/core/services/pipeline/task.eth_tx_test.go +++ b/core/services/pipeline/task.eth_tx_test.go @@ -65,7 +65,7 @@ func TestETHTxTask(t *testing.T) { "12345", `{ "jobID": 321, "requestID": "0x5198616554d738d9485d1a7cf53b2f33e09c3bbc8fe9ac0020bd672cd2bc15d2", "requestTxHash": "0xc524fafafcaec40652b1f84fca09c231185437d008d195fccf2f51e64b7062f8" }`, `0`, - "", + "0", `{"CheckerType": "vrf_v2", "VRFCoordinatorAddress": "0x2E396ecbc8223Ebc16EC45136228AE5EDB649943"}`, nil, false, @@ -107,7 +107,7 @@ func TestETHTxTask(t *testing.T) { "$(gasLimit)", `{ "jobID": $(jobID), "requestID": $(requestID), "requestTxHash": $(requestTxHash) }`, `0`, - "", + "0", "", nil, false, @@ -150,7 +150,7 @@ func TestETHTxTask(t *testing.T) { "$(gasLimit)", `{ "jobID": $(jobID), "requestID": $(requestID), "requestTxHash": $(requestTxHash) }`, "$(minConfirmations)", - "", + "0", "", nil, false, @@ -182,7 +182,7 @@ func TestETHTxTask(t *testing.T) { "$(gasLimit)", `$(requestData)`, `0`, - "", + "0", "", nil, false, @@ -227,7 +227,7 @@ func TestETHTxTask(t *testing.T) { "$(gasLimit)", `$(requestData)`, `0`, - "", + "0", "", nil, false, @@ -272,7 +272,7 @@ func TestETHTxTask(t *testing.T) { "12345", `{}`, `0`, - "", + "0", "", nil, false, @@ -302,7 +302,7 @@ func TestETHTxTask(t *testing.T) { "", `{ "jobID": 321, "requestID": "0x5198616554d738d9485d1a7cf53b2f33e09c3bbc8fe9ac0020bd672cd2bc15d2", "requestTxHash": "0xc524fafafcaec40652b1f84fca09c231185437d008d195fccf2f51e64b7062f8" }`, `0`, - "", + "0", "", nil, // spec does not override gas limit false, @@ -336,7 +336,7 @@ func TestETHTxTask(t *testing.T) { "", `{ "jobID": 321, "requestID": "0x5198616554d738d9485d1a7cf53b2f33e09c3bbc8fe9ac0020bd672cd2bc15d2", "requestTxHash": "0xc524fafafcaec40652b1f84fca09c231185437d008d195fccf2f51e64b7062f8" }`, `0`, - "", + "0", "", &specGasLimit, false, @@ -370,7 +370,7 @@ func TestETHTxTask(t *testing.T) { "$(gasLimit)", `$(requestData)`, `0`, - "", + "0", "", nil, false, @@ -400,7 +400,7 @@ func TestETHTxTask(t *testing.T) { "12345", `{ "jobID": 321, "requestID": "0x5198616554d738d9485d1a7cf53b2f33e09c3bbc8fe9ac0020bd672cd2bc15d2", "requestTxHash": "0xc524fafafcaec40652b1f84fca09c231185437d008d195fccf2f51e64b7062f8" }`, `0`, - "", + "0", "", nil, false, @@ -435,7 +435,7 @@ func TestETHTxTask(t *testing.T) { "12345", `{ "jobID": 321, "requestID": "0x5198616554d738d9485d1a7cf53b2f33e09c3bbc8fe9ac0020bd672cd2bc15d2", "requestTxHash": "0xc524fafafcaec40652b1f84fca09c231185437d008d195fccf2f51e64b7062f8", "foo": "bar" }`, `0`, - "", + "0", "", nil, false, @@ -452,7 +452,7 @@ func TestETHTxTask(t *testing.T) { "12345", `{ "jobID": "asdf", "requestID": 123, "requestTxHash": true }`, `0`, - "", + "0", "", nil, false, @@ -469,7 +469,7 @@ func TestETHTxTask(t *testing.T) { "12345", `{ "jobID": 321, "requestID": "0x5198616554d738d9485d1a7cf53b2f33e09c3bbc8fe9ac0020bd672cd2bc15d2", "requestTxHash": "0xc524fafafcaec40652b1f84fca09c231185437d008d195fccf2f51e64b7062f8" }`, `0`, - "", + "0", "", nil, false, @@ -486,7 +486,7 @@ func TestETHTxTask(t *testing.T) { "12345", `{ "jobID": 321, "requestID": "0x5198616554d738d9485d1a7cf53b2f33e09c3bbc8fe9ac0020bd672cd2bc15d2", "requestTxHash": "0xc524fafafcaec40652b1f84fca09c231185437d008d195fccf2f51e64b7062f8" }`, `0`, - "", + "0", "", nil, false, @@ -503,7 +503,7 @@ func TestETHTxTask(t *testing.T) { "12345", `{ "jobID": 321, "requestID": "0x5198616554d738d9485d1a7cf53b2f33e09c3bbc8fe9ac0020bd672cd2bc15d2", "requestTxHash": "0xc524fafafcaec40652b1f84fca09c231185437d008d195fccf2f51e64b7062f8" }`, `3`, - "", + "0", "", nil, false, diff --git a/core/services/promreporter/prom_reporter.go b/core/services/promreporter/prom_reporter.go index 508e424c3b0..c0b48b46e3a 100644 --- a/core/services/promreporter/prom_reporter.go +++ b/core/services/promreporter/prom_reporter.go @@ -176,7 +176,7 @@ func (pr *promReporter) reportHeadMetrics(ctx context.Context, head *evmtypes.He func (pr *promReporter) reportPendingEthTxes(ctx context.Context, evmChainID *big.Int) (err error) { var unconfirmed int64 - if err := pr.db.QueryRowContext(ctx, `SELECT count(*) FROM eth_txes WHERE state = 'unconfirmed' AND evm_chain_id = $1`, evmChainID.String()).Scan(&unconfirmed); err != nil { + if err := pr.db.QueryRowContext(ctx, `SELECT count(*) FROM evm.txes WHERE state = 'unconfirmed' AND evm_chain_id = $1`, evmChainID.String()).Scan(&unconfirmed); err != nil { return errors.Wrap(err, "failed to query for unconfirmed eth_tx count") } pr.backend.SetUnconfirmedTransactions(evmChainID, unconfirmed) @@ -186,7 +186,7 @@ func (pr *promReporter) reportPendingEthTxes(ctx context.Context, evmChainID *bi func (pr *promReporter) reportMaxUnconfirmedAge(ctx context.Context, evmChainID *big.Int) (err error) { var broadcastAt null.Time now := time.Now() - if err := pr.db.QueryRowContext(ctx, `SELECT min(initial_broadcast_at) FROM eth_txes WHERE state = 'unconfirmed' AND evm_chain_id = $1`, evmChainID.String()).Scan(&broadcastAt); err != nil { + if err := pr.db.QueryRowContext(ctx, `SELECT min(initial_broadcast_at) FROM evm.txes WHERE state = 'unconfirmed' AND evm_chain_id = $1`, evmChainID.String()).Scan(&broadcastAt); err != nil { return errors.Wrap(err, "failed to query for unconfirmed eth_tx count") } var seconds float64 @@ -201,11 +201,11 @@ func (pr *promReporter) reportMaxUnconfirmedAge(ctx context.Context, evmChainID func (pr *promReporter) reportMaxUnconfirmedBlocks(ctx context.Context, head *evmtypes.Head) (err error) { var earliestUnconfirmedTxBlock null.Int err = pr.db.QueryRowContext(ctx, ` -SELECT MIN(broadcast_before_block_num) FROM eth_tx_attempts -JOIN eth_txes ON eth_txes.id = eth_tx_attempts.eth_tx_id -WHERE eth_txes.state = 'unconfirmed' +SELECT MIN(broadcast_before_block_num) FROM evm.tx_attempts +JOIN evm.txes ON evm.txes.id = evm.tx_attempts.eth_tx_id +WHERE evm.txes.state = 'unconfirmed' AND evm_chain_id = $1 -AND eth_txes.state = 'unconfirmed'`, head.EVMChainID.String()).Scan(&earliestUnconfirmedTxBlock) +AND evm.txes.state = 'unconfirmed'`, head.EVMChainID.String()).Scan(&earliestUnconfirmedTxBlock) if err != nil { return errors.Wrap(err, "failed to query for min broadcast_before_block_num") } diff --git a/core/services/promreporter/prom_reporter_test.go b/core/services/promreporter/prom_reporter_test.go index 62fbef64ea9..9629045cb0b 100644 --- a/core/services/promreporter/prom_reporter_test.go +++ b/core/services/promreporter/prom_reporter_test.go @@ -54,7 +54,7 @@ func Test_PromReporter_OnNewLongestChain(t *testing.T) { require.Eventually(t, func() bool { return subscribeCalls.Load() >= 1 }, 12*time.Second, 100*time.Millisecond) }) - t.Run("with unconfirmed eth_txes", func(t *testing.T) { + t.Run("with unconfirmed evm.txes", func(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) @@ -82,7 +82,7 @@ func Test_PromReporter_OnNewLongestChain(t *testing.T) { etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress) cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, fromAddress) cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 2, fromAddress) - require.NoError(t, utils.JustError(db.Exec(`UPDATE eth_tx_attempts SET broadcast_before_block_num = 7 WHERE eth_tx_id = $1`, etx.ID))) + require.NoError(t, utils.JustError(db.Exec(`UPDATE evm.tx_attempts SET broadcast_before_block_num = 7 WHERE eth_tx_id = $1`, etx.ID))) head := newHead() reporter.OnNewLongestChain(testutils.Context(t), &head) diff --git a/core/services/relay/evm/config_poller.go b/core/services/relay/evm/config_poller.go index aada1242303..6d8d4588d07 100644 --- a/core/services/relay/evm/config_poller.go +++ b/core/services/relay/evm/config_poller.go @@ -138,6 +138,9 @@ func (cp *configPoller) LatestConfig(ctx context.Context, changedInBlock uint64) if err != nil { return ocrtypes.ContractConfig{}, err } + if len(lgs) == 0 { + return ocrtypes.ContractConfig{}, errors.New("no logs found") + } latestConfigSet, err := configFromLog(lgs[len(lgs)-1].Data) if err != nil { return ocrtypes.ContractConfig{}, err diff --git a/core/services/relay/evm/config_poller_test.go b/core/services/relay/evm/config_poller_test.go index 724c303210b..75e033dfeb7 100644 --- a/core/services/relay/evm/config_poller_test.go +++ b/core/services/relay/evm/config_poller_test.go @@ -64,12 +64,14 @@ func TestConfigPoller(t *testing.T) { lp := logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, 1, 2, 2, 1000) require.NoError(t, lp.Start(ctx)) t.Cleanup(func() { lp.Close() }) - logPoller, err := NewConfigPoller(lggr, lp, ocrAddress) + configPoller, err := NewConfigPoller(lggr, lp, ocrAddress) require.NoError(t, err) // Should have no config to begin with. - _, config, err := logPoller.LatestConfigDetails(testutils.Context(t)) + _, config, err := configPoller.LatestConfigDetails(testutils.Context(t)) require.NoError(t, err) require.Equal(t, ocrtypes2.ConfigDigest{}, config) + _, err = configPoller.LatestConfig(testutils.Context(t), 0) + require.Error(t, err) // Set the config contractConfig := setConfig(t, median.OffchainConfig{ AlphaReportInfinite: false, @@ -89,13 +91,13 @@ func TestConfigPoller(t *testing.T) { var digest [32]byte gomega.NewGomegaWithT(t).Eventually(func() bool { b.Commit() - configBlock, digest, err = logPoller.LatestConfigDetails(testutils.Context(t)) + configBlock, digest, err = configPoller.LatestConfigDetails(testutils.Context(t)) require.NoError(t, err) return ocrtypes2.ConfigDigest{} != digest }, testutils.WaitTimeout(t), 100*time.Millisecond).Should(gomega.BeTrue()) // Assert the config returned is the one we configured. - newConfig, err := logPoller.LatestConfig(testutils.Context(t), configBlock) + newConfig, err := configPoller.LatestConfig(testutils.Context(t), configBlock) require.NoError(t, err) // Note we don't check onchainConfig, as that is populated in the contract itself. assert.Equal(t, digest, [32]byte(newConfig.ConfigDigest)) diff --git a/core/services/relay/evm/contract_transmitter.go b/core/services/relay/evm/contract_transmitter.go index d4a2c6204ca..470b5bae076 100644 --- a/core/services/relay/evm/contract_transmitter.go +++ b/core/services/relay/evm/contract_transmitter.go @@ -93,6 +93,9 @@ func (oc *contractTransmitter) Transmit(ctx context.Context, reportCtx ocrtypes. var rs [][32]byte var ss [][32]byte var vs [32]byte + if len(signatures) > 32 { + return errors.New("too many signatures, maximum is 32") + } for i, as := range signatures { r, s, v, err := evmutil.SplitSignature(as.Signature) if err != nil { @@ -138,6 +141,9 @@ func parseTransmitted(log []byte) ([32]byte, uint32, error) { if err != nil { return [32]byte{}, 0, err } + if len(transmitted) < 2 { + return [32]byte{}, 0, errors.New("transmitted event log has too few arguments") + } configDigest := *abi.ConvertType(transmitted[0], new([32]byte)).(*[32]byte) epoch := *abi.ConvertType(transmitted[1], new(uint32)).(*uint32) return configDigest, epoch, err diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 9578d4e0b0f..1ce68f2d944 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -35,6 +35,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/functions" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" + mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" reportcodecv1 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v1/reportcodec" reportcodecv2 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v2/reportcodec" reportcodecv3 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v3/reportcodec" @@ -112,6 +113,7 @@ func (r *Relayer) NewMercuryProvider(rargs relaytypes.RelayArgs, pargs relaytype if relayConfig.FeedID == nil { return nil, errors.New("FeedID must be specified") } + feedID := mercuryutils.FeedID(*relayConfig.FeedID) if relayConfig.ChainID.String() != r.chain.ID().String() { return nil, fmt.Errorf("internal error: chain id in spec does not match this relayer's chain: have %s expected %s", relayConfig.ChainID.String(), r.chain.ID().String()) @@ -121,13 +123,6 @@ func (r *Relayer) NewMercuryProvider(rargs relaytypes.RelayArgs, pargs relaytype return nil, errors.WithStack(err) } - // FIXME: We actually know the version here since it's in the feed ID, can - // we use generics to avoid passing three of this? - // https://smartcontract-it.atlassian.net/browse/MERC-1414 - reportCodecV1 := reportcodecv1.NewReportCodec(*relayConfig.FeedID, r.lggr.Named("ReportCodecV1")) - reportCodecV2 := reportcodecv2.NewReportCodec(*relayConfig.FeedID, r.lggr.Named("ReportCodecV2")) - reportCodecV3 := reportcodecv3.NewReportCodec(*relayConfig.FeedID, r.lggr.Named("ReportCodecV3")) - if !relayConfig.EffectiveTransmitterID.Valid { return nil, errors.New("EffectiveTransmitterID must be specified") } @@ -140,7 +135,26 @@ func (r *Relayer) NewMercuryProvider(rargs relaytypes.RelayArgs, pargs relaytype if err != nil { return nil, err } - transmitter := mercury.NewTransmitter(r.lggr, configWatcher.ContractConfigTracker(), client, privKey.PublicKey, rargs.JobID, *relayConfig.FeedID, r.db, r.pgCfg) + + // FIXME: We actually know the version here since it's in the feed ID, can + // we use generics to avoid passing three of this? + // https://smartcontract-it.atlassian.net/browse/MERC-1414 + reportCodecV1 := reportcodecv1.NewReportCodec(*relayConfig.FeedID, r.lggr.Named("ReportCodecV1")) + reportCodecV2 := reportcodecv2.NewReportCodec(*relayConfig.FeedID, r.lggr.Named("ReportCodecV2")) + reportCodecV3 := reportcodecv3.NewReportCodec(*relayConfig.FeedID, r.lggr.Named("ReportCodecV3")) + + var transmitterCodec mercury.TransmitterReportDecoder + switch feedID.Version() { + case 1: + transmitterCodec = reportCodecV1 + case 2: + transmitterCodec = reportCodecV2 + case 3: + transmitterCodec = reportCodecV3 + default: + return nil, fmt.Errorf("invalid feed version %d", feedID.Version()) + } + transmitter := mercury.NewTransmitter(r.lggr, configWatcher.ContractConfigTracker(), client, privKey.PublicKey, rargs.JobID, *relayConfig.FeedID, r.db, r.pgCfg, transmitterCodec) return NewMercuryProvider(configWatcher, transmitter, reportCodecV1, reportCodecV2, reportCodecV3, r.lggr), nil } diff --git a/core/services/relay/evm/functions/config_poller.go b/core/services/relay/evm/functions/config_poller.go index 4feff842ce3..f068f13cc77 100644 --- a/core/services/relay/evm/functions/config_poller.go +++ b/core/services/relay/evm/functions/config_poller.go @@ -162,6 +162,9 @@ func (cp *configPoller) LatestConfig(ctx context.Context, changedInBlock uint64) if err != nil { return ocrtypes.ContractConfig{}, err } + if len(lgs) == 0 { + return ocrtypes.ContractConfig{}, errors.New("no logs found") + } latestConfigSet, err := configFromLog(lgs[len(lgs)-1].Data, cp.pluginType) if err != nil { return ocrtypes.ContractConfig{}, err diff --git a/core/services/relay/evm/functions/config_poller_test.go b/core/services/relay/evm/functions/config_poller_test.go index b6de78b49df..b53b2751b15 100644 --- a/core/services/relay/evm/functions/config_poller_test.go +++ b/core/services/relay/evm/functions/config_poller_test.go @@ -89,6 +89,8 @@ func runTest(t *testing.T, pluginType functions.FunctionsPluginType, expectedDig _, config, err := configPoller.LatestConfigDetails(testutils.Context(t)) require.NoError(t, err) require.Equal(t, ocrtypes2.ConfigDigest{}, config) + _, err = configPoller.LatestConfig(testutils.Context(t), 0) + require.Error(t, err) pluginConfig := &functionsConfig.ReportingPluginConfigWrapper{ Config: &functionsConfig.ReportingPluginConfig{ diff --git a/core/services/relay/evm/functions/contract_transmitter.go b/core/services/relay/evm/functions/contract_transmitter.go index ecbe3c49f96..648cbcc2606 100644 --- a/core/services/relay/evm/functions/contract_transmitter.go +++ b/core/services/relay/evm/functions/contract_transmitter.go @@ -1,8 +1,10 @@ package functions import ( + "bytes" "context" "database/sql" + "encoding/hex" "fmt" "math/big" "sync/atomic" @@ -99,6 +101,9 @@ func (oc *contractTransmitter) Transmit(ctx context.Context, reportCtx ocrtypes. var rs [][32]byte var ss [][32]byte var vs [32]byte + if len(signatures) > 32 { + return errors.New("too many signatures, maximum is 32") + } for i, as := range signatures { r, s, v, err := evmutil.SplitSignature(as.Signature) if err != nil { @@ -134,9 +139,20 @@ func (oc *contractTransmitter) Transmit(ctx context.Context, reportCtx ocrtypes. if len(requests[0].CoordinatorContract) != common.AddressLength { return fmt.Errorf("FunctionsContractTransmitter: incorrect length of CoordinatorContract field: %d", len(requests[0].CoordinatorContract)) } - // NOTE: this is incorrect if batch contains requests destined for different contracts (unlikely) - // it will be fixed when we get rid of batching destinationContract.SetBytes(requests[0].CoordinatorContract) + if destinationContract == (common.Address{}) { + return errors.New("FunctionsContractTransmitter: destination coordinator contract is zero") + } + // Sanity check - every report should contain requests with the same coordinator contract. + for _, req := range requests[1:] { + if !bytes.Equal(req.CoordinatorContract, destinationContract.Bytes()) { + oc.lggr.Errorw("FunctionsContractTransmitter: non-uniform coordinator addresses in a batch - still sending to a single destination", + "requestID", hex.EncodeToString(req.RequestID), + "destinationContract", destinationContract, + "requestCoordinator", hex.EncodeToString(req.CoordinatorContract), + ) + } + } oc.lggr.Debugw("FunctionsContractTransmitter: ready", "nRequests", len(requests), "coordinatorContract", destinationContract.Hex()) } else { return fmt.Errorf("unsupported contract version: %d", oc.contractVersion) @@ -169,6 +185,9 @@ func parseTransmitted(log []byte) ([32]byte, uint32, error) { if err != nil { return [32]byte{}, 0, err } + if len(transmitted) < 2 { + return [32]byte{}, 0, errors.New("transmitted event log has too few arguments") + } configDigest := *abi.ConvertType(transmitted[0], new([32]byte)).(*[32]byte) epoch := *abi.ConvertType(transmitted[1], new(uint32)).(*uint32) return configDigest, epoch, err diff --git a/core/services/relay/evm/functions/contract_transmitter_test.go b/core/services/relay/evm/functions/contract_transmitter_test.go index fb4a071de2a..6b227bcdd50 100644 --- a/core/services/relay/evm/functions/contract_transmitter_test.go +++ b/core/services/relay/evm/functions/contract_transmitter_test.go @@ -116,6 +116,55 @@ func TestContractTransmitter_Transmit_V1(t *testing.T) { reportBytes, err := codec.EncodeReport(processedRequests) require.NoError(t, err) + // success require.NoError(t, ot.Transmit(testutils.Context(t), ocrtypes.ReportContext{}, reportBytes, []ocrtypes.AttributedOnchainSignature{})) require.Equal(t, coordinatorAddress, ocrTransmitter.toAddress) + + // failure on too many signatures + signatures := []ocrtypes.AttributedOnchainSignature{} + for i := 0; i < 33; i++ { + signatures = append(signatures, ocrtypes.AttributedOnchainSignature{}) + } + require.Error(t, ot.Transmit(testutils.Context(t), ocrtypes.ReportContext{}, reportBytes, signatures)) +} + +func TestContractTransmitter_Transmit_V1_CoordinatorMismatch(t *testing.T) { + t.Parallel() + + contractVersion := uint32(1) + configuredDestAddress, coordinatorAddress1, coordinatorAddress2 := testutils.NewAddress(), testutils.NewAddress(), testutils.NewAddress() + lggr := logger.TestLogger(t) + c := evmclimocks.NewClient(t) + lp := lpmocks.NewLogPoller(t) + contractABI, _ := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorABI)) + lp.On("RegisterFilter", mock.Anything).Return(nil) + + ocrTransmitter := mockTransmitter{} + ot, err := functions.NewFunctionsContractTransmitter(c, contractABI, &ocrTransmitter, lp, lggr, func(b []byte) (*txmgr.TxMeta, error) { + return &txmgr.TxMeta{}, nil + }, contractVersion) + require.NoError(t, err) + require.NoError(t, ot.UpdateRoutes(configuredDestAddress, configuredDestAddress)) + + reqId1, err := hex.DecodeString("110102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f") + require.NoError(t, err) + reqId2, err := hex.DecodeString("220102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f") + require.NoError(t, err) + processedRequests := []*encoding.ProcessedRequest{ + { + RequestID: reqId1, + CoordinatorContract: coordinatorAddress1.Bytes(), + }, + { + RequestID: reqId2, + CoordinatorContract: coordinatorAddress2.Bytes(), + }, + } + codec, err := encoding.NewReportCodec(contractVersion) + require.NoError(t, err) + reportBytes, err := codec.EncodeReport(processedRequests) + require.NoError(t, err) + + require.NoError(t, ot.Transmit(testutils.Context(t), ocrtypes.ReportContext{}, reportBytes, []ocrtypes.AttributedOnchainSignature{})) + require.Equal(t, coordinatorAddress1, ocrTransmitter.toAddress) } diff --git a/core/services/relay/evm/loop_impl.go b/core/services/relay/evm/loop_impl.go index 02a9194b380..8142721ed16 100644 --- a/core/services/relay/evm/loop_impl.go +++ b/core/services/relay/evm/loop_impl.go @@ -2,6 +2,7 @@ package evm import ( "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) @@ -10,7 +11,6 @@ import ( type LoopRelayAdapter interface { loop.Relayer Chain() evm.Chain - Default() bool } type LoopRelayer struct { loop.Relayer @@ -19,8 +19,8 @@ type LoopRelayer struct { var _ loop.Relayer = &LoopRelayer{} -func NewLoopRelayAdapter(r *Relayer, cs EVMChainRelayerExtender) *LoopRelayer { - ra := relay.NewRelayerAdapter(r, cs) +func NewLoopRelayServerAdapter(r *Relayer, cs EVMChainRelayerExtender) *LoopRelayer { + ra := relay.NewRelayerServerAdapter(r, cs) return &LoopRelayer{ Relayer: ra, ext: cs, @@ -30,7 +30,3 @@ func NewLoopRelayAdapter(r *Relayer, cs EVMChainRelayerExtender) *LoopRelayer { func (la *LoopRelayer) Chain() evm.Chain { return la.ext.Chain() } - -func (la *LoopRelayer) Default() bool { - return la.ext.Default() -} diff --git a/core/services/relay/evm/mercury/helpers_test.go b/core/services/relay/evm/mercury/helpers_test.go index 4a7b8f70d75..4e3587b5de6 100644 --- a/core/services/relay/evm/mercury/helpers_test.go +++ b/core/services/relay/evm/mercury/helpers_test.go @@ -175,7 +175,7 @@ func SetupTH(t *testing.T, feedID common.Hash) TestHarness { require.NoError(t, lp.Start(ctx)) t.Cleanup(func() { lp.Close() }) - eventBroadcaster.On("Subscribe", "insert_on_evm_logs", "").Return(subscription, nil) + eventBroadcaster.On("Subscribe", "evm.insert_on_logs", "").Return(subscription, nil) configPoller, err := NewConfigPoller(lggr, lp, verifierAddress, feedID, eventBroadcaster) require.NoError(t, err) diff --git a/core/services/relay/evm/mercury/persistence_manager.go b/core/services/relay/evm/mercury/persistence_manager.go index b8ae9bf72c0..9e8df72a155 100644 --- a/core/services/relay/evm/mercury/persistence_manager.go +++ b/core/services/relay/evm/mercury/persistence_manager.go @@ -94,11 +94,12 @@ func (pm *PersistenceManager) runFlushDeletesLoop() { ticker.Stop() return case <-ticker.C: - pm.lggr.Trace("Deleting queued requests from transmit requests table") queuedReqs := pm.resetDeleteQueue() if err := pm.orm.DeleteTransmitRequests(queuedReqs, pg.WithParentCtx(ctx)); err != nil { pm.lggr.Errorw("Failed to delete queued transmit requests", "err", err) pm.addToDeleteQueue(queuedReqs...) + } else { + pm.lggr.Debugw("Deleted queued transmit requests") } } } @@ -117,9 +118,10 @@ func (pm *PersistenceManager) runPruneLoop() { ticker.Stop() return case <-ticker.C: - pm.lggr.Trace("Pruning transmit requests table") if err := pm.orm.PruneTransmitRequests(pm.maxTransmitQueueSize, pg.WithParentCtx(ctx), pg.WithLongQueryTimeout()); err != nil { pm.lggr.Errorw("Failed to prune transmit requests table", "err", err) + } else { + pm.lggr.Debugw("Pruned transmit requests table") } } } diff --git a/core/services/relay/evm/mercury/persistence_manager_test.go b/core/services/relay/evm/mercury/persistence_manager_test.go index 211e2c20c32..97628ed9c2b 100644 --- a/core/services/relay/evm/mercury/persistence_manager_test.go +++ b/core/services/relay/evm/mercury/persistence_manager_test.go @@ -7,25 +7,28 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/stretchr/testify/require" + "go.uber.org/zap/zapcore" + "go.uber.org/zap/zaptest/observer" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" ) -func bootstrapPersistenceManager(t *testing.T) *PersistenceManager { +func bootstrapPersistenceManager(t *testing.T) (*PersistenceManager, *observer.ObservedLogs) { t.Helper() db := pgtest.NewSqlxDB(t) pgtest.MustExec(t, db, `SET CONSTRAINTS mercury_transmit_requests_job_id_fkey DEFERRED`) pgtest.MustExec(t, db, `SET CONSTRAINTS feed_latest_reports_job_id_fkey DEFERRED`) - lggr := logger.TestLogger(t) + lggr, observedLogs := logger.TestLoggerObserved(t, zapcore.DebugLevel) orm := NewORM(db, lggr, pgtest.NewQConfig(true)) - return NewPersistenceManager(lggr, orm, 0, 2, 10*time.Millisecond, 10*time.Millisecond) + return NewPersistenceManager(lggr, orm, 0, 2, 5*time.Millisecond, 5*time.Millisecond), observedLogs } func TestPersistenceManager(t *testing.T) { ctx := context.Background() - pm := bootstrapPersistenceManager(t) + pm, _ := bootstrapPersistenceManager(t) reports := sampleReports @@ -53,7 +56,7 @@ func TestPersistenceManager(t *testing.T) { func TestPersistenceManagerAsyncDelete(t *testing.T) { ctx := context.Background() - pm := bootstrapPersistenceManager(t) + pm, observedLogs := bootstrapPersistenceManager(t) reports := sampleReports @@ -67,7 +70,9 @@ func TestPersistenceManagerAsyncDelete(t *testing.T) { pm.AsyncDelete(&pb.TransmitRequest{Payload: reports[0]}) - time.Sleep(15 * time.Millisecond) + // Wait for next poll. + observedLogs.TakeAll() + testutils.WaitForLogMessage(t, observedLogs, "Deleted queued transmit requests") transmissions, err := pm.Load(ctx) require.NoError(t, err) @@ -92,7 +97,7 @@ func TestPersistenceManagerAsyncDelete(t *testing.T) { func TestPersistenceManagerPrune(t *testing.T) { ctx := context.Background() - pm := bootstrapPersistenceManager(t) + pm, observedLogs := bootstrapPersistenceManager(t) reports := sampleReports @@ -106,7 +111,9 @@ func TestPersistenceManagerPrune(t *testing.T) { err = pm.Start(ctx) require.NoError(t, err) - time.Sleep(15 * time.Millisecond) + // Wait for next poll. + observedLogs.TakeAll() + testutils.WaitForLogMessage(t, observedLogs, "Pruned transmit requests table") transmissions, err := pm.Load(ctx) require.NoError(t, err) diff --git a/core/services/relay/evm/mercury/transmitter.go b/core/services/relay/evm/mercury/transmitter.go index d259ab7a0ff..199dbfcdf88 100644 --- a/core/services/relay/evm/mercury/transmitter.go +++ b/core/services/relay/evm/mercury/transmitter.go @@ -76,7 +76,11 @@ type ConfigTracker interface { LatestConfigDetails(ctx context.Context) (changedInBlock uint64, configDigest ocrtypes.ConfigDigest, err error) } -var _ Transmitter = &mercuryTransmitter{} +type TransmitterReportDecoder interface { + BenchmarkPriceFromReport(report ocrtypes.Report) (*big.Int, error) +} + +var _ Transmitter = (*mercuryTransmitter)(nil) type mercuryTransmitter struct { utils.StartStopOnce @@ -84,6 +88,7 @@ type mercuryTransmitter struct { rpcClient wsrpc.Client cfgTracker ConfigTracker persistenceManager *PersistenceManager + codec TransmitterReportDecoder feedID mercuryutils.FeedID jobID int32 @@ -117,7 +122,7 @@ func getPayloadTypes() abi.Arguments { }) } -func NewTransmitter(lggr logger.Logger, cfgTracker ConfigTracker, rpcClient wsrpc.Client, fromAccount ed25519.PublicKey, jobID int32, feedID [32]byte, db *sqlx.DB, cfg pg.QConfig) *mercuryTransmitter { +func NewTransmitter(lggr logger.Logger, cfgTracker ConfigTracker, rpcClient wsrpc.Client, fromAccount ed25519.PublicKey, jobID int32, feedID [32]byte, db *sqlx.DB, cfg pg.QConfig, codec TransmitterReportDecoder) *mercuryTransmitter { feedIDHex := fmt.Sprintf("0x%x", feedID[:]) persistenceManager := NewPersistenceManager(lggr, NewORM(db, lggr, cfg), jobID, maxTransmitQueueSize, flushDeletesFrequency, pruneFrequency) return &mercuryTransmitter{ @@ -126,6 +131,7 @@ func NewTransmitter(lggr logger.Logger, cfgTracker ConfigTracker, rpcClient wsrp rpcClient, cfgTracker, persistenceManager, + codec, feedID, jobID, fmt.Sprintf("%x", fromAccount), @@ -322,18 +328,23 @@ func (mt *mercuryTransmitter) FetchInitialMaxFinalizedBlockNumber(ctx context.Co func (mt *mercuryTransmitter) LatestPrice(ctx context.Context, feedID [32]byte) (*big.Int, error) { mt.lggr.Trace("LatestPrice") - report, err := mt.latestReport(ctx, feedID) + fullReport, err := mt.latestReport(ctx, feedID) if err != nil { return nil, err } - if report == nil { + if fullReport == nil { return nil, nil } - price, err := relaymercury.DecodeValueInt192(report.Price) - if err != nil { - return nil, pkgerrors.Wrap(err, "failed to decode report.Price as *big.Int") + payload := fullReport.Payload + m := make(map[string]interface{}) + if err := PayloadTypes.UnpackIntoMap(m, payload); err != nil { + return nil, err + } + report, is := m["report"].([]byte) + if !is { + return nil, fmt.Errorf("expected report to be []byte, but it was %T", m["report"]) } - return price, nil + return mt.codec.BenchmarkPriceFromReport(report) } // LatestTimestamp will return -1, nil if the feed is missing diff --git a/core/services/relay/evm/mercury/transmitter_test.go b/core/services/relay/evm/mercury/transmitter_test.go index 247959609f9..6723ffcbcac 100644 --- a/core/services/relay/evm/mercury/transmitter_test.go +++ b/core/services/relay/evm/mercury/transmitter_test.go @@ -10,11 +10,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" + mercurytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/types" mocks "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" ) @@ -38,7 +39,7 @@ func Test_MercuryTransmitter_Transmit(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, jobID, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, jobID, sampleFeedID, db, pgtest.NewQConfig(true), nil) err := mt.Transmit(testutils.Context(t), sampleReportContext, report, sampleSigs) require.NoError(t, err) @@ -55,7 +56,7 @@ func Test_MercuryTransmitter_Transmit(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, jobID, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, jobID, sampleFeedID, db, pgtest.NewQConfig(true), nil) err := mt.Transmit(testutils.Context(t), sampleReportContext, report, sampleSigs) require.NoError(t, err) @@ -72,7 +73,7 @@ func Test_MercuryTransmitter_Transmit(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, jobID, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, jobID, sampleFeedID, db, pgtest.NewQConfig(true), nil) err := mt.Transmit(testutils.Context(t), sampleReportContext, report, sampleSigs) require.NoError(t, err) @@ -96,7 +97,7 @@ func Test_MercuryTransmitter_LatestTimestamp(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) ts, err := mt.LatestTimestamp(testutils.Context(t)) require.NoError(t, err) @@ -111,7 +112,7 @@ func Test_MercuryTransmitter_LatestTimestamp(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) ts, err := mt.LatestTimestamp(testutils.Context(t)) require.NoError(t, err) @@ -124,21 +125,33 @@ func Test_MercuryTransmitter_LatestTimestamp(t *testing.T) { return nil, errors.New("something exploded") }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) _, err := mt.LatestTimestamp(testutils.Context(t)) require.Error(t, err) assert.Contains(t, err.Error(), "something exploded") }) } +type mockCodec struct { + val *big.Int + err error +} + +var _ mercurytypes.ReportCodec = &mockCodec{} + +func (m *mockCodec) BenchmarkPriceFromReport(_ ocrtypes.Report) (*big.Int, error) { + return m.val, m.err +} + func Test_MercuryTransmitter_LatestPrice(t *testing.T) { t.Parallel() lggr := logger.TestLogger(t) db := pgtest.NewSqlxDB(t) + codec := new(mockCodec) + t.Run("successful query", func(t *testing.T) { originalPrice := big.NewInt(123456789) - encodedPrice, _ := relaymercury.EncodeValueInt192(originalPrice) c := mocks.MockWSRPCClient{ LatestReportF: func(ctx context.Context, in *pb.LatestReportRequest) (out *pb.LatestReportResponse, err error) { require.NotNil(t, in) @@ -146,15 +159,30 @@ func Test_MercuryTransmitter_LatestPrice(t *testing.T) { out = new(pb.LatestReportResponse) out.Report = new(pb.Report) out.Report.FeedId = sampleFeedID[:] - out.Report.Price = encodedPrice + out.Report.Payload = buildSamplePayload([]byte("doesn't matter")) return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) - price, err := mt.LatestPrice(testutils.Context(t), sampleFeedID) - require.NoError(t, err) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), codec) + + t.Run("BenchmarkPriceFromReport succeeds", func(t *testing.T) { + codec.val = originalPrice + codec.err = nil + + price, err := mt.LatestPrice(testutils.Context(t), sampleFeedID) + require.NoError(t, err) + + assert.Equal(t, originalPrice, price) + }) + t.Run("BenchmarkPriceFromReport fails", func(t *testing.T) { + codec.val = nil + codec.err = errors.New("something exploded") + + _, err := mt.LatestPrice(testutils.Context(t), sampleFeedID) + require.Error(t, err) - assert.Equal(t, price, originalPrice) + assert.EqualError(t, err, "something exploded") + }) }) t.Run("successful query returning nil report (new feed)", func(t *testing.T) { @@ -165,7 +193,7 @@ func Test_MercuryTransmitter_LatestPrice(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) price, err := mt.LatestPrice(testutils.Context(t), sampleFeedID) require.NoError(t, err) @@ -178,7 +206,7 @@ func Test_MercuryTransmitter_LatestPrice(t *testing.T) { return nil, errors.New("something exploded") }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) _, err := mt.LatestPrice(testutils.Context(t), sampleFeedID) require.Error(t, err) assert.Contains(t, err.Error(), "something exploded") @@ -203,7 +231,7 @@ func Test_MercuryTransmitter_FetchInitialMaxFinalizedBlockNumber(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) bn, err := mt.FetchInitialMaxFinalizedBlockNumber(testutils.Context(t)) require.NoError(t, err) @@ -218,7 +246,7 @@ func Test_MercuryTransmitter_FetchInitialMaxFinalizedBlockNumber(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) bn, err := mt.FetchInitialMaxFinalizedBlockNumber(testutils.Context(t)) require.NoError(t, err) @@ -230,7 +258,7 @@ func Test_MercuryTransmitter_FetchInitialMaxFinalizedBlockNumber(t *testing.T) { return nil, errors.New("something exploded") }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) _, err := mt.FetchInitialMaxFinalizedBlockNumber(testutils.Context(t)) require.Error(t, err) assert.Contains(t, err.Error(), "something exploded") @@ -247,7 +275,7 @@ func Test_MercuryTransmitter_FetchInitialMaxFinalizedBlockNumber(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) _, err := mt.FetchInitialMaxFinalizedBlockNumber(testutils.Context(t)) require.Error(t, err) assert.Contains(t, err.Error(), "latestReport failed; mismatched feed IDs, expected: 0x1c916b4aa7e57ca7b68ae1bf45653f56b656fd3aa335ef7fae696b663f1b8472, got: 0x") diff --git a/core/services/relay/evm/mercury/types/types.go b/core/services/relay/evm/mercury/types/types.go index 6affba58169..ca266ca8ccd 100644 --- a/core/services/relay/evm/mercury/types/types.go +++ b/core/services/relay/evm/mercury/types/types.go @@ -2,6 +2,11 @@ package types import ( "context" + "math/big" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" @@ -17,3 +22,22 @@ type ChainHeadTracker interface { type DataSourceORM interface { LatestReport(ctx context.Context, feedID [32]byte, qopts ...pg.QOpt) (report []byte, err error) } + +type ReportCodec interface { + BenchmarkPriceFromReport(report ocrtypes.Report) (*big.Int, error) +} + +var ( + PriceFeedMissingCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "mercury_price_feed_missing", + Help: "Running count of times mercury tried to query a price feed for billing from mercury server, but it was missing", + }, + []string{"queriedFeedID"}, + ) + PriceFeedErrorCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "mercury_price_feed_errors", + Help: "Running count of times mercury tried to query a price feed for billing from mercury server, but got an error", + }, + []string{"queriedFeedID"}, + ) +) diff --git a/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go index a28186cce9c..fefddd6395b 100644 --- a/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go +++ b/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "math" + "math/big" "github.com/ethereum/go-ethereum/common" pkgerrors "github.com/pkg/errors" @@ -89,3 +90,11 @@ func (r *ReportCodec) ValidFromBlockNumFromReport(report ocrtypes.Report) (int64 func (r *ReportCodec) Decode(report ocrtypes.Report) (*reporttypes.Report, error) { return reporttypes.Decode(report) } + +func (r *ReportCodec) BenchmarkPriceFromReport(report ocrtypes.Report) (*big.Int, error) { + decoded, err := r.Decode(report) + if err != nil { + return nil, err + } + return decoded.BenchmarkPrice, nil +} diff --git a/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go b/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go index 6e6a58af4ca..3f4838c3e7c 100644 --- a/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go +++ b/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go @@ -161,3 +161,22 @@ func Test_ReportCodec_ValidFromBlockNumFromReport(t *testing.T) { assert.Contains(t, err.Error(), "ValidFromBlockNum=18446744073709551615 overflows max int64") }) } + +func Test_ReportCodec_BenchmarkPriceFromReport(t *testing.T) { + r := ReportCodec{} + feedID := utils.NewHash() + + t.Run("BenchmarkPriceFromReport extracts the benchmark price from valid report", func(t *testing.T) { + report := buildSampleReport(42, 999, feedID) + + bp, err := r.BenchmarkPriceFromReport(report) + require.NoError(t, err) + + assert.Equal(t, big.NewInt(242), bp) + }) + t.Run("BenchmarkPriceFromReport errors on invalid report", func(t *testing.T) { + _, err := r.BenchmarkPriceFromReport([]byte{1, 2, 3}) + require.Error(t, err) + assert.EqualError(t, err, "failed to decode report: abi: cannot marshal in to go type: length insufficient 3 require 32") + }) +} diff --git a/core/services/relay/evm/mercury/v2/data_source.go b/core/services/relay/evm/mercury/v2/data_source.go index ecf0fd60a82..25fe279dd43 100644 --- a/core/services/relay/evm/mercury/v2/data_source.go +++ b/core/services/relay/evm/mercury/v2/data_source.go @@ -18,6 +18,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/types" + mercurytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/types" mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v2/reportcodec" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -117,8 +118,11 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam defer wg.Done() obs.LinkPrice.Val, obs.LinkPrice.Err = ds.fetcher.LatestPrice(ctx, ds.linkFeedID) if obs.LinkPrice.Val == nil && obs.LinkPrice.Err == nil { + mercurytypes.PriceFeedMissingCount.WithLabelValues(ds.linkFeedID.String()).Inc() ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing LINK feed, using sentinel value of %s", relaymercuryv2.MissingPrice), "linkFeedID", ds.linkFeedID) obs.LinkPrice.Val = relaymercuryv2.MissingPrice + } else if obs.LinkPrice.Err != nil { + mercurytypes.PriceFeedErrorCount.WithLabelValues(ds.linkFeedID.String()).Inc() } }() } @@ -131,8 +135,11 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam defer wg.Done() obs.NativePrice.Val, obs.NativePrice.Err = ds.fetcher.LatestPrice(ctx, ds.nativeFeedID) if obs.NativePrice.Val == nil && obs.NativePrice.Err == nil { + mercurytypes.PriceFeedMissingCount.WithLabelValues(ds.nativeFeedID.String()).Inc() ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing native feed, using sentinel value of %s", relaymercuryv2.MissingPrice), "nativeFeedID", ds.nativeFeedID) obs.NativePrice.Val = relaymercuryv2.MissingPrice + } else if obs.NativePrice.Err != nil { + mercurytypes.PriceFeedErrorCount.WithLabelValues(ds.nativeFeedID.String()).Inc() } }() } diff --git a/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go index 60dde81f1cb..0e1dfe9c46f 100644 --- a/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go +++ b/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go @@ -67,3 +67,11 @@ func (r *ReportCodec) ObservationTimestampFromReport(report ocrtypes.Report) (ui func (r *ReportCodec) Decode(report ocrtypes.Report) (*reporttypes.Report, error) { return reporttypes.Decode(report) } + +func (r *ReportCodec) BenchmarkPriceFromReport(report ocrtypes.Report) (*big.Int, error) { + decoded, err := r.Decode(report) + if err != nil { + return nil, err + } + return decoded.BenchmarkPrice, nil +} diff --git a/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go b/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go index c0c931dfe3a..8cf16a5dab4 100644 --- a/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go +++ b/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go @@ -132,3 +132,21 @@ func Test_ReportCodec_ObservationTimestampFromReport(t *testing.T) { assert.EqualError(t, err, "failed to decode report: abi: cannot marshal in to go type: length insufficient 3 require 32") }) } + +func Test_ReportCodec_BenchmarkPriceFromReport(t *testing.T) { + r := ReportCodec{} + + t.Run("BenchmarkPriceFromReport extracts the benchmark price from valid report", func(t *testing.T) { + report := buildSampleReport(123) + + bp, err := r.BenchmarkPriceFromReport(report) + require.NoError(t, err) + + assert.Equal(t, big.NewInt(242), bp) + }) + t.Run("BenchmarkPriceFromReport errors on invalid report", func(t *testing.T) { + _, err := r.BenchmarkPriceFromReport([]byte{1, 2, 3}) + require.Error(t, err) + assert.EqualError(t, err, "failed to decode report: abi: cannot marshal in to go type: length insufficient 3 require 32") + }) +} diff --git a/core/services/relay/evm/mercury/v3/data_source.go b/core/services/relay/evm/mercury/v3/data_source.go index 7c12ffe8237..d325f70a002 100644 --- a/core/services/relay/evm/mercury/v3/data_source.go +++ b/core/services/relay/evm/mercury/v3/data_source.go @@ -19,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/types" + mercurytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/types" mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v3/reportcodec" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -120,8 +121,11 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam defer wg.Done() obs.LinkPrice.Val, obs.LinkPrice.Err = ds.fetcher.LatestPrice(ctx, ds.linkFeedID) if obs.LinkPrice.Val == nil && obs.LinkPrice.Err == nil { + mercurytypes.PriceFeedMissingCount.WithLabelValues(ds.linkFeedID.String()).Inc() ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing LINK feed, using sentinel value of %s", relaymercuryv3.MissingPrice), "linkFeedID", ds.linkFeedID) obs.LinkPrice.Val = relaymercuryv3.MissingPrice + } else if obs.LinkPrice.Err != nil { + mercurytypes.PriceFeedErrorCount.WithLabelValues(ds.linkFeedID.String()).Inc() } }() } @@ -134,8 +138,11 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam defer wg.Done() obs.NativePrice.Val, obs.NativePrice.Err = ds.fetcher.LatestPrice(ctx, ds.nativeFeedID) if obs.NativePrice.Val == nil && obs.NativePrice.Err == nil { + mercurytypes.PriceFeedMissingCount.WithLabelValues(ds.nativeFeedID.String()).Inc() ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing native feed, using sentinel value of %s", relaymercuryv3.MissingPrice), "nativeFeedID", ds.nativeFeedID) obs.NativePrice.Val = relaymercuryv3.MissingPrice + } else if obs.NativePrice.Err != nil { + mercurytypes.PriceFeedErrorCount.WithLabelValues(ds.nativeFeedID.String()).Inc() } }() } diff --git a/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go index 66995e74ea7..4c0b3756d7b 100644 --- a/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go +++ b/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go @@ -74,3 +74,11 @@ func (r *ReportCodec) ObservationTimestampFromReport(report ocrtypes.Report) (ui func (r *ReportCodec) Decode(report ocrtypes.Report) (*reporttypes.Report, error) { return reporttypes.Decode(report) } + +func (r *ReportCodec) BenchmarkPriceFromReport(report ocrtypes.Report) (*big.Int, error) { + decoded, err := r.Decode(report) + if err != nil { + return nil, err + } + return decoded.BenchmarkPrice, nil +} diff --git a/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go b/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go index 80cf4c9665b..98b81edb002 100644 --- a/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go +++ b/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go @@ -140,3 +140,21 @@ func Test_ReportCodec_ObservationTimestampFromReport(t *testing.T) { assert.EqualError(t, err, "failed to decode report: abi: cannot marshal in to go type: length insufficient 3 require 32") }) } + +func Test_ReportCodec_BenchmarkPriceFromReport(t *testing.T) { + r := ReportCodec{} + + t.Run("BenchmarkPriceFromReport extracts the benchmark price from valid report", func(t *testing.T) { + report := buildSampleReport(123) + + bp, err := r.BenchmarkPriceFromReport(report) + require.NoError(t, err) + + assert.Equal(t, big.NewInt(242), bp) + }) + t.Run("BenchmarkPriceFromReport errors on invalid report", func(t *testing.T) { + _, err := r.BenchmarkPriceFromReport([]byte{1, 2, 3}) + require.Error(t, err) + assert.EqualError(t, err, "failed to decode report: abi: cannot marshal in to go type: length insufficient 3 require 32") + }) +} diff --git a/core/services/relay/evm/mercury_provider.go b/core/services/relay/evm/mercury_provider.go index ee32b8d99be..74072167061 100644 --- a/core/services/relay/evm/mercury_provider.go +++ b/core/services/relay/evm/mercury_provider.go @@ -4,13 +4,15 @@ import ( "context" "errors" + "golang.org/x/exp/maps" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" relaymercuryv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" relaymercuryv2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" relaymercuryv3 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v3" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "golang.org/x/exp/maps" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services" @@ -96,6 +98,10 @@ func (p *mercuryProvider) ReportCodecV3() relaymercuryv3.ReportCodec { return p.reportCodecV3 } -func (p *mercuryProvider) ContractTransmitter() relaymercury.Transmitter { +func (p *mercuryProvider) ContractTransmitter() ocrtypes.ContractTransmitter { + return p.transmitter +} + +func (p *mercuryProvider) MercuryServerFetcher() relaymercury.MercuryServerFetcher { return p.transmitter } diff --git a/core/services/relay/evm/mocks/loop_relay_adapter.go b/core/services/relay/evm/mocks/loop_relay_adapter.go index 7ed28ac4b11..11150874b9e 100644 --- a/core/services/relay/evm/mocks/loop_relay_adapter.go +++ b/core/services/relay/evm/mocks/loop_relay_adapter.go @@ -47,20 +47,6 @@ func (_m *LoopRelayAdapter) Close() error { return r0 } -// Default provides a mock function with given fields: -func (_m *LoopRelayAdapter) Default() bool { - ret := _m.Called() - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - // GetChainStatus provides a mock function with given fields: ctx func (_m *LoopRelayAdapter) GetChainStatus(ctx context.Context) (types.ChainStatus, error) { ret := _m.Called(ctx) @@ -181,72 +167,20 @@ func (_m *LoopRelayAdapter) NewConfigProvider(_a0 context.Context, _a1 types.Rel return r0, r1 } -// NewFunctionsProvider provides a mock function with given fields: _a0, _a1, _a2 -func (_m *LoopRelayAdapter) NewFunctionsProvider(_a0 context.Context, _a1 types.RelayArgs, _a2 types.PluginArgs) (types.FunctionsProvider, error) { - ret := _m.Called(_a0, _a1, _a2) - - var r0 types.FunctionsProvider - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) (types.FunctionsProvider, error)); ok { - return rf(_a0, _a1, _a2) - } - if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) types.FunctionsProvider); ok { - r0 = rf(_a0, _a1, _a2) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(types.FunctionsProvider) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, types.RelayArgs, types.PluginArgs) error); ok { - r1 = rf(_a0, _a1, _a2) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NewMedianProvider provides a mock function with given fields: _a0, _a1, _a2 -func (_m *LoopRelayAdapter) NewMedianProvider(_a0 context.Context, _a1 types.RelayArgs, _a2 types.PluginArgs) (types.MedianProvider, error) { - ret := _m.Called(_a0, _a1, _a2) - - var r0 types.MedianProvider - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) (types.MedianProvider, error)); ok { - return rf(_a0, _a1, _a2) - } - if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) types.MedianProvider); ok { - r0 = rf(_a0, _a1, _a2) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(types.MedianProvider) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, types.RelayArgs, types.PluginArgs) error); ok { - r1 = rf(_a0, _a1, _a2) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NewMercuryProvider provides a mock function with given fields: _a0, _a1, _a2 -func (_m *LoopRelayAdapter) NewMercuryProvider(_a0 context.Context, _a1 types.RelayArgs, _a2 types.PluginArgs) (types.MercuryProvider, error) { +// NewPluginProvider provides a mock function with given fields: _a0, _a1, _a2 +func (_m *LoopRelayAdapter) NewPluginProvider(_a0 context.Context, _a1 types.RelayArgs, _a2 types.PluginArgs) (types.PluginProvider, error) { ret := _m.Called(_a0, _a1, _a2) - var r0 types.MercuryProvider + var r0 types.PluginProvider var r1 error - if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) (types.MercuryProvider, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) (types.PluginProvider, error)); ok { return rf(_a0, _a1, _a2) } - if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) types.MercuryProvider); ok { + if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) types.PluginProvider); ok { r0 = rf(_a0, _a1, _a2) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(types.MercuryProvider) + r0 = ret.Get(0).(types.PluginProvider) } } diff --git a/core/services/relay/evm/relayer_extender.go b/core/services/relay/evm/relayer_extender.go index c71ccd03b25..592c9bacee2 100644 --- a/core/services/relay/evm/relayer_extender.go +++ b/core/services/relay/evm/relayer_extender.go @@ -22,9 +22,6 @@ var ErrNoChains = errors.New("no EVM chains loaded") type EVMChainRelayerExtender interface { relay.RelayerExt Chain() evmchain.Chain - Default() bool - // compatibility remove after BCF-2441 - NodeStatuses(ctx context.Context, offset, limit int, chainIDs ...string) (nodes []relaytypes.NodeStatus, count int, err error) } type EVMChainRelayerExtenderSlicer interface { @@ -42,18 +39,10 @@ var _ EVMChainRelayerExtenderSlicer = &ChainRelayerExtenders{} func NewLegacyChainsFromRelayerExtenders(exts EVMChainRelayerExtenderSlicer) *evmchain.LegacyChains { m := make(map[string]evmchain.Chain) - var dflt evmchain.Chain for _, r := range exts.Slice() { m[r.Chain().ID().String()] = r.Chain() - if r.Default() { - dflt = r.Chain() - } - } - l := evmchain.NewLegacyChains(m, exts.AppConfig().EVMConfigs()) - if dflt != nil { - l.SetDefault(dflt) } - return l + return evmchain.NewLegacyChains(m, exts.AppConfig().EVMConfigs()) } func newChainRelayerExtsFromSlice(exts []*ChainRelayerExt, appConfig evm.AppConfig) *ChainRelayerExtenders { @@ -81,8 +70,7 @@ func (c *ChainRelayerExtenders) Len() int { // implements OneChain type ChainRelayerExt struct { - chain evmchain.Chain - isDefault bool + chain evmchain.Chain } var _ EVMChainRelayerExtender = &ChainRelayerExt{} @@ -107,10 +95,6 @@ func (s *ChainRelayerExt) Chain() evmchain.Chain { return s.chain } -func (s *ChainRelayerExt) Default() bool { - return s.isDefault -} - var ErrCorruptEVMChain = errors.New("corrupt evm chain") func (s *ChainRelayerExt) Start(ctx context.Context) error { @@ -133,32 +117,6 @@ func (s *ChainRelayerExt) Ready() (err error) { return s.chain.Ready() } -var ErrInconsistentChainRelayerExtender = errors.New("inconsistent evm chain relayer extender") - -func (s *ChainRelayerExt) NodeStatuses(ctx context.Context, offset, limit int, chainIDs ...string) (nodes []relaytypes.NodeStatus, total int, err error) { - if len(chainIDs) > 1 { - return nil, -1, fmt.Errorf("single chain chain set only support one chain id. got %v", chainIDs) - } - cid := chainIDs[0] - if cid != s.chain.ID().String() { - return nil, -1, fmt.Errorf("unknown chain id %s. expected %s", cid, s.chain.ID()) - } - nodes, _, total, err = s.ListNodeStatuses(ctx, int32(limit), "") - if err != nil { - return nil, -1, err - } - if len(nodes) < offset { - return []relaytypes.NodeStatus{}, -1, fmt.Errorf("out of range") - } - if limit <= 0 { - limit = len(nodes) - } else if len(nodes) < limit { - limit = len(nodes) - } - return nodes[offset:limit], total, nil - -} - func NewChainRelayerExtenders(ctx context.Context, opts evmchain.ChainRelayExtenderConfig) (*ChainRelayerExtenders, error) { if err := opts.Check(); err != nil { return nil, err @@ -179,14 +137,6 @@ func NewChainRelayerExtenders(ctx context.Context, opts evmchain.ChainRelayExten } } - defaultChainID := opts.AppConfig.DefaultChainID() - if defaultChainID == nil && len(enabled) >= 1 { - defaultChainID = enabled[0].ChainID.ToInt() - if len(enabled) > 1 { - opts.Logger.Debugf("Multiple chains present, default chain: %s", defaultChainID.String()) - } - } - var result []*ChainRelayerExt var err error for i := range enabled { @@ -207,8 +157,7 @@ func NewChainRelayerExtenders(ctx context.Context, opts evmchain.ChainRelayExten } s := &ChainRelayerExt{ - chain: chain, - isDefault: (cid == defaultChainID.String()), + chain: chain, } result = append(result, s) } diff --git a/core/services/relay/evm/relayer_extender_test.go b/core/services/relay/evm/relayer_extender_test.go index 6caf8472478..361a7468f30 100644 --- a/core/services/relay/evm/relayer_extender_test.go +++ b/core/services/relay/evm/relayer_extender_test.go @@ -66,15 +66,4 @@ func TestChainRelayExtenders(t *testing.T) { assert.NotEmpty(t, s) assert.NoError(t, err) - // test error conditions for NodeStatuses - nstats, cnt, err := relayExt.NodeStatuses(testutils.Context(t), 0, 0, cltest.FixtureChainID.String(), "error, only one chain supported") - assert.Error(t, err) - assert.Nil(t, nstats) - assert.Equal(t, -1, cnt) - - nstats, cnt, err = relayExt.NodeStatuses(testutils.Context(t), 0, 0, "not the chain id") - assert.Error(t, err) - assert.Nil(t, nstats) - assert.Equal(t, -1, cnt) - } diff --git a/core/services/relay/relay.go b/core/services/relay/relay.go index fccd69c411e..c96abb4b8c8 100644 --- a/core/services/relay/relay.go +++ b/core/services/relay/relay.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "regexp" - "strconv" "golang.org/x/exp/maps" @@ -14,7 +13,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services" ) -type Network string +type Network = string +type ChainID = string var ( EVM Network = "evm" @@ -36,29 +36,14 @@ type ID struct { } func (i *ID) Name() string { - return fmt.Sprintf("%s.%s", i.Network, i.ChainID.String()) + return fmt.Sprintf("%s.%s", i.Network, i.ChainID) } func (i *ID) String() string { return i.Name() } -func NewID(n Network, c ChainID) (ID, error) { - id := ID{Network: n, ChainID: c} - err := id.validate() - if err != nil { - return ID{}, err - } - return id, nil -} -func (i *ID) validate() error { - // the only validation is to ensure that EVM chain ids are compatible with int64 - if i.Network == EVM { - _, err := i.ChainID.Int64() - if err != nil { - return fmt.Errorf("RelayIdentifier invalid: EVM relayer must have integer-compatible chain ID: %w", err) - } - } - return nil +func NewID(n Network, c ChainID) ID { + return ID{Network: n, ChainID: c} } var idRegex = regexp.MustCompile( @@ -88,19 +73,6 @@ func (i *ID) UnmarshalString(s string) error { return nil } -type ChainID string - -func (c ChainID) String() string { - return string(c) -} -func (c ChainID) Int64() (int64, error) { - i, err := strconv.Atoi(c.String()) - if err != nil { - return int64(0), err - } - return int64(i), nil -} - // RelayerExt is a subset of [loop.Relayer] for adapting [types.Relayer], typically with a Chain. See [relayerAdapter]. type RelayerExt interface { types.ChainService @@ -112,12 +84,12 @@ var _ loop.Relayer = (*relayerAdapter)(nil) // relayerAdapter adapts a [types.Relayer] and [RelayerExt] to implement [loop.Relayer]. type relayerAdapter struct { types.Relayer - // TODO we can un-embedded `ext` once BFC-2441 is merged. Right now that's not possible - // because this are conflicting definitions of SendTx RelayerExt } // NewRelayerAdapter returns a [loop.Relayer] adapted from a [types.Relayer] and [RelayerExt]. +// Unlike NewRelayerServerAdapter which is used to adapt non-LOOPP relayers, this is used to adapt +// LOOPP-based relayer which are then server over GRPC (by the relayerServer). func NewRelayerAdapter(r types.Relayer, e RelayerExt) loop.Relayer { return &relayerAdapter{Relayer: r, RelayerExt: e} } @@ -138,6 +110,10 @@ func (r *relayerAdapter) NewFunctionsProvider(ctx context.Context, rargs types.R return r.Relayer.NewFunctionsProvider(rargs, pargs) } +func (r *relayerAdapter) NewPluginProvider(ctx context.Context, rargs types.RelayArgs, pargs types.PluginArgs) (types.PluginProvider, error) { + return nil, fmt.Errorf("unexpected call to NewPluginProvider: did you forget to wrap relayerAdapter in a relayerServerAdapter?") +} + func (r *relayerAdapter) Start(ctx context.Context) error { var ms services.MultiStart return ms.Start(ctx, r.RelayerExt, r.Relayer) @@ -184,3 +160,33 @@ func (r *relayerAdapter) NodeStatuses(ctx context.Context, offset, limit int, ch } return nodes[offset:limit], total, nil } + +type relayerServerAdapter struct { + *relayerAdapter +} + +func (r *relayerServerAdapter) NewPluginProvider(ctx context.Context, rargs types.RelayArgs, pargs types.PluginArgs) (types.PluginProvider, error) { + switch types.OCR2PluginType(rargs.ProviderType) { + case types.Median: + return r.NewMedianProvider(ctx, rargs, pargs) + case types.Functions: + return r.NewFunctionsProvider(ctx, rargs, pargs) + case types.Mercury: + return r.NewMercuryProvider(ctx, rargs, pargs) + case types.DKG, types.OCR2VRF, types.OCR2Keeper, types.GenericPlugin: + return r.relayerAdapter.NewPluginProvider(ctx, rargs, pargs) + } + + return nil, fmt.Errorf("provider type not supported: %s", rargs.ProviderType) +} + +// NewRelayerServerAdapter returns a [loop.Relayer] adapted from a [types.Relayer] and [RelayerExt]. +// Unlike NewRelayerAdapter, this behaves like the loop `RelayerServer` and dispatches calls +// to `NewPluginProvider` according to the passed in `RelayArgs.ProviderType`. +// This should only be used to adapt relayers not running via GRPC in a LOOPP. +// +// nolint:staticcheck // SA1019 +func NewRelayerServerAdapter(r types.Relayer, e RelayerExt) loop.Relayer { + ra := &relayerAdapter{Relayer: r, RelayerExt: e} + return &relayerServerAdapter{relayerAdapter: ra} +} diff --git a/core/services/relay/relay_test.go b/core/services/relay/relay_test.go index 0ed14b6c5b7..28ee0172c20 100644 --- a/core/services/relay/relay_test.go +++ b/core/services/relay/relay_test.go @@ -1,9 +1,12 @@ package relay import ( + "context" "testing" "github.com/stretchr/testify/assert" + + "github.com/smartcontractkit/chainlink-relay/pkg/types" ) func TestIdentifier_UnmarshalString(t *testing.T) { @@ -48,34 +51,91 @@ func TestIdentifier_UnmarshalString(t *testing.T) { } func TestNewID(t *testing.T) { - type args struct { - n Network - c ChainID - } - tests := []struct { - name string - args args - want ID - wantErr bool + rid := NewID(EVM, "chain id") + assert.Equal(t, EVM, rid.Network) + assert.Equal(t, "chain id", rid.ChainID) +} + +type staticMedianProvider struct { + types.MedianProvider +} + +type staticFunctionsProvider struct { + types.FunctionsProvider +} + +type staticMercuryProvider struct { + types.MercuryProvider +} + +type mockRelayer struct { + types.Relayer +} + +func (m *mockRelayer) NewMedianProvider(rargs types.RelayArgs, pargs types.PluginArgs) (types.MedianProvider, error) { + return staticMedianProvider{}, nil +} + +func (m *mockRelayer) NewFunctionsProvider(rargs types.RelayArgs, pargs types.PluginArgs) (types.FunctionsProvider, error) { + return staticFunctionsProvider{}, nil +} + +func (m *mockRelayer) NewMercuryProvider(rargs types.RelayArgs, pargs types.PluginArgs) (types.MercuryProvider, error) { + return staticMercuryProvider{}, nil +} + +type mockRelayerExt struct { + RelayerExt +} + +func isType[T any](p any) bool { + _, ok := p.(T) + return ok +} + +func TestRelayerServerAdapter(t *testing.T) { + r := &mockRelayer{} + sa := NewRelayerServerAdapter(r, mockRelayerExt{}) + + testCases := []struct { + ProviderType string + Test func(p any) bool + Error string }{ - {name: "good evm", - args: args{n: EVM, c: "1"}, - want: ID{Network: EVM, ChainID: "1"}, + { + ProviderType: string(types.Median), + Test: isType[types.MedianProvider], }, - {name: "bad evm", - args: args{n: EVM, c: "not a number"}, - want: ID{}, - wantErr: true, + { + ProviderType: string(types.Functions), + Test: isType[types.FunctionsProvider], + }, + { + ProviderType: string(types.Mercury), + Test: isType[types.MercuryProvider], + }, + { + ProviderType: "unknown", + Error: "provider type not supported", + }, + { + ProviderType: string(types.GenericPlugin), + Error: "unexpected call to NewPluginProvider", }, } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := NewID(tt.args.n, tt.args.c) - if (err != nil) != tt.wantErr { - t.Errorf("NewID() error = %v, wantErr %v", err, tt.wantErr) - return - } - assert.Equal(t, tt.want, got, "got id %v", got) - }) + + for _, tc := range testCases { + pp, err := sa.NewPluginProvider( + context.Background(), + types.RelayArgs{ProviderType: tc.ProviderType}, + types.PluginArgs{}, + ) + + if tc.Error != "" { + assert.ErrorContains(t, err, tc.Error) + } else { + assert.NoError(t, err) + assert.True(t, tc.Test(pp)) + } } } diff --git a/core/services/s4/envelope.go b/core/services/s4/envelope.go index 07e4201341c..5c917e7ebda 100644 --- a/core/services/s4/envelope.go +++ b/core/services/s4/envelope.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -62,7 +63,12 @@ func (e Envelope) ToJson() ([]byte, error) { if err != nil { return nil, err } - payload, err := json.Marshal(e.Payload) + nonNilPayload := e.Payload + if nonNilPayload == nil { + // prevent unwanted "null" values in JSON representation + nonNilPayload = []byte{} + } + payload, err := json.Marshal(nonNilPayload) if err != nil { return nil, err } diff --git a/core/services/s4/errors.go b/core/services/s4/errors.go index 408903254bb..aa447f88f39 100644 --- a/core/services/s4/errors.go +++ b/core/services/s4/errors.go @@ -3,10 +3,11 @@ package s4 import "errors" var ( - ErrNotFound = errors.New("not found") - ErrWrongSignature = errors.New("wrong signature") - ErrSlotIdTooBig = errors.New("slot id is too big") - ErrPayloadTooBig = errors.New("payload is too big") - ErrPastExpiration = errors.New("past expiration") - ErrVersionTooLow = errors.New("version too low") + ErrNotFound = errors.New("not found") + ErrWrongSignature = errors.New("wrong signature") + ErrSlotIdTooBig = errors.New("slot id is too big") + ErrPayloadTooBig = errors.New("payload is too big") + ErrPastExpiration = errors.New("past expiration") + ErrVersionTooLow = errors.New("version too low") + ErrExpirationTooLong = errors.New("expiration too long") ) diff --git a/core/services/s4/postgres_orm.go b/core/services/s4/postgres_orm.go index e562273d33a..d0a79dba959 100644 --- a/core/services/s4/postgres_orm.go +++ b/core/services/s4/postgres_orm.go @@ -71,7 +71,7 @@ RETURNING id;`, o.tableName) if errors.Is(err, sql.ErrNoRows) { return ErrVersionTooLow } - return nil + return err } func (o orm) DeleteExpired(limit uint, utcNow time.Time, qopts ...pg.QOpt) (int64, error) { diff --git a/core/services/s4/postgres_orm_test.go b/core/services/s4/postgres_orm_test.go index fdfa007f705..c233fe2361a 100644 --- a/core/services/s4/postgres_orm_test.go +++ b/core/services/s4/postgres_orm_test.go @@ -2,6 +2,7 @@ package s4_test import ( "errors" + "math" "testing" "time" @@ -257,3 +258,22 @@ func TestPostgresORM_Namespace(t *testing.T) { assert.NoError(t, err) assert.Len(t, snapshotA, n) } + +func TestPostgresORM_BigIntVersion(t *testing.T) { + t.Parallel() + + orm := setupORM(t, "test") + row := generateTestRows(t, 1)[0] + row.Version = math.MaxUint64 - 10 + + err := orm.Update(row) + assert.NoError(t, err) + + row.Version++ + err = orm.Update(row) + assert.NoError(t, err) + + gotRow, err := orm.Get(row.Address, row.SlotId) + assert.NoError(t, err) + assert.Equal(t, row, gotRow) +} diff --git a/core/services/s4/storage.go b/core/services/s4/storage.go index d90c7a4ead7..2a2a4ffcdd4 100644 --- a/core/services/s4/storage.go +++ b/core/services/s4/storage.go @@ -12,8 +12,9 @@ import ( // Constraints specifies the global storage constraints. type Constraints struct { - MaxPayloadSizeBytes uint `json:"maxPayloadSizeBytes"` - MaxSlotsPerUser uint `json:"maxSlotsPerUser"` + MaxPayloadSizeBytes uint `json:"maxPayloadSizeBytes"` + MaxSlotsPerUser uint `json:"maxSlotsPerUser"` + MaxExpirationLengthSec uint64 `json:"maxExpirationLengthSec"` } // Key identifies a versioned user record. @@ -128,9 +129,13 @@ func (s *storage) Put(ctx context.Context, key *Key, record *Record, signature [ if len(record.Payload) > int(s.contraints.MaxPayloadSizeBytes) { return ErrPayloadTooBig } - if s.clock.Now().UnixMilli() > record.Expiration { + now := s.clock.Now().UnixMilli() + if now > record.Expiration { return ErrPastExpiration } + if record.Expiration-now > int64(s.contraints.MaxExpirationLengthSec)*1000 { + return ErrExpirationTooLong + } envelope := NewEnvelopeFromRecord(key, record) signer, err := envelope.GetSignerAddress(signature) diff --git a/core/services/s4/storage_test.go b/core/services/s4/storage_test.go index 1a56e3d5710..6c384d493bf 100644 --- a/core/services/s4/storage_test.go +++ b/core/services/s4/storage_test.go @@ -17,8 +17,9 @@ import ( var ( constraints = s4.Constraints{ - MaxSlotsPerUser: 5, - MaxPayloadSizeBytes: 32, + MaxSlotsPerUser: 5, + MaxPayloadSizeBytes: 32, + MaxExpirationLengthSec: 3600, } ) @@ -100,6 +101,20 @@ func TestStorage_Errors(t *testing.T) { assert.ErrorIs(t, err, s4.ErrPastExpiration) }) + t.Run("ErrExpirationTooLong", func(t *testing.T) { + key := &s4.Key{ + Address: testutils.NewAddress(), + SlotId: 1, + Version: 0, + } + record := &s4.Record{ + Payload: make([]byte, 10), + Expiration: now.UnixMilli() + 10000000, + } + err := storage.Put(testutils.Context(t), key, record, []byte{}) + assert.ErrorIs(t, err, s4.ErrExpirationTooLong) + }) + t.Run("ErrWrongSignature", func(t *testing.T) { privateKey, address := testutils.NewPrivateKeyAndAddress(t) key := &s4.Key{ diff --git a/core/services/synchronization/explorer_client.go b/core/services/synchronization/explorer_client.go deleted file mode 100644 index 4bdcc30b134..00000000000 --- a/core/services/synchronization/explorer_client.go +++ /dev/null @@ -1,410 +0,0 @@ -package synchronization - -import ( - "context" - "errors" - "fmt" - "net/http" - "net/url" - "sync" - "sync/atomic" - "time" - - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" - "github.com/smartcontractkit/chainlink/v2/core/static" - "github.com/smartcontractkit/chainlink/v2/core/utils" - - "github.com/gorilla/websocket" -) - -var ( - // ErrReceiveTimeout is returned when no message is received after a - // specified duration in Receive - ErrReceiveTimeout = errors.New("timeout waiting for message") -) - -type ConnectionStatus string - -const ( - // ConnectionStatusDisconnected is the default state - ConnectionStatusDisconnected = ConnectionStatus("disconnected") - // ConnectionStatusConnected is used when the client is successfully connected - ConnectionStatusConnected = ConnectionStatus("connected") - // ConnectionStatusError is used when there is an error - ConnectionStatusError = ConnectionStatus("error") -) - -// SendBufferSize is the number of messages to keep in the buffer before dropping additional ones -const SendBufferSize = 100 - -const ( - ExplorerTextMessage = websocket.TextMessage - ExplorerBinaryMessage = websocket.BinaryMessage -) - -//go:generate mockery --quiet --name ExplorerClient --output ./mocks --case=underscore - -// ExplorerClient encapsulates all the functionality needed to -// push run information to explorer. -type ExplorerClient interface { - services.ServiceCtx - Url() url.URL - Status() ConnectionStatus - Send(context.Context, []byte, ...int) - Receive(context.Context, ...time.Duration) ([]byte, error) -} - -type NoopExplorerClient struct{} - -func (NoopExplorerClient) HealthReport() map[string]error { return map[string]error{} } -func (NoopExplorerClient) Name() string { return "NoopExplorerClient" } - -// Url always returns underlying url. -func (NoopExplorerClient) Url() url.URL { return url.URL{} } - -// Status always returns ConnectionStatusDisconnected. -func (NoopExplorerClient) Status() ConnectionStatus { return ConnectionStatusDisconnected } - -// Start is a no-op -func (NoopExplorerClient) Start(context.Context) error { return nil } - -// Close is a no-op -func (NoopExplorerClient) Close() error { return nil } - -// Ready is a no-op -func (NoopExplorerClient) Ready() error { return nil } - -// Send is a no-op -func (NoopExplorerClient) Send(context.Context, []byte, ...int) {} - -// Receive is a no-op -func (NoopExplorerClient) Receive(context.Context, ...time.Duration) ([]byte, error) { return nil, nil } - -type explorerClient struct { - utils.StartStopOnce - conn *websocket.Conn - sendText chan []byte - sendBinary chan []byte - dropMessageCount atomic.Uint32 - receive chan []byte - sleeper utils.Sleeper - status ConnectionStatus - url *url.URL - accessKey string - secret string - lggr logger.Logger - - chStop utils.StopChan - wg sync.WaitGroup - writePumpDone chan struct{} - - statusMtx sync.RWMutex -} - -// NewExplorerClient returns a stats pusher using a websocket for -// delivery. -func NewExplorerClient(url *url.URL, accessKey, secret string, lggr logger.Logger) ExplorerClient { - return &explorerClient{ - url: url, - receive: make(chan []byte), - sleeper: utils.NewBackoffSleeper(), - status: ConnectionStatusDisconnected, - accessKey: accessKey, - secret: secret, - lggr: lggr.Named("ExplorerClient"), - - sendText: make(chan []byte, SendBufferSize), - sendBinary: make(chan []byte, SendBufferSize), - } -} - -// Url returns the URL the client was initialized with -func (ec *explorerClient) Url() url.URL { - return *ec.url -} - -// Status returns the current connection status -func (ec *explorerClient) Status() ConnectionStatus { - ec.statusMtx.RLock() - defer ec.statusMtx.RUnlock() - return ec.status -} - -// Start starts a write pump over a websocket. -func (ec *explorerClient) Start(context.Context) error { - return ec.StartOnce("Explorer client", func() error { - ec.chStop = make(chan struct{}) - ec.wg.Add(1) - go ec.connectAndWritePump() - return nil - }) -} - -func (ec *explorerClient) Name() string { - return ec.lggr.Name() -} - -func (ec *explorerClient) HealthReport() map[string]error { - return map[string]error{ - ec.Name(): ec.StartStopOnce.Healthy(), - } -} - -// Send sends data asynchronously across the websocket if it's open, or -// holds it in a small buffer until connection, throwing away messages -// once buffer is full. -// func (ec *explorerClient) Receive(durationParams ...time.Duration) ([]byte, error) { -func (ec *explorerClient) Send(ctx context.Context, data []byte, messageTypes ...int) { - messageType := ExplorerTextMessage - if len(messageTypes) > 0 { - messageType = messageTypes[0] - } - var send chan []byte - switch messageType { - case ExplorerTextMessage: - send = ec.sendText - case ExplorerBinaryMessage: - send = ec.sendBinary - default: - err := fmt.Errorf("send on explorer client received unsupported message type %d", messageType) - ec.SvcErrBuffer.Append(err) - ec.lggr.Critical(err.Error()) - return - } - select { - case send <- data: - ec.dropMessageCount.Store(0) - case <-ctx.Done(): - return - default: - ec.logBufferFullWithExpBackoff(data) - } -} - -// logBufferFullWithExpBackoff logs messages at -// 1 -// 2 -// 4 -// 8 -// 16 -// 32 -// 64 -// 100 -// 200 -// 300 -// etc... -func (ec *explorerClient) logBufferFullWithExpBackoff(data []byte) { - count := ec.dropMessageCount.Add(1) - if count > 0 && (count%100 == 0 || count&(count-1) == 0) { - ec.lggr.Warnw("explorer client buffer full, dropping message", "data", data, "droppedCount", count) - } -} - -// Receive blocks the caller while waiting for a response from the server, -// returning the raw response bytes -func (ec *explorerClient) Receive(ctx context.Context, durationParams ...time.Duration) ([]byte, error) { - duration := defaultReceiveTimeout - if len(durationParams) > 0 { - duration = durationParams[0] - } - - select { - case data := <-ec.receive: - return data, nil - case <-time.After(duration): - return nil, ErrReceiveTimeout - case <-ctx.Done(): - return nil, nil - } -} - -const ( - // Time allowed to write a message to the peer. - writeWait = 10 * time.Second - - // Time allowed to read the next pong message from the peer. - pongWait = 60 * time.Second - - // Send pings to peer with this period. Must be less than pongWait. - pingPeriod = (pongWait * 9) / 10 - - // Maximum message size allowed from peer. - maxMessageSize = 512 - - // defaultReceiveTimeout is the default amount of time to wait for receipt of messages - defaultReceiveTimeout = 30 * time.Second -) - -// Inspired by https://github.com/gorilla/websocket/blob/master/examples/chat/client.go -// lexical confinement of done chan allows multiple connectAndWritePump routines -// to clean up independent of itself by reducing shared state. i.e. a passed done, not ec.done. -func (ec *explorerClient) connectAndWritePump() { - defer ec.wg.Done() - ctx, cancel := ec.chStop.NewCtx() - defer cancel() - for { - select { - case <-time.After(ec.sleeper.After()): - ec.lggr.Infow("Connecting to explorer", "url", ec.url) - err := ec.connect(ctx) - if ctx.Err() != nil { - return - } else if err != nil { - ec.setStatus(ConnectionStatusError) - ec.lggr.Warn("Failed to connect to explorer (", ec.url.String(), "): ", err) - break - } - - ec.setStatus(ConnectionStatusConnected) - - ec.lggr.Infow("Connected to explorer", "url", ec.url) - start := time.Now() - ec.writePumpDone = make(chan struct{}) - ec.wg.Add(1) - go ec.readPump() - ec.writePump() - if time.Since(start) > time.Second { - ec.sleeper.Reset() - } - - case <-ec.chStop: - return - } - } -} - -func (ec *explorerClient) setStatus(s ConnectionStatus) { - ec.statusMtx.Lock() - defer ec.statusMtx.Unlock() - ec.status = s -} - -// Inspired by https://github.com/gorilla/websocket/blob/master/examples/chat/client.go#L82 -func (ec *explorerClient) writePump() { - ticker := time.NewTicker(pingPeriod) - defer func() { - ticker.Stop() - ec.wrapConnErrorIf(ec.conn.Close()) // exclusive responsibility to close ws conn - }() - - for { - select { - case message, open := <-ec.sendText: - if !open { - ec.wrapConnErrorIf(ec.conn.WriteMessage(websocket.CloseMessage, []byte{})) - } - - err := ec.writeMessage(message, websocket.TextMessage) - if err != nil { - ec.lggr.Warnw("websocketStatsPusher: error writing text message", "err", err) - return - } - - case message, open := <-ec.sendBinary: - if !open { - ec.wrapConnErrorIf(ec.conn.WriteMessage(websocket.CloseMessage, []byte{})) - } - - err := ec.writeMessage(message, websocket.BinaryMessage) - if err != nil { - ec.lggr.Warnw("websocketStatsPusher: error writing binary message", "err", err) - return - } - - case <-ticker.C: - ec.wrapConnErrorIf(ec.conn.SetWriteDeadline(time.Now().Add(writeWait))) - if err := ec.conn.WriteMessage(websocket.PingMessage, nil); err != nil { - ec.wrapConnErrorIf(err) - return - } - - case <-ec.writePumpDone: - return - case <-ec.chStop: - return - } - } -} - -func (ec *explorerClient) writeMessage(message []byte, messageType int) error { - ec.wrapConnErrorIf(ec.conn.SetWriteDeadline(time.Now().Add(writeWait))) - writer, err := ec.conn.NextWriter(messageType) - if err != nil { - return err - } - - if _, err := writer.Write(message); err != nil { - return err - } - ec.lggr.Tracew("websocketStatsPusher successfully wrote message", "messageType", messageType, "message", message) - - return writer.Close() -} - -func (ec *explorerClient) connect(ctx context.Context) error { - authHeader := http.Header{} - authHeader.Add("X-Explore-Chainlink-Accesskey", ec.accessKey) - authHeader.Add("X-Explore-Chainlink-Secret", ec.secret) - authHeader.Add("X-Explore-Chainlink-Core-Version", static.Version) - authHeader.Add("X-Explore-Chainlink-Core-Sha", static.Sha) - - conn, _, err := websocket.DefaultDialer.DialContext(ctx, ec.url.String(), authHeader) - if ctx.Err() != nil { - return fmt.Errorf("websocketStatsPusher#connect context canceled: %w", ctx.Err()) - } else if err != nil { - return fmt.Errorf("websocketStatsPusher#connect: %v", err) - } - - ec.conn = conn - return nil -} - -var expectedCloseMessages = []int{websocket.CloseGoingAway, websocket.CloseAbnormalClosure, websocket.CloseNormalClosure} - -// readPump listens on the websocket connection for control messages and -// response messages (text) -// -// For more details on how disconnection messages are handled, see: -// - https://stackoverflow.com/a/48181794/639773 -// - https://github.com/gorilla/websocket/blob/master/examples/chat/client.go#L56 -func (ec *explorerClient) readPump() { - defer ec.wg.Done() - ec.conn.SetReadLimit(maxMessageSize) - _ = ec.conn.SetReadDeadline(time.Now().Add(pongWait)) - ec.conn.SetPongHandler(func(string) error { - _ = ec.conn.SetReadDeadline(time.Now().Add(pongWait)) - return nil - }) - - for { - messageType, message, err := ec.conn.ReadMessage() - if err != nil { - if websocket.IsUnexpectedCloseError(err, expectedCloseMessages...) { - ec.lggr.Warnw("Unexpected close error on ExplorerClient", "err", err) - } - close(ec.writePumpDone) - return - } - - switch messageType { - case websocket.TextMessage: - ec.receive <- message - } - } -} - -func (ec *explorerClient) wrapConnErrorIf(err error) { - if err != nil && websocket.IsUnexpectedCloseError(err, expectedCloseMessages...) { - ec.setStatus(ConnectionStatusError) - ec.lggr.Error(fmt.Sprintf("websocketStatsPusher: %v", err)) - } -} - -func (ec *explorerClient) Close() error { - return ec.StopOnce("Explorer client", func() error { - close(ec.chStop) - ec.wg.Wait() - return nil - }) -} diff --git a/core/services/synchronization/explorer_client_test.go b/core/services/synchronization/explorer_client_test.go deleted file mode 100644 index 727b8dd6d33..00000000000 --- a/core/services/synchronization/explorer_client_test.go +++ /dev/null @@ -1,213 +0,0 @@ -package synchronization_test - -import ( - "net/http" - "net/http/httptest" - "net/url" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/onsi/gomega" - "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/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" - "github.com/smartcontractkit/chainlink/v2/core/static" -) - -func TestWebSocketClient_ReconnectLoop(t *testing.T) { - wsserver, cleanup := cltest.NewEventWebSocketServer(t) - defer cleanup() - - explorerClient := newTestExplorerClient(t, wsserver.URL) - require.NoError(t, explorerClient.Start(testutils.Context(t))) - cltest.CallbackOrTimeout(t, "ws client connects", func() { - <-wsserver.Connected - }, testutils.WaitTimeout(t)) - - // reconnect after server disconnect - wsserver.WriteCloseMessage() - cltest.CallbackOrTimeout(t, "ws client reconnects", func() { - <-wsserver.Disconnected - <-wsserver.Connected - }, testutils.WaitTimeout(t)) - require.NoError(t, explorerClient.Close()) -} - -func TestWebSocketClient_Authentication(t *testing.T) { - headerChannel := make(chan http.Header, 1) - handler := func(w http.ResponseWriter, r *http.Request) { - headerChannel <- r.Header - } - server := httptest.NewServer(http.HandlerFunc(handler)) - defer server.Close() - - url := cltest.MustParseURL(t, server.URL) - url.Scheme = "ws" - explorerClient := synchronization.NewExplorerClient(url, "accessKey", "secret", logger.TestLogger(t)) - require.NoError(t, explorerClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, explorerClient.Close()) }() - - cltest.CallbackOrTimeout(t, "receive authentication headers", func() { - headers := <-headerChannel - assert.Equal(t, []string{"accessKey"}, headers["X-Explore-Chainlink-Accesskey"]) - assert.Equal(t, []string{"secret"}, headers["X-Explore-Chainlink-Secret"]) - assert.Equal(t, []string{static.Version}, headers["X-Explore-Chainlink-Core-Version"]) - assert.Equal(t, []string{static.Sha}, headers["X-Explore-Chainlink-Core-Sha"]) - }) -} - -func TestWebSocketClient_Send_DefaultsToTextMessage(t *testing.T) { - wsserver, cleanup := cltest.NewEventWebSocketServer(t) - defer cleanup() - - explorerClient := newTestExplorerClient(t, wsserver.URL) - require.NoError(t, explorerClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, explorerClient.Close()) }() - - expectation := `{"hello": "world"}` - explorerClient.Send(testutils.Context(t), []byte(expectation)) - cltest.CallbackOrTimeout(t, "receive stats", func() { - require.Equal(t, expectation, <-wsserver.ReceivedText) - }, testutils.WaitTimeout(t)) -} - -func TestWebSocketClient_Send_TextMessage(t *testing.T) { - wsserver, cleanup := cltest.NewEventWebSocketServer(t) - defer cleanup() - - explorerClient := newTestExplorerClient(t, wsserver.URL) - require.NoError(t, explorerClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, explorerClient.Close()) }() - - expectation := `{"hello": "world"}` - explorerClient.Send(testutils.Context(t), []byte(expectation), synchronization.ExplorerTextMessage) - cltest.CallbackOrTimeout(t, "receive stats", func() { - require.Equal(t, expectation, <-wsserver.ReceivedText) - }, testutils.WaitTimeout(t)) -} - -func TestWebSocketClient_Send_Binary(t *testing.T) { - wsserver, cleanup := cltest.NewEventWebSocketServer(t) - defer cleanup() - - explorerClient := newTestExplorerClient(t, wsserver.URL) - require.NoError(t, explorerClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, explorerClient.Close()) }() - - address := common.HexToAddress("0xabc123") - addressBytes := address.Bytes() - explorerClient.Send(testutils.Context(t), addressBytes, synchronization.ExplorerBinaryMessage) - cltest.CallbackOrTimeout(t, "receive stats", func() { - require.Equal(t, addressBytes, <-wsserver.ReceivedBinary) - }, testutils.WaitTimeout(t)) -} - -func TestWebSocketClient_Send_Unsupported(t *testing.T) { - wsserver, cleanup := cltest.NewEventWebSocketServer(t) - defer cleanup() - - explorerClient := newTestExplorerClient(t, wsserver.URL) - require.NoError(t, explorerClient.Start(testutils.Context(t))) - - explorerClient.Send(testutils.Context(t), []byte(`{"hello": "world"}`), -1) - require.Contains(t, explorerClient.HealthReport()[explorerClient.Name()].Error(), "send on explorer client received unsupported message type -1") - require.NoError(t, explorerClient.Close()) -} - -func TestWebSocketClient_Send_WithAck(t *testing.T) { - wsserver, cleanup := cltest.NewEventWebSocketServer(t) - defer cleanup() - - explorerClient := newTestExplorerClient(t, wsserver.URL) - require.NoError(t, explorerClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, explorerClient.Close()) }() - - expectation := `{"hello": "world"}` - explorerClient.Send(testutils.Context(t), []byte(expectation)) - cltest.CallbackOrTimeout(t, "receive stats", func() { - require.Equal(t, expectation, <-wsserver.ReceivedText) - err := wsserver.Broadcast(`{"result": 200}`) - assert.NoError(t, err) - }, testutils.WaitTimeout(t)) - - cltest.CallbackOrTimeout(t, "receive response", func() { - response, err := explorerClient.Receive(testutils.Context(t)) - assert.NoError(t, err) - assert.NotNil(t, response) - }, testutils.WaitTimeout(t)) -} - -func TestWebSocketClient_Send_WithAckTimeout(t *testing.T) { - wsserver, cleanup := cltest.NewEventWebSocketServer(t) - defer cleanup() - - explorerClient := newTestExplorerClient(t, wsserver.URL) - require.NoError(t, explorerClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, explorerClient.Close()) }() - - expectation := `{"hello": "world"}` - explorerClient.Send(testutils.Context(t), []byte(expectation)) - cltest.CallbackOrTimeout(t, "receive stats", func() { - require.Equal(t, expectation, <-wsserver.ReceivedText) - }, testutils.WaitTimeout(t)) - - cltest.CallbackOrTimeout(t, "receive response", func() { - _, err := explorerClient.Receive(testutils.Context(t), 100*time.Millisecond) - assert.ErrorIs(t, err, synchronization.ErrReceiveTimeout) - }, testutils.WaitTimeout(t)) -} - -func TestWebSocketClient_Status_ConnectAndServerDisconnect(t *testing.T) { - wsserver, cleanup := cltest.NewEventWebSocketServer(t) - defer cleanup() - - explorerClient := newTestExplorerClient(t, wsserver.URL) - assert.Equal(t, synchronization.ConnectionStatusDisconnected, explorerClient.Status()) - - require.NoError(t, explorerClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, explorerClient.Close()) }() - cltest.CallbackOrTimeout(t, "ws client connects", func() { - <-wsserver.Connected - }, testutils.WaitTimeout(t)) - - gomega.NewWithT(t).Eventually(func() synchronization.ConnectionStatus { - return explorerClient.Status() - }).Should(gomega.Equal(synchronization.ConnectionStatusConnected)) - - // this triggers ConnectionStatusError and then the client gets reconnected - wsserver.WriteCloseMessage() - - cltest.CallbackOrTimeout(t, "ws client disconnects and reconnects", func() { - <-wsserver.Disconnected - <-wsserver.Connected - }, testutils.WaitTimeout(t)) - - // expecting the client to reconnect - gomega.NewWithT(t).Eventually(func() synchronization.ConnectionStatus { - return explorerClient.Status() - }).Should(gomega.Equal(synchronization.ConnectionStatusConnected)) - - require.Equal(t, 1, wsserver.ConnectionsCount()) -} - -func TestWebSocketClient_Status_ConnectError(t *testing.T) { - badURL, err := url.Parse("http://badhost.com") - require.NoError(t, err) - - errorExplorerClient := newTestExplorerClient(t, badURL) - require.NoError(t, errorExplorerClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, errorExplorerClient.Close()) }() - - gomega.NewWithT(t).Eventually(func() synchronization.ConnectionStatus { - return errorExplorerClient.Status() - }).Should(gomega.Equal(synchronization.ConnectionStatusError)) -} - -func newTestExplorerClient(t *testing.T, wsURL *url.URL) synchronization.ExplorerClient { - return synchronization.NewExplorerClient(wsURL, "", "", logger.TestLogger(t)) -} diff --git a/core/services/synchronization/mocks/explorer_client.go b/core/services/synchronization/mocks/explorer_client.go deleted file mode 100644 index 2aa1616d1ca..00000000000 --- a/core/services/synchronization/mocks/explorer_client.go +++ /dev/null @@ -1,178 +0,0 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. - -package mocks - -import ( - context "context" - time "time" - - synchronization "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" - mock "github.com/stretchr/testify/mock" - - url "net/url" -) - -// ExplorerClient is an autogenerated mock type for the ExplorerClient type -type ExplorerClient struct { - mock.Mock -} - -// Close provides a mock function with given fields: -func (_m *ExplorerClient) Close() error { - ret := _m.Called() - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// HealthReport provides a mock function with given fields: -func (_m *ExplorerClient) HealthReport() map[string]error { - ret := _m.Called() - - var r0 map[string]error - if rf, ok := ret.Get(0).(func() map[string]error); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]error) - } - } - - return r0 -} - -// Name provides a mock function with given fields: -func (_m *ExplorerClient) Name() string { - ret := _m.Called() - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// Ready provides a mock function with given fields: -func (_m *ExplorerClient) Ready() error { - ret := _m.Called() - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Receive provides a mock function with given fields: _a0, _a1 -func (_m *ExplorerClient) Receive(_a0 context.Context, _a1 ...time.Duration) ([]byte, error) { - _va := make([]interface{}, len(_a1)) - for _i := range _a1 { - _va[_i] = _a1[_i] - } - var _ca []interface{} - _ca = append(_ca, _a0) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 []byte - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, ...time.Duration) ([]byte, error)); ok { - return rf(_a0, _a1...) - } - if rf, ok := ret.Get(0).(func(context.Context, ...time.Duration) []byte); ok { - r0 = rf(_a0, _a1...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]byte) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, ...time.Duration) error); ok { - r1 = rf(_a0, _a1...) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Send provides a mock function with given fields: _a0, _a1, _a2 -func (_m *ExplorerClient) Send(_a0 context.Context, _a1 []byte, _a2 ...int) { - _va := make([]interface{}, len(_a2)) - for _i := range _a2 { - _va[_i] = _a2[_i] - } - var _ca []interface{} - _ca = append(_ca, _a0, _a1) - _ca = append(_ca, _va...) - _m.Called(_ca...) -} - -// Start provides a mock function with given fields: _a0 -func (_m *ExplorerClient) Start(_a0 context.Context) error { - ret := _m.Called(_a0) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(_a0) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Status provides a mock function with given fields: -func (_m *ExplorerClient) Status() synchronization.ConnectionStatus { - ret := _m.Called() - - var r0 synchronization.ConnectionStatus - if rf, ok := ret.Get(0).(func() synchronization.ConnectionStatus); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(synchronization.ConnectionStatus) - } - - return r0 -} - -// Url provides a mock function with given fields: -func (_m *ExplorerClient) Url() url.URL { - ret := _m.Called() - - var r0 url.URL - if rf, ok := ret.Get(0).(func() url.URL); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(url.URL) - } - - return r0 -} - -type mockConstructorTestingTNewExplorerClient interface { - mock.TestingT - Cleanup(func()) -} - -// NewExplorerClient creates a new instance of ExplorerClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewExplorerClient(t mockConstructorTestingTNewExplorerClient) *ExplorerClient { - mock := &ExplorerClient{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/telemetry/explorer.go b/core/services/telemetry/explorer.go deleted file mode 100644 index aa0f8410404..00000000000 --- a/core/services/telemetry/explorer.go +++ /dev/null @@ -1,31 +0,0 @@ -package telemetry - -import ( - "context" - - ocrtypes "github.com/smartcontractkit/libocr/commontypes" - - "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" -) - -var _ MonitoringEndpointGenerator = &ExplorerAgent{} - -type ExplorerAgent struct { - explorerClient synchronization.ExplorerClient -} - -// NewExplorerAgent returns a Agent which is just a thin wrapper over -// the explorerClient for now -func NewExplorerAgent(explorerClient synchronization.ExplorerClient) *ExplorerAgent { - return &ExplorerAgent{explorerClient} -} - -// SendLog sends a telemetry log to the explorer -func (t *ExplorerAgent) SendLog(log []byte) { - t.explorerClient.Send(context.Background(), log, synchronization.ExplorerBinaryMessage) -} - -// GenMonitoringEndpoint creates a monitoring endpoint for telemetry -func (t *ExplorerAgent) GenMonitoringEndpoint(contractID string, telemType synchronization.TelemetryType) ocrtypes.MonitoringEndpoint { - return t -} diff --git a/core/services/telemetry/explorer_test.go b/core/services/telemetry/explorer_test.go deleted file mode 100644 index c3f50033d35..00000000000 --- a/core/services/telemetry/explorer_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package telemetry_test - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - - "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" - "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/mocks" - "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" -) - -func TestExplorerAgent(t *testing.T) { - explorerClient := mocks.NewExplorerClient(t) - explorerAgent := telemetry.NewExplorerAgent(explorerClient) - monitoringEndpoint := explorerAgent.GenMonitoringEndpoint("0xa", synchronization.OCR) - - // Handle the Send call and store the logs - var sentLog []byte - explorerClient.On("Send", mock.AnythingOfType("*context.emptyCtx"), mock.AnythingOfType("[]uint8"), synchronization.ExplorerBinaryMessage).Return().Run(func(args mock.Arguments) { - sentLog = args[1].([]byte) - }) - - // Send the log to the monitoring endpoint - log := []byte("test log") - monitoringEndpoint.SendLog(log) - - // Logs should be sent to the mock as they were passed in - assert.Equal(t, log, sentLog) -} diff --git a/core/services/telemetry/noop.go b/core/services/telemetry/noop.go index 2603c87875c..71670f2a198 100644 --- a/core/services/telemetry/noop.go +++ b/core/services/telemetry/noop.go @@ -11,7 +11,7 @@ var _ MonitoringEndpointGenerator = &NoopAgent{} type NoopAgent struct { } -// SendLog sends a telemetry log to the explorer +// SendLog sends a telemetry log to the ingress service func (t *NoopAgent) SendLog(log []byte) { } diff --git a/core/services/vrf/delegate.go b/core/services/vrf/delegate.go index 733c21b45a7..cc6c05cacdd 100644 --- a/core/services/vrf/delegate.go +++ b/core/services/vrf/delegate.go @@ -367,24 +367,24 @@ func getRespCounts(q pg.Q, chainID uint64, evmFinalityDepth uint32) ( RequestID string Count int }{} - // This query should use the idx_eth_txes_state_from_address_evm_chain_id + // This query should use the idx_evm.txes_state_from_address_evm_chain_id // index, since the quantity of unconfirmed/unstarted/in_progress transactions _should_ be small // relative to the rest of the data. unconfirmedQuery := ` SELECT meta->'RequestID' AS request_id, count(meta->'RequestID') AS count -FROM eth_txes et +FROM evm.txes et WHERE et.meta->'RequestID' IS NOT NULL AND et.state IN ('unconfirmed', 'unstarted', 'in_progress') GROUP BY meta->'RequestID' ` // Fetch completed transactions only as far back as the given cutoffBlockNumber. This avoids - // a table scan of the eth_txes table, which could be large if it is unpruned. + // a table scan of the evm.txes table, which could be large if it is unpruned. confirmedQuery := ` SELECT meta->'RequestID' AS request_id, count(meta->'RequestID') AS count -FROM eth_txes et JOIN eth_tx_attempts eta on et.id = eta.eth_tx_id - join eth_receipts er on eta.hash = er.tx_hash +FROM evm.txes et JOIN evm.tx_attempts eta on et.id = eta.eth_tx_id + join evm.receipts er on eta.hash = er.tx_hash WHERE et.meta->'RequestID' is not null -AND er.block_number >= (SELECT number FROM evm_heads WHERE evm_chain_id = $1 ORDER BY number DESC LIMIT 1) - $2 +AND er.block_number >= (SELECT number FROM evm.heads WHERE evm_chain_id = $1 ORDER BY number DESC LIMIT 1) - $2 GROUP BY meta->'RequestID' ` query := unconfirmedQuery + "\nUNION ALL\n" + confirmedQuery diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index b26e5511c16..ae0accc329e 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -155,7 +155,7 @@ func setup(t *testing.T) (vrfUniverse, *v1.Listener, job.Job) { logger.TestLogger(t), cfg.Database(), mailMon) - vs := testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{PublicKey: vuni.vrfkey.PublicKey.String()}) + vs := testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{PublicKey: vuni.vrfkey.PublicKey.String(), EVMChainID: testutils.FixtureChainID.String()}) jb, err := vrfcommon.ValidatedVRFSpec(vs.Toml()) require.NoError(t, err) err = vuni.jrm.CreateJob(&jb) @@ -413,7 +413,7 @@ func TestDelegate_InvalidLog(t *testing.T) { // Ensure we have NOT queued up an eth transaction var ethTxes []txmgr.DbEthTx - err = vuni.prm.GetQ().Select(ðTxes, `SELECT * FROM eth_txes;`) + err = vuni.prm.GetQ().Select(ðTxes, `SELECT * FROM evm.txes;`) require.NoError(t, err) require.Len(t, ethTxes, 0) } diff --git a/core/services/vrf/v1/integration_test.go b/core/services/vrf/v1/integration_test.go index 42b709e298c..0a57c72ef17 100644 --- a/core/services/vrf/v1/integration_test.go +++ b/core/services/vrf/v1/integration_test.go @@ -30,6 +30,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrftesthelpers" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" + "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestIntegration_VRF_JPV2(t *testing.T) { @@ -47,6 +48,7 @@ func TestIntegration_VRF_JPV2(t *testing.T) { t.Run(test.name, func(t *testing.T) { config, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("vrf_jpv2_%v", test.eip1559), func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = &test.eip1559 + c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) }) key1 := cltest.MustGenerateRandomKey(t) key2 := cltest.MustGenerateRandomKey(t) @@ -133,6 +135,7 @@ func TestIntegration_VRF_WithBHS(t *testing.T) { c.Feature.LogPoller = ptr(true) c.EVM[0].FinalityDepth = ptr[uint32](2) c.EVM[0].LogPollInterval = models.MustNewDuration(time.Second) + c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) }) key := cltest.MustGenerateRandomKey(t) cu := vrftesthelpers.NewVRFCoordinatorUniverse(t, key) @@ -241,7 +244,9 @@ func createVRFJobRegisterKey(t *testing.T, u vrftesthelpers.CoordinatorUniverse, Name: "vrf-primary", CoordinatorAddress: u.RootContractAddress.String(), MinIncomingConfirmations: incomingConfs, - PublicKey: vrfKey.PublicKey.String()}).Toml() + PublicKey: vrfKey.PublicKey.String(), + EVMChainID: testutils.SimulatedChainID.String(), + }).Toml() jb, err := vrfcommon.ValidatedVRFSpec(s) require.NoError(t, err) assert.Equal(t, expectedOnChainJobID, jb.ExternalIDEncodeStringToTopic().Bytes()) diff --git a/core/services/vrf/v1/listener_v1.go b/core/services/vrf/v1/listener_v1.go index 0fce2ebedde..39aec367b4a 100644 --- a/core/services/vrf/v1/listener_v1.go +++ b/core/services/vrf/v1/listener_v1.go @@ -416,6 +416,7 @@ func (lsn *Listener) ProcessRequest(ctx context.Context, req request) bool { "name": lsn.Job.Name.ValueOrZero(), "publicKey": lsn.Job.VRFSpec.PublicKey[:], "from": lsn.fromAddresses(), + "evmChainID": lsn.Job.VRFSpec.EVMChainID.String(), }, "jobRun": map[string]interface{}{ "logBlockHash": req.req.Raw.BlockHash[:], diff --git a/core/services/vrf/v2/integration_helpers_test.go b/core/services/vrf/v2/integration_helpers_test.go index 43ca198334d..74d7175e08b 100644 --- a/core/services/vrf/v2/integration_helpers_test.go +++ b/core/services/vrf/v2/integration_helpers_test.go @@ -28,6 +28,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" @@ -533,6 +534,7 @@ func testSingleConsumerHappyPathBatchFulfillment( })(c, s) c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](5_000_000) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) + c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1) @@ -1616,6 +1618,7 @@ func testMaliciousConsumer( c.EVM[0].GasEstimator.PriceMax = assets.GWei(1) c.EVM[0].GasEstimator.PriceDefault = assets.GWei(1) c.EVM[0].GasEstimator.FeeCapDefault = assets.GWei(1) + c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) }) carol := uni.vrfConsumers[0] @@ -1640,6 +1643,7 @@ func testMaliciousConsumer( GasLanePrice: assets.GWei(1), PublicKey: vrfkey.PublicKey.String(), V2: true, + EVMChainID: testutils.SimulatedChainID.String(), }).Toml() jb, err := vrfcommon.ValidatedVRFSpec(s) require.NoError(t, err) @@ -1681,7 +1685,7 @@ func testMaliciousConsumer( }, testutils.WaitTimeout(t), 1*time.Second).Should(gomega.BeTrue()) // The fulfillment tx should succeed - ch, err := app.GetRelayers().LegacyEVMChains().Default() + ch, err := app.GetRelayers().LegacyEVMChains().Get(evmtest.MustGetDefaultChainID(t, config.EVMConfigs()).String()) require.NoError(t, err) r, err := ch.Client().TransactionReceipt(testutils.Context(t), attempts[0].Hash) require.NoError(t, err) diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index 3b85a524bac..f4054333808 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -128,22 +128,22 @@ type coordinatorV2Universe struct { } const ( - ConfirmedEthTxesV2Query = `SELECT * FROM eth_txes - WHERE eth_txes.state = 'confirmed' - AND eth_txes.meta->>'RequestID' = $1 - AND CAST(eth_txes.meta->>'SubId' AS NUMERIC) = $2 LIMIT 1` - ConfirmedEthTxesV2PlusQuery = `SELECT * FROM eth_txes - WHERE eth_txes.state = 'confirmed' - AND eth_txes.meta->>'RequestID' = $1 - AND CAST(eth_txes.meta->>'GlobalSubId' AS NUMERIC) = $2 LIMIT 1` + ConfirmedEthTxesV2Query = `SELECT * FROM evm.txes + WHERE evm.txes.state = 'confirmed' + AND evm.txes.meta->>'RequestID' = $1 + AND CAST(evm.txes.meta->>'SubId' AS NUMERIC) = $2 LIMIT 1` + ConfirmedEthTxesV2PlusQuery = `SELECT * FROM evm.txes + WHERE evm.txes.state = 'confirmed' + AND evm.txes.meta->>'RequestID' = $1 + AND CAST(evm.txes.meta->>'GlobalSubId' AS NUMERIC) = $2 LIMIT 1` ConfirmedEthTxesV2BatchQuery = ` - SELECT * FROM eth_txes - WHERE eth_txes.state = 'confirmed' - AND CAST(eth_txes.meta->>'SubId' AS NUMERIC) = $1` + SELECT * FROM evm.txes + WHERE evm.txes.state = 'confirmed' + AND CAST(evm.txes.meta->>'SubId' AS NUMERIC) = $1` ConfirmedEthTxesV2PlusBatchQuery = ` - SELECT * FROM eth_txes - WHERE eth_txes.state = 'confirmed' - AND CAST(eth_txes.meta->>'GlobalSubId' AS NUMERIC) = $1` + SELECT * FROM evm.txes + WHERE evm.txes.state = 'confirmed' + AND CAST(evm.txes.meta->>'GlobalSubId' AS NUMERIC) = $1` ) func newVRFCoordinatorV2Universe(t *testing.T, key ethkey.KeyV2, numConsumers int) coordinatorV2Universe { @@ -554,6 +554,7 @@ func createVRFJobs( V2: true, GasLanePrice: gasLanePrices[i], VRFOwnerAddress: vrfOwnerString, + EVMChainID: testutils.SimulatedChainID.String(), }).Toml() jb, err := vrfcommon.ValidatedVRFSpec(spec) @@ -1067,6 +1068,7 @@ func testEoa( } func TestVRFV2Integration_SingleConsumer_EIP150_HappyPath(t *testing.T) { + t.Skip("TODO: VRF-617") t.Parallel() ownerKey := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2Universe(t, ownerKey, 1) @@ -1318,6 +1320,7 @@ func TestVRFV2Integration_SingleConsumer_NeedsTrustedBlockhashStore(t *testing.T } func TestVRFV2Integration_SingleConsumer_NeedsTrustedBlockhashStore_AfterDelay(t *testing.T) { + t.Skip("TODO: VRF-616") t.Parallel() ownerKey := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2PlusUniverse(t, ownerKey, 2, true) @@ -1995,7 +1998,7 @@ func TestFulfillmentCost(t *testing.T) { func TestStartingCountsV1(t *testing.T) { cfg, db := heavyweight.FullTestDBNoFixturesV2(t, "vrf_test_starting_counts", nil) - _, err := db.Exec(`INSERT INTO evm_heads (hash, number, parent_hash, created_at, timestamp, evm_chain_id) + _, err := db.Exec(`INSERT INTO evm.heads (hash, number, parent_hash, created_at, timestamp, evm_chain_id) VALUES ($1, 4, $2, NOW(), NOW(), 1337)`, utils.NewHash(), utils.NewHash()) require.NoError(t, err) @@ -2099,7 +2102,7 @@ func TestStartingCountsV1(t *testing.T) { ChainID: chainID.ToInt(), }) } - sql := `INSERT INTO eth_txes (nonce, from_address, to_address, encoded_payload, value, gas_limit, state, created_at, broadcast_at, initial_broadcast_at, meta, subject, evm_chain_id, min_confirmations, pipeline_task_run_id) + sql := `INSERT INTO evm.txes (nonce, from_address, to_address, encoded_payload, value, gas_limit, state, created_at, broadcast_at, initial_broadcast_at, meta, subject, evm_chain_id, min_confirmations, pipeline_task_run_id) VALUES (:nonce, :from_address, :to_address, :encoded_payload, :value, :gas_limit, :state, :created_at, :broadcast_at, :initial_broadcast_at, :meta, :subject, :evm_chain_id, :min_confirmations, :pipeline_task_run_id);` for _, tx := range append(confirmedTxes, unconfirmedTxes...) { dbEtx := txmgr.DbEthTxFromEthTx(&tx) @@ -2107,7 +2110,7 @@ VALUES (:nonce, :from_address, :to_address, :encoded_payload, :value, :gas_limit require.NoError(t, err) } - // add eth_tx_attempts for confirmed + // add evm.tx_attempts for confirmed broadcastBlock := int64(1) var txAttempts []txmgr.TxAttempt for i := range confirmedTxes { @@ -2122,7 +2125,7 @@ VALUES (:nonce, :from_address, :to_address, :encoded_payload, :value, :gas_limit ChainSpecificFeeLimit: uint32(100), }) } - // add eth_tx_attempts for unconfirmed + // add evm.tx_attempts for unconfirmed for i := range unconfirmedTxes { txAttempts = append(txAttempts, txmgr.TxAttempt{ TxID: int64(i + 1 + len(confirmedTxes)), @@ -2137,16 +2140,16 @@ VALUES (:nonce, :from_address, :to_address, :encoded_payload, :value, :gas_limit for _, txAttempt := range txAttempts { t.Log("tx attempt eth tx id: ", txAttempt.TxID) } - sql = `INSERT INTO eth_tx_attempts (eth_tx_id, gas_price, signed_raw_tx, hash, state, created_at, chain_specific_gas_limit) + sql = `INSERT INTO evm.tx_attempts (eth_tx_id, gas_price, signed_raw_tx, hash, state, created_at, chain_specific_gas_limit) VALUES (:eth_tx_id, :gas_price, :signed_raw_tx, :hash, :state, :created_at, :chain_specific_gas_limit)` for _, attempt := range txAttempts { - dbAttempt := txmgr.DbEthTxAttemptFromEthTxAttempt(&attempt) //nolint:gosec - just copying fields + dbAttempt := txmgr.DbEthTxAttemptFromEthTxAttempt(&attempt) //nolint:gosec // just copying fields _, err = db.NamedExec(sql, &dbAttempt) require.NoError(t, err) - txmgr.DbEthTxAttemptToEthTxAttempt(dbAttempt, &attempt) //nolint:gosec - just copying fields + txmgr.DbEthTxAttemptToEthTxAttempt(dbAttempt, &attempt) //nolint:gosec // just copying fields } - // add eth_receipts + // add evm.receipts receipts := []txmgr.Receipt{} for i := 0; i < 4; i++ { receipts = append(receipts, txmgr.Receipt{ @@ -2158,7 +2161,7 @@ VALUES (:nonce, :from_address, :to_address, :encoded_payload, :value, :gas_limit CreatedAt: time.Now(), }) } - sql = `INSERT INTO eth_receipts (block_hash, tx_hash, block_number, transaction_index, receipt, created_at) + sql = `INSERT INTO evm.receipts (block_hash, tx_hash, block_number, transaction_index, receipt, created_at) VALUES (:block_hash, :tx_hash, :block_number, :transaction_index, :receipt, :created_at)` for _, r := range receipts { _, err := db.NamedExec(sql, &r) diff --git a/core/services/vrf/v2/listener_v2.go b/core/services/vrf/v2/listener_v2.go index 9b643d4f571..2eb10f64c89 100644 --- a/core/services/vrf/v2/listener_v2.go +++ b/core/services/vrf/v2/listener_v2.go @@ -72,7 +72,7 @@ const ( backoffFactor = 1.3 V2ReservedLinkQuery = `SELECT SUM(CAST(meta->>'MaxLink' AS NUMERIC(78, 0))) - FROM eth_txes + FROM evm.txes WHERE meta->>'MaxLink' IS NOT NULL AND evm_chain_id = $1 AND CAST(meta->>'SubId' AS NUMERIC) = $2 @@ -80,7 +80,7 @@ const ( GROUP BY meta->>'SubId'` V2PlusReservedLinkQuery = `SELECT SUM(CAST(meta->>'MaxLink' AS NUMERIC(78, 0))) - FROM eth_txes + FROM evm.txes WHERE meta->>'MaxLink' IS NOT NULL AND evm_chain_id = $1 AND CAST(meta->>'GlobalSubId' AS NUMERIC) = $2 @@ -88,7 +88,7 @@ const ( GROUP BY meta->>'GlobalSubId'` V2PlusReservedEthQuery = `SELECT SUM(CAST(meta->>'MaxEth' AS NUMERIC(78, 0))) - FROM eth_txes + FROM evm.txes WHERE meta->>'MaxEth' IS NOT NULL AND evm_chain_id = $1 AND CAST(meta->>'GlobalSubId' AS NUMERIC) = $2 @@ -1415,6 +1415,7 @@ func (lsn *listenerV2) simulateFulfillment( "name": lsn.job.Name.ValueOrZero(), "publicKey": lsn.job.VRFSpec.PublicKey[:], "maxGasPrice": maxGasPriceWei.ToInt().String(), + "evmChainID": lsn.job.VRFSpec.EVMChainID.String(), }, "jobRun": map[string]interface{}{ "logBlockHash": req.req.Raw().BlockHash.Bytes(), diff --git a/core/services/vrf/v2/listener_v2_test.go b/core/services/vrf/v2/listener_v2_test.go index dd63ec8208e..4da20a2a7e8 100644 --- a/core/services/vrf/v2/listener_v2_test.go +++ b/core/services/vrf/v2/listener_v2_test.go @@ -34,17 +34,17 @@ import ( ) const ( - addEthTxQuery = `INSERT INTO eth_txes (from_address, to_address, encoded_payload, value, gas_limit, state, created_at, meta, subject, evm_chain_id, min_confirmations, pipeline_task_run_id) + addEthTxQuery = `INSERT INTO evm.txes (from_address, to_address, encoded_payload, value, gas_limit, state, created_at, meta, subject, evm_chain_id, min_confirmations, pipeline_task_run_id) VALUES ( $1, $2, $3, $4, $5, $6, NOW(), $7, $8, $9, $10, $11 ) - RETURNING "eth_txes".*` + RETURNING "txes".*` - addConfirmedEthTxQuery = `INSERT INTO eth_txes (nonce, broadcast_at, initial_broadcast_at, error, from_address, to_address, encoded_payload, value, gas_limit, state, created_at, meta, subject, evm_chain_id, min_confirmations, pipeline_task_run_id) + addConfirmedEthTxQuery = `INSERT INTO evm.txes (nonce, broadcast_at, initial_broadcast_at, error, from_address, to_address, encoded_payload, value, gas_limit, state, created_at, meta, subject, evm_chain_id, min_confirmations, pipeline_task_run_id) VALUES ( $1, NOW(), NOW(), NULL, $2, $3, $4, $5, $6, 'confirmed', NOW(), $7, $8, $9, $10, $11 ) - RETURNING "eth_txes".*` + RETURNING "txes".*` ) func txMetaSubIDs(t *testing.T, vrfVersion vrfcommon.Version, subID *big.Int) (*uint64, *string) { diff --git a/core/store/migrate/migrate_test.go b/core/store/migrate/migrate_test.go index 97d0ec5b182..66764a266f0 100644 --- a/core/store/migrate/migrate_test.go +++ b/core/store/migrate/migrate_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -350,7 +351,7 @@ func TestMigrate_101_GenericOCR2(t *testing.T) { require.NoError(t, err) type PluginValues struct { - PluginType job.OCR2PluginType + PluginType types.OCR2PluginType PluginConfig job.JSONConfig } @@ -360,7 +361,7 @@ func TestMigrate_101_GenericOCR2(t *testing.T) { err = db.Get(&pluginValues, sql) require.NoError(t, err) - require.Equal(t, job.Median, pluginValues.PluginType) + require.Equal(t, types.Median, pluginValues.PluginType) require.Equal(t, job.JSONConfig{"juelsPerFeeCoinSource": spec.JuelsPerFeeCoinPipeline}, pluginValues.PluginConfig) err = goose.Down(db.DB, migrationDir) diff --git a/core/store/migrate/migrations/0193_s4_alter_version_type.sql b/core/store/migrate/migrations/0193_s4_alter_version_type.sql new file mode 100644 index 00000000000..36179d5d7f0 --- /dev/null +++ b/core/store/migrate/migrations/0193_s4_alter_version_type.sql @@ -0,0 +1,7 @@ +-- +goose Up + +ALTER TABLE "s4".shared ALTER COLUMN version TYPE NUMERIC; + +-- +goose Down + +ALTER TABLE "s4".shared ALTER COLUMN version TYPE INT USING version::integer; diff --git a/core/store/migrate/migrations/0194_evm_schema.sql b/core/store/migrate/migrations/0194_evm_schema.sql new file mode 100644 index 00000000000..fc55028c16e --- /dev/null +++ b/core/store/migrate/migrations/0194_evm_schema.sql @@ -0,0 +1,164 @@ +-- +goose Up +CREATE SCHEMA evm; +SET search_path TO evm,public; + +ALTER TABLE public.evm_forwarders SET SCHEMA evm; +ALTER TABLE evm.evm_forwarders RENAME TO forwarders; + +ALTER TABLE public.evm_heads SET SCHEMA evm; +ALTER TABLE evm.evm_heads RENAME TO heads; + +ALTER TABLE public.evm_key_states SET SCHEMA evm; +ALTER TABLE evm.evm_key_states RENAME TO key_states; + +ALTER TABLE public.evm_log_poller_blocks SET SCHEMA evm; +ALTER TABLE evm.evm_log_poller_blocks RENAME TO log_poller_blocks; + +ALTER TABLE public.evm_log_poller_filters SET SCHEMA evm; +ALTER TABLE evm.evm_log_poller_filters RENAME TO log_poller_filters; + + + +ALTER TABLE public.evm_upkeep_states SET SCHEMA evm; +ALTER TABLE evm.evm_upkeep_states RENAME TO upkeep_states; + +ALTER TABLE public.eth_receipts SET SCHEMA evm; +ALTER TABLE evm.eth_receipts RENAME TO receipts; + +ALTER TABLE public.eth_tx_attempts SET SCHEMA evm; +ALTER TABLE evm.eth_tx_attempts RENAME TO tx_attempts; + +--------------------- +-- Handle log triggers +--------------------- +DROP TRIGGER IF EXISTS notify_insert_on_evm_logs_topics ON PUBLIC.evm_logs; +DROP FUNCTION IF EXISTS public.notifysavedlogtopics(); + +ALTER TABLE public.evm_logs SET SCHEMA evm; +ALTER TABLE evm.evm_logs RENAME TO logs; + +-- +goose StatementBegin +CREATE OR REPLACE FUNCTION evm.notifysavedlogtopics() RETURNS trigger + LANGUAGE plpgsql +AS $$ +BEGIN + PERFORM pg_notify( + 'evm.insert_on_logs'::text, + -- hex encoded address plus comma separated list of hex encoded topic values + -- e.g. "
:," + encode(NEW.address, 'hex') || ':' || array_to_string(array(SELECT encode(unnest(NEW.topics), 'hex')), ',') + ); + RETURN NULL; +END +$$; + +DROP TRIGGER IF EXISTS notify_insert_on_logs_topics ON evm.logs; +CREATE TRIGGER notify_insert_on_logs_topics AFTER INSERT ON evm.logs FOR EACH ROW EXECUTE PROCEDURE evm.notifysavedlogtopics(); +-- +goose StatementEnd + +--------------------- +-- Handle tx triggers +--------------------- +DROP TRIGGER IF EXISTS notify_eth_tx_insertion on public.eth_txes; +DROP FUNCTION IF EXISTS public.notifyethtxinsertion(); + +ALTER TABLE public.eth_txes SET SCHEMA evm; +ALTER TABLE evm.eth_txes RENAME TO txes; + + +-- +goose StatementBegin +CREATE OR REPLACE FUNCTION evm.notifytxinsertion() RETURNS trigger + LANGUAGE plpgsql + AS $$ + BEGIN + PERFORM pg_notify('evm.insert_on_txes'::text, encode(NEW.from_address, 'hex')); + RETURN NULL; + END + $$; + +DROP TRIGGER IF EXISTS notify_tx_insertion on evm.txes; +CREATE TRIGGER notify_tx_insertion AFTER INSERT ON evm.txes FOR EACH ROW EXECUTE PROCEDURE evm.notifytxinsertion(); +-- +goose StatementEnd + + +-- +goose Down +SET search_path TO evm,public; +ALTER TABLE evm.forwarders SET SCHEMA public; +ALTER TABLE public.forwarders RENAME TO evm_forwarders; + +ALTER TABLE evm.heads SET SCHEMA public; +ALTER TABLE public.heads RENAME TO evm_heads; + +ALTER TABLE evm.key_states SET SCHEMA public; +ALTER TABLE public.key_states RENAME TO evm_key_states; + +ALTER TABLE evm.log_poller_blocks SET SCHEMA public; +ALTER TABLE public.log_poller_blocks RENAME TO evm_log_poller_blocks; + +ALTER TABLE evm.log_poller_filters SET SCHEMA public; +ALTER TABLE public.log_poller_filters RENAME TO evm_log_poller_filters; + +ALTER TABLE evm.upkeep_states SET SCHEMA public; +ALTER table public.upkeep_states RENAME TO evm_upkeep_states; + +ALTER TABLE evm.receipts SET SCHEMA public; +ALTER TABLE public.receipts RENAME TO eth_receipts; + +ALTER TABLE evm.tx_attempts SET SCHEMA public; +ALTER TABLE public.tx_attempts RENAME TO eth_tx_attempts; + + +--------------------- +-- Handle log triggers +--------------------- + +DROP TRIGGER IF EXISTS notify_insert_on_logs_topics ON evm.logs; +DROP FUNCTION IF EXISTS evm.notifysavedlogtopics(); + +ALTER TABLE evm.logs SET SCHEMA public; +ALTER TABLE public.logs RENAME TO evm_logs; + +-- +goose StatementBegin +CREATE OR REPLACE FUNCTION PUBLIC.notifysavedlogtopics() RETURNS trigger + LANGUAGE plpgsql +AS $$ +BEGIN + PERFORM pg_notify( + 'insert_on_evm_logs'::text, + -- hex encoded address plus comma separated list of hex encoded topic values + -- e.g. "
:," + encode(NEW.address, 'hex') || ':' || array_to_string(array(SELECT encode(unnest(NEW.topics), 'hex')), ',') + ); + RETURN NULL; +END +$$; + +DROP TRIGGER IF EXISTS notify_insert_on_evm_logs_topics ON PUBLIC.evm_logs; +CREATE TRIGGER notify_insert_on_evm_logs_topics AFTER INSERT ON PUBLIC.evm_logs FOR EACH ROW EXECUTE PROCEDURE PUBLIC.notifysavedlogtopics(); +-- +goose StatementEnd + +--------------------- +-- Handle tx triggers +--------------------- + +DROP TRIGGER IF EXISTS notify_tx_insertion on evm.txes; +DROP FUNCTION IF EXISTS evm.notifytxinsertion(); + +ALTER TABLE evm.txes SET SCHEMA public; +ALTER TABLE public.txes RENAME TO eth_txes; + +-- +goose StatementBegin +CREATE OR REPLACE FUNCTION public.notifyethtxinsertion() RETURNS trigger + LANGUAGE plpgsql + AS $$ + BEGIN + PERFORM pg_notify('insert_on_eth_txes'::text, encode(NEW.from_address, 'hex')); + RETURN NULL; + END + $$; + +DROP TRIGGER IF EXISTS notify_eth_tx_insertion on public.eth_txes; +CREATE TRIGGER notify_eth_tx_insertion AFTER INSERT ON public.eth_txes FOR EACH ROW EXECUTE PROCEDURE public.notifyethtxinsertion(); +-- +goose StatementEnd + +DROP SCHEMA evm; diff --git a/core/testdata/testspecs/v2_specs.go b/core/testdata/testspecs/v2_specs.go index 4c44f3b9c5e..f2669a6fe9d 100644 --- a/core/testdata/testspecs/v2_specs.go +++ b/core/testdata/testspecs/v2_specs.go @@ -44,6 +44,7 @@ type = "directrequest" schemaVersion = 1 name = "%s" contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" +evmChainID = "0" observationSource = """ ds1 [type=http method=GET url="http://example.com" allowunrestrictednetworkaccess="true"]; ds1_parse [type=jsonparse path="USD"]; @@ -57,6 +58,7 @@ schemaVersion = 1 name = "example eth request event spec" contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" externalJobID = "123e4567-e89b-12d3-a456-426655440004" +evmChainID = "0" observationSource = """ ds1 [type=http method=GET url="http://example.com" allowunrestrictednetworkaccess="true"]; ds1_parse [type=jsonparse path="USD"]; @@ -72,6 +74,7 @@ minContractPaymentLinkJuels = "1000000000000000000000" name = "example eth request event spec with requesters and min contract payment" contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" externalJobID = "123e4567-e89b-12d3-a456-426655440014" +evmChainID = 0 observationSource = """ ds1 [type=http method=GET url="http://example.com" allowunrestrictednetworkaccess="true"]; ds1_parse [type=jsonparse path="USD"]; @@ -85,6 +88,7 @@ schemaVersion = 1 name = "example flux monitor spec" contractAddress = "0x3cCad4715152693fE3BC4460591e3D3Fbd071b42" externalJobID = "123e4567-e89b-12d3-a456-426655440005" +evmChainID = 0 threshold = 0.5 absoluteThreshold = 0.0 # optional @@ -251,6 +255,7 @@ type VRFSpecParams struct { FromAddresses []string PublicKey string ObservationSource string + EVMChainID string RequestedConfsDelay int RequestTimeout time.Duration V2 bool @@ -353,14 +358,16 @@ vrf [type=vrfv2 estimate_gas [type=estimategaslimit to="%s" multiplier="1.1" - data="$(vrf.output)"] + data="$(vrf.output)" +] simulate [type=ethcall to="%s" gas="$(estimate_gas)" gasPrice="$(jobSpec.maxGasPrice)" extractRevertReason=true contract="%s" - data="$(vrf.output)"] + data="$(vrf.output)" +] decode_log->vrf->estimate_gas->simulate `, coordinatorAddress, coordinatorAddress, coordinatorAddress) } @@ -378,26 +385,32 @@ generate_proof [type=vrfv2plus estimate_gas [type=estimategaslimit to="%s" multiplier="1.1" - data="$(generate_proof.output)"] + data="$(generate_proof.output)" +] simulate_fulfillment [type=ethcall to="%s" gas="$(estimate_gas)" gasPrice="$(jobSpec.maxGasPrice)" extractRevertReason=true contract="%s" - data="$(generate_proof.output)"] + data="$(generate_proof.output)" +] decode_log->generate_proof->estimate_gas->simulate_fulfillment `, coordinatorAddress, coordinatorAddress, coordinatorAddress) } if params.ObservationSource != "" { observationSource = params.ObservationSource } + if params.EVMChainID == "" { + params.EVMChainID = "0" + } template := ` externalJobID = "%s" type = "vrf" schemaVersion = 1 name = "%s" coordinatorAddress = "%s" +evmChainID = "%s" batchCoordinatorAddress = "%s" batchFulfillmentEnabled = %v batchFulfillmentGasMultiplier = %s @@ -414,7 +427,7 @@ observationSource = """ """ ` toml := fmt.Sprintf(template, - jobID, name, coordinatorAddress, batchCoordinatorAddress, + jobID, name, coordinatorAddress, params.EVMChainID, batchCoordinatorAddress, params.BatchFulfillmentEnabled, strconv.FormatFloat(batchFulfillmentGasMultiplier, 'f', 2, 64), confirmations, params.RequestedConfsDelay, requestTimeout.String(), publicKey, chunkSize, params.BackoffInitialDelay.String(), params.BackoffMaxDelay.String(), gasLanePrice.String(), observationSource) @@ -438,6 +451,7 @@ observationSource = """ MinIncomingConfirmations: confirmations, PublicKey: publicKey, ObservationSource: observationSource, + EVMChainID: params.EVMChainID, RequestedConfsDelay: params.RequestedConfsDelay, RequestTimeout: requestTimeout, ChunkSize: chunkSize, @@ -492,7 +506,7 @@ func GenerateOCRSpec(params OCRSpecParams) OCRSpec { if params.DS2BridgeName != "" { ds2BridgeName = params.DS2BridgeName } - // set to empty so it defaults to the default evm chain id + evmChainID := "0" if params.EVMChainID != "" { evmChainID = params.EVMChainID diff --git a/core/testdata/tomlspecs/direct-request-spec-cbor.toml b/core/testdata/tomlspecs/direct-request-spec-cbor.toml index 2a51cefef7b..500c4973d88 100644 --- a/core/testdata/tomlspecs/direct-request-spec-cbor.toml +++ b/core/testdata/tomlspecs/direct-request-spec-cbor.toml @@ -3,6 +3,7 @@ schemaVersion = 1 name = "example eth request event spec" contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F90" +evmChainID = 1337 observationSource = """ decode_log [type=ethabidecodelog abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" diff --git a/core/testdata/tomlspecs/direct-request-spec.toml b/core/testdata/tomlspecs/direct-request-spec.toml index d3c866102bc..35c0cc9274e 100644 --- a/core/testdata/tomlspecs/direct-request-spec.toml +++ b/core/testdata/tomlspecs/direct-request-spec.toml @@ -1,5 +1,6 @@ type = "directrequest" schemaVersion = 1 +evmChainID = "0" name = "example eth request event spec" contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F47" diff --git a/core/testdata/tomlspecs/multiword-response-spec.toml b/core/testdata/tomlspecs/multiword-response-spec.toml index 825f96946b1..31da76b797c 100644 --- a/core/testdata/tomlspecs/multiword-response-spec.toml +++ b/core/testdata/tomlspecs/multiword-response-spec.toml @@ -2,6 +2,7 @@ type = "directrequest" schemaVersion = 1 name = "example eth request event spec" contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" +evmChainID = "1337" externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F47" observationSource = """ decode_log [type=ethabidecodelog diff --git a/core/testdata/tomlspecs/ocr-bootstrap-spec.toml b/core/testdata/tomlspecs/ocr-bootstrap-spec.toml index ce12800f634..9df0a861960 100644 --- a/core/testdata/tomlspecs/ocr-bootstrap-spec.toml +++ b/core/testdata/tomlspecs/ocr-bootstrap-spec.toml @@ -2,6 +2,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x27548a32b9aD5D64c5945EaE9Da5337bc3169D15" externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F50" +evmChainID = "0" p2pBootstrapPeers = [ "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", ] diff --git a/core/utils/thread_control.go b/core/utils/thread_control.go new file mode 100644 index 00000000000..8f7fff42496 --- /dev/null +++ b/core/utils/thread_control.go @@ -0,0 +1,44 @@ +package utils + +import ( + "context" + "sync" +) + +var _ ThreadControl = &threadControl{} + +// ThreadControl is a helper for managing a group of goroutines. +type ThreadControl interface { + // Go starts a goroutine and tracks the lifetime of the goroutine. + Go(fn func(context.Context)) + // Close cancels the goroutines and waits for all of them to exit. + Close() +} + +func NewThreadControl() *threadControl { + tc := &threadControl{ + stop: make(chan struct{}), + } + + return tc +} + +type threadControl struct { + threadsWG sync.WaitGroup + stop StopChan +} + +func (tc *threadControl) Go(fn func(context.Context)) { + tc.threadsWG.Add(1) + go func() { + defer tc.threadsWG.Done() + ctx, cancel := tc.stop.NewCtx() + defer cancel() + fn(ctx) + }() +} + +func (tc *threadControl) Close() { + close(tc.stop) + tc.threadsWG.Wait() +} diff --git a/core/utils/thread_control_test.go b/core/utils/thread_control_test.go new file mode 100644 index 00000000000..9001ca7241c --- /dev/null +++ b/core/utils/thread_control_test.go @@ -0,0 +1,27 @@ +package utils + +import ( + "context" + "sync/atomic" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestThreadControl_Close(t *testing.T) { + n := 10 + tc := NewThreadControl() + + finished := atomic.Int32{} + + for i := 0; i < n; i++ { + tc.Go(func(ctx context.Context) { + <-ctx.Done() + finished.Add(1) + }) + } + + tc.Close() + + require.Equal(t, int32(n), finished.Load()) +} diff --git a/core/web/common.go b/core/web/common.go index 0253e0593de..ae2158d153b 100644 --- a/core/web/common.go +++ b/core/web/common.go @@ -9,9 +9,10 @@ import ( ) var ( - ErrMissingChainID = errors.New("evmChainID does not match any local chains") - ErrInvalidChainID = errors.New("invalid evmChainID") - ErrMultipleChains = errors.New("more than one chain available, you must specify evmChainID parameter") + ErrMissingChainID = errors.New("chain id does not match any local chains") + ErrEmptyChainID = errors.New("chainID is empty") + ErrInvalidChainID = errors.New("invalid chain id") + ErrMultipleChains = errors.New("more than one chain available, you must specify chain id parameter") ) func getChain(legacyChains evm.LegacyChainContainer, chainIDstr string) (chain evm.Chain, err error) { @@ -33,9 +34,5 @@ func getChain(legacyChains evm.LegacyChainContainer, chainIDstr string) (chain e return nil, ErrMultipleChains } - chain, err = legacyChains.Default() - if err != nil { - return nil, err - } - return chain, nil + return nil, ErrEmptyChainID } diff --git a/core/web/cosmos_chains_controller_test.go b/core/web/cosmos_chains_controller_test.go index f670076d748..3fc42f3d860 100644 --- a/core/web/cosmos_chains_controller_test.go +++ b/core/web/cosmos_chains_controller_test.go @@ -48,7 +48,7 @@ BlockRate = '6s' BlocksUntilTxTimeout = 30 ConfirmPollPeriod = '1s' FallbackGasPrice = '9.999' -FeeToken = 'ucosm' +GasToken = 'ucosm' GasLimitMultiplier = '1.55555' MaxMsgsPerBatch = 100 OCR2CachePollPeriod = '4s' diff --git a/core/web/cosmos_transfer_controller.go b/core/web/cosmos_transfer_controller.go index 2409a05e6a4..afe0fe16d1e 100644 --- a/core/web/cosmos_transfer_controller.go +++ b/core/web/cosmos_transfer_controller.go @@ -58,9 +58,9 @@ func (tc *CosmosTransfersController) Create(c *gin.Context) { jsonAPIError(c, http.StatusUnprocessableEntity, errors.Errorf("withdrawal source address is missing: %v", tr.FromAddress)) return } - coin, err := denom.ConvertDecCoinToDenom(sdk.NewDecCoinFromDec(tr.Token, tr.Amount), chain.Config().FeeToken()) + coin, err := denom.ConvertDecCoinToDenom(sdk.NewDecCoinFromDec(tr.Token, tr.Amount), chain.Config().GasToken()) if err != nil { - jsonAPIError(c, http.StatusBadRequest, errors.Errorf("unable to convert %s to %s: %v", tr.Token, chain.Config().FeeToken(), err)) + jsonAPIError(c, http.StatusBadRequest, errors.Errorf("unable to convert %s to %s: %v", tr.Token, chain.Config().GasToken(), err)) return } else if !coin.Amount.IsPositive() { jsonAPIError(c, http.StatusBadRequest, errors.Errorf("amount must be greater than zero: %s", coin.Amount)) diff --git a/core/web/eth_keys_controller_test.go b/core/web/eth_keys_controller_test.go index 0ef01257e17..104e487b207 100644 --- a/core/web/eth_keys_controller_test.go +++ b/core/web/eth_keys_controller_test.go @@ -228,7 +228,12 @@ func TestETHKeysController_CreateSuccess(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) - resp, cleanup := client.Post("/v2/keys/evm", nil) + chainURL := url.URL{Path: "/v2/keys/evm"} + query := chainURL.Query() + query.Set("evmChainID", cltest.FixtureChainID.String()) + chainURL.RawQuery = query.Encode() + + resp, cleanup := client.Post(chainURL.String(), nil) defer cleanup() cltest.AssertServerResponse(t, resp, http.StatusOK) @@ -409,7 +414,7 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { assert.NoError(t, err) var count int - err = app.GetSqlxDB().Get(&count, `SELECT count(*) FROM eth_txes WHERE from_address = $1 AND state = 'fatal_error'`, addr) + err = app.GetSqlxDB().Get(&count, `SELECT count(*) FROM evm.txes WHERE from_address = $1 AND state = 'fatal_error'`, addr) require.NoError(t, err) assert.Equal(t, 0, count) @@ -436,7 +441,7 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { assert.Equal(t, false, updatedKey.Disabled) var s string - err = app.GetSqlxDB().Get(&s, `SELECT error FROM eth_txes WHERE from_address = $1 AND state = 'fatal_error'`, addr) + err = app.GetSqlxDB().Get(&s, `SELECT error FROM evm.txes WHERE from_address = $1 AND state = 'fatal_error'`, addr) require.NoError(t, err) assert.Equal(t, "abandoned", s) } diff --git a/core/web/evm_transfer_controller.go b/core/web/evm_transfer_controller.go index 675d978e35f..69d55b54bba 100644 --- a/core/web/evm_transfer_controller.go +++ b/core/web/evm_transfer_controller.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + commontxmgr "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" @@ -146,7 +147,8 @@ func FindTxAttempt(ctx context.Context, timeout time.Duration, etx txmgr.Tx, Fin } // exit if tx attempts are found - if len(etx.TxAttempts) > 0 { + // also validate etx.State != unstarted (ensure proper tx state for tx with attempts) + if len(etx.TxAttempts) > 0 && etx.State != commontxmgr.TxUnstarted { break } tick = time.After(recheckTime) diff --git a/core/web/evm_transfer_controller_test.go b/core/web/evm_transfer_controller_test.go index 51c53a54ef3..70d4c7d5e0b 100644 --- a/core/web/evm_transfer_controller_test.go +++ b/core/web/evm_transfer_controller_test.go @@ -16,8 +16,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" configtest2 "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/models" + "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -53,6 +55,7 @@ func TestTransfersController_CreateSuccess_From(t *testing.T) { FromAddress: key.Address, Amount: amount, SkipWaitTxAttempt: true, + EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -65,7 +68,7 @@ func TestTransfersController_CreateSuccess_From(t *testing.T) { assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Len(t, errors.Errors, 0) - cltest.AssertCount(t, app.GetSqlxDB(), "eth_txes", 1) + cltest.AssertCount(t, app.GetSqlxDB(), "evm.txes", 1) } func TestTransfersController_CreateSuccess_From_WEI(t *testing.T) { @@ -93,6 +96,7 @@ func TestTransfersController_CreateSuccess_From_WEI(t *testing.T) { FromAddress: key.Address, Amount: amount, SkipWaitTxAttempt: true, + EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -105,7 +109,7 @@ func TestTransfersController_CreateSuccess_From_WEI(t *testing.T) { assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Len(t, errors.Errors, 0) - cltest.AssertCount(t, app.GetSqlxDB(), "eth_txes", 1) + cltest.AssertCount(t, app.GetSqlxDB(), "evm.txes", 1) } func TestTransfersController_CreateSuccess_From_BalanceMonitorDisabled(t *testing.T) { @@ -138,6 +142,7 @@ func TestTransfersController_CreateSuccess_From_BalanceMonitorDisabled(t *testin FromAddress: key.Address, Amount: amount, SkipWaitTxAttempt: true, + EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -150,7 +155,7 @@ func TestTransfersController_CreateSuccess_From_BalanceMonitorDisabled(t *testin assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Len(t, errors.Errors, 0) - cltest.AssertCount(t, app.GetSqlxDB(), "eth_txes", 1) + cltest.AssertCount(t, app.GetSqlxDB(), "evm.txes", 1) } func TestTransfersController_TransferZeroAddressError(t *testing.T) { @@ -167,6 +172,7 @@ func TestTransfersController_TransferZeroAddressError(t *testing.T) { DestinationAddress: common.HexToAddress("0xFA01FA015C8A5332987319823728982379128371"), FromAddress: common.HexToAddress("0x0000000000000000000000000000000000000000"), Amount: amount, + EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -201,6 +207,7 @@ func TestTransfersController_TransferBalanceToLowError(t *testing.T) { DestinationAddress: common.HexToAddress("0xFA01FA015C8A5332987319823728982379128371"), Amount: amount, AllowHigherAmounts: false, + EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -238,6 +245,7 @@ func TestTransfersController_TransferBalanceToLowError_ZeroBalance(t *testing.T) DestinationAddress: common.HexToAddress("0xFA01FA015C8A5332987319823728982379128371"), Amount: amount, AllowHigherAmounts: false, + EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -280,7 +288,7 @@ func TestTransfersController_CreateSuccess_eip1559(t *testing.T) { config := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) c.EVM[0].GasEstimator.Mode = ptr("FixedPrice") - + c.EVM[0].ChainID = (*utils.Big)(testutils.FixtureChainID) // NOTE: FallbackPollInterval is used in this test to quickly create TxAttempts // Testing triggers requires committing transactions and does not work with transactional tests c.Database.Listener.FallbackPollInterval = models.MustNewDuration(time.Second) @@ -300,6 +308,7 @@ func TestTransfersController_CreateSuccess_eip1559(t *testing.T) { FromAddress: key.Address, Amount: amount, WaitAttemptTimeout: &timeout, + EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -314,7 +323,7 @@ func TestTransfersController_CreateSuccess_eip1559(t *testing.T) { err = web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, resp), &resource) assert.NoError(t, err) - cltest.AssertCount(t, app.GetSqlxDB(), "eth_txes", 1) + cltest.AssertCount(t, app.GetSqlxDB(), "evm.txes", 1) // check returned data assert.NotEmpty(t, resource.Hash) diff --git a/core/web/jobs_controller_test.go b/core/web/jobs_controller_test.go index b8b68e402d5..d6d3f459a8a 100644 --- a/core/web/jobs_controller_test.go +++ b/core/web/jobs_controller_test.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "net/http" + "net/url" "strconv" "sync" "testing" @@ -186,7 +187,7 @@ func TestJobController_Create_HappyPath(t *testing.T) { name = "example keeper spec" contractAddress = "0x9E40733cC9df84636505f4e6Db28DCa0dC5D1bba" fromAddress = "0xa8037A20989AFcBC51798de9762b351D63ff462e" - evmChainId = 4 + evmChainID = 0 minIncomingConfigurations = 1 externalJobID = "123e4567-e89b-12d3-a456-426655440002" `, @@ -398,7 +399,12 @@ func TestJobsController_FailToCreate_EmptyJsonAttribute(t *testing.T) { func TestJobsController_Index_HappyPath(t *testing.T) { _, client, ocrJobSpecFromFile, _, ereJobSpecFromFile, _ := setupJobSpecsControllerTestsWithJobs(t) - response, cleanup := client.Get("/v2/jobs") + url := url.URL{Path: "/v2/jobs"} + query := url.Query() + query.Set("evmChainID", cltest.FixtureChainID.String()) + url.RawQuery = query.Encode() + + response, cleanup := client.Get(url.String()) t.Cleanup(cleanup) cltest.AssertServerResponse(t, response, http.StatusOK) @@ -653,7 +659,7 @@ func setupJobSpecsControllerTestsWithJobs(t *testing.T) (*cltest.TestApplication client := app.NewHTTPClient(cltest.APIEmailAdmin) var jb job.Job - ocrspec := testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{DS1BridgeName: bridge.Name.String(), DS2BridgeName: bridge2.Name.String()}) + ocrspec := testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{DS1BridgeName: bridge.Name.String(), DS2BridgeName: bridge2.Name.String(), EVMChainID: testutils.FixtureChainID.String()}) err := toml.Unmarshal([]byte(ocrspec.Toml()), &jb) require.NoError(t, err) var ocrSpec job.OCROracleSpec diff --git a/core/web/loader/chain.go b/core/web/loader/chain.go index 77e231ace13..c91c2f02a3b 100644 --- a/core/web/loader/chain.go +++ b/core/web/loader/chain.go @@ -7,6 +7,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) type chainBatcher struct { @@ -17,14 +18,14 @@ func (b *chainBatcher) loadByIDs(_ context.Context, keys dataloader.Keys) []*dat // Create a map for remembering the order of keys passed in keyOrder := make(map[string]int, len(keys)) // Collect the keys to search for - var chainIDs []string + var chainIDs []relay.ChainID for ix, key := range keys { - chainIDs = append(chainIDs, key.String()) + chainIDs = append(chainIDs, relay.ChainID(key.String())) keyOrder[key.String()] = ix } // Fetch the chains - cs, _, err := b.app.EVMORM().Chains(0, -1, chainIDs...) + cs, _, err := b.app.EVMORM().Chains(chainIDs...) if err != nil { return []*dataloader.Result{{Data: nil, Error: err}} } diff --git a/core/web/loop_registry.go b/core/web/loop_registry.go index 4bbcef2b44a..345ff03704e 100644 --- a/core/web/loop_registry.go +++ b/core/web/loop_registry.go @@ -48,19 +48,12 @@ func (l *LoopRegistryServer) discoveryHandler(w http.ResponseWriter, req *http.R w.Header().Set("Content-Type", "application/json") var groups []*targetgroup.Group - for _, registeredPlugin := range l.registry.List() { - // create a metric target for each running plugin - target := &targetgroup.Group{ - Targets: []model.LabelSet{ - // target address will be called by external prometheus - {model.AddressLabel: model.LabelValue(fmt.Sprintf("%s:%d", l.discoveryHostName, l.exposedPromPort))}, - }, - Labels: map[model.LabelName]model.LabelValue{ - model.MetricsPathLabel: model.LabelValue(pluginMetricPath(registeredPlugin.Name)), - }, - } + // add node metrics to service discovery + groups = append(groups, metricTarget(l.discoveryHostName, l.exposedPromPort, "/metrics")) - groups = append(groups, target) + // add all the plugins + for _, registeredPlugin := range l.registry.List() { + groups = append(groups, metricTarget(l.discoveryHostName, l.exposedPromPort, pluginMetricPath(registeredPlugin.Name))) } b, err := l.jsonMarshalFn(groups) @@ -80,6 +73,18 @@ func (l *LoopRegistryServer) discoveryHandler(w http.ResponseWriter, req *http.R } +func metricTarget(hostName string, port int, path string) *targetgroup.Group { + return &targetgroup.Group{ + Targets: []model.LabelSet{ + // target address will be called by external prometheus + {model.AddressLabel: model.LabelValue(fmt.Sprintf("%s:%d", hostName, port))}, + }, + Labels: map[model.LabelName]model.LabelValue{ + model.MetricsPathLabel: model.LabelValue(path), + }, + } +} + // pluginMetricHandlers routes from endpoints published in service discovery to the the backing LOOP endpoint func (l *LoopRegistryServer) pluginMetricHandler(gc *gin.Context) { pluginName := gc.Param("name") diff --git a/core/web/loop_registry_test.go b/core/web/loop_registry_test.go index 5f737952aec..58a88dad21d 100644 --- a/core/web/loop_registry_test.go +++ b/core/web/loop_registry_test.go @@ -1,6 +1,7 @@ package web_test import ( + "encoding/json" "fmt" "io" "net/http" @@ -8,6 +9,9 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/discovery/targetgroup" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -67,7 +71,13 @@ func TestLoopRegistry(t *testing.T) { // shim a reference to the promserver that is running in our mock loop // this ensures the client.Get calls below have a reference to mock loop impl - expectedEndPoint := "/plugins/mockLoopImpl/metrics" + expectedLooppEndPoint, expectedCoreEndPoint := "/plugins/mockLoopImpl/metrics", "/metrics" + + // note we expect this to be an ordered result + expectedLabels := []model.LabelSet{ + model.LabelSet{"__metrics_path__": model.LabelValue(expectedCoreEndPoint)}, + model.LabelSet{"__metrics_path__": model.LabelValue(expectedLooppEndPoint)}, + } require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) require.NoError(t, app.Start(testutils.Context(t))) @@ -97,12 +107,22 @@ func TestLoopRegistry(t *testing.T) { b, err := io.ReadAll(resp.Body) require.NoError(t, err) t.Logf("discovery response %s", b) - require.Contains(t, string(b), expectedEndPoint) + var got []*targetgroup.Group + require.NoError(t, json.Unmarshal(b, &got)) + + gotLabels := make([]model.LabelSet, 0) + for _, ls := range got { + gotLabels = append(gotLabels, ls.Labels) + } + assert.Equal(t, len(expectedLabels), len(gotLabels)) + for i := range expectedLabels { + assert.EqualValues(t, expectedLabels[i], gotLabels[i]) + } }) t.Run("plugin metrics OK", func(t *testing.T) { // plugin name `mockLoopImpl` matches key in PluginConfigs - resp, cleanup := client.Get(expectedEndPoint) + resp, cleanup := client.Get(expectedLooppEndPoint) t.Cleanup(cleanup) cltest.AssertServerResponse(t, resp, http.StatusOK) @@ -117,6 +137,17 @@ func TestLoopRegistry(t *testing.T) { require.Contains(t, string(b), expectedMetric) }) + t.Run("core metrics OK", func(t *testing.T) { + // core node metrics endpoint + resp, cleanup := client.Get(expectedCoreEndPoint) + t.Cleanup(cleanup) + cltest.AssertServerResponse(t, resp, http.StatusOK) + + b, err := io.ReadAll(resp.Body) + require.NoError(t, err) + t.Logf("core metrics response %s", b) + }) + t.Run("no existent plugin metrics ", func(t *testing.T) { // request plugin that doesn't exist resp, cleanup := client.Get("/plugins/noexist/metrics") diff --git a/core/web/pipeline_runs_controller_test.go b/core/web/pipeline_runs_controller_test.go index 4af7a761827..4637b1836bf 100644 --- a/core/web/pipeline_runs_controller_test.go +++ b/core/web/pipeline_runs_controller_test.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "net/http" + "net/url" "strconv" "strings" "testing" @@ -149,7 +150,12 @@ func TestPipelineRunsController_CreateNoBody_HappyPath(t *testing.T) { func TestPipelineRunsController_Index_GlobalHappyPath(t *testing.T) { client, jobID, runIDs := setupPipelineRunsControllerTests(t) - response, cleanup := client.Get("/v2/pipeline/runs") + url := url.URL{Path: "/v2/pipeline/runs"} + query := url.Query() + query.Set("evmChainID", cltest.FixtureChainID.String()) + url.RawQuery = query.Encode() + + response, cleanup := client.Get(url.String()) defer cleanup() cltest.AssertServerResponse(t, response, http.StatusOK) @@ -266,6 +272,7 @@ func setupPipelineRunsControllerTests(t *testing.T) (cltest.HTTPClientCleaner, i schemaVersion = 1 externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F46" contractAddress = "%s" + evmChainID = "0" p2pBootstrapPeers = [ "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", ] diff --git a/core/web/resolver/query.go b/core/web/resolver/query.go index 22b95a2d2ef..e9fd18cf19a 100644 --- a/core/web/resolver/query.go +++ b/core/web/resolver/query.go @@ -15,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/utils/stringutils" ) @@ -68,7 +69,7 @@ func (r *Resolver) Chain(ctx context.Context, args struct{ ID graphql.ID }) (*Ch return nil, err } - cs, _, err := r.App.EVMORM().Chains(0, -1, string(args.ID)) + cs, _, err := r.App.EVMORM().Chains(relay.ChainID(args.ID)) if err != nil { return nil, err } @@ -94,12 +95,20 @@ func (r *Resolver) Chains(ctx context.Context, args struct { offset := pageOffset(args.Offset) limit := pageLimit(args.Limit) - page, count, err := r.App.EVMORM().Chains(offset, limit) + chains, count, err := r.App.EVMORM().Chains() if err != nil { return nil, err } + // bound the chain results + if offset >= len(chains) { + return nil, fmt.Errorf("offset %d out of range", offset) + } + end := len(chains) + if limit > 0 && offset+limit < end { + end = offset + limit + } - return NewChainsPayload(page, int32(count)), nil + return NewChainsPayload(chains[offset:end], int32(count)), nil } // FeedsManager retrieves a feeds manager by id. diff --git a/core/web/resolver/spec_test.go b/core/web/resolver/spec_test.go index 8c6dadc880e..c4efbb65825 100644 --- a/core/web/resolver/spec_test.go +++ b/core/web/resolver/spec_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/assets" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -515,7 +516,7 @@ func TestResolver_OCR2Spec(t *testing.T) { Relay: relay.EVM, RelayConfig: relayConfig, TransmitterID: null.StringFrom(transmitterAddress.String()), - PluginType: job.Median, + PluginType: types.Median, PluginConfig: pluginConfig, }, }, nil) diff --git a/core/web/resolver/testdata/config-empty-effective.toml b/core/web/resolver/testdata/config-empty-effective.toml index 8c3eef53f6a..45e92a147d3 100644 --- a/core/web/resolver/testdata/config-empty-effective.toml +++ b/core/web/resolver/testdata/config-empty-effective.toml @@ -1,4 +1,3 @@ -ExplorerURL = '' InsecureFastScrypt = false RootDir = '~/.chainlink' ShutdownGracePeriod = '5s' diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index 96f24b1955c..ff7eb832c9c 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -1,4 +1,3 @@ -ExplorerURL = 'http://explorer.url' InsecureFastScrypt = true RootDir = 'test/root/dir' ShutdownGracePeriod = '10s' @@ -324,7 +323,7 @@ BlockRate = '1m0s' BlocksUntilTxTimeout = 12 ConfirmPollPeriod = '1s' FallbackGasPrice = '0.001' -FeeToken = 'ucosm' +GasToken = 'ucosm' GasLimitMultiplier = '1.2' MaxMsgsPerBatch = 17 OCR2CachePollPeriod = '1m0s' diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index d6b38349b83..665de9be8cb 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -1,4 +1,3 @@ -ExplorerURL = '' InsecureFastScrypt = false RootDir = 'my/root/dir' ShutdownGracePeriod = '5s' @@ -456,7 +455,7 @@ BlockRate = '6s' BlocksUntilTxTimeout = 30 ConfirmPollPeriod = '1s' FallbackGasPrice = '0.015' -FeeToken = 'ucosm' +GasToken = 'ucosm' GasLimitMultiplier = '1.5' MaxMsgsPerBatch = 13 OCR2CachePollPeriod = '4s' @@ -474,7 +473,7 @@ BlockRate = '6s' BlocksUntilTxTimeout = 20 ConfirmPollPeriod = '1s' FallbackGasPrice = '0.015' -FeeToken = 'ucosm' +GasToken = 'ucosm' GasLimitMultiplier = '1.5' MaxMsgsPerBatch = 100 OCR2CachePollPeriod = '4s' diff --git a/core/web/resolver/testdata/config-multi-chain.toml b/core/web/resolver/testdata/config-multi-chain.toml index eee786e69bf..543fb3156bd 100644 --- a/core/web/resolver/testdata/config-multi-chain.toml +++ b/core/web/resolver/testdata/config-multi-chain.toml @@ -72,7 +72,7 @@ WSURL = 'wss://web.socket/test/bar' [[Cosmos]] ChainID = 'Ibiza-808' Bech32Prefix = 'wasm' -FeeToken = 'ucosm' +GasToken = 'ucosm' MaxMsgsPerBatch = 13 [[Cosmos.Nodes]] @@ -83,7 +83,7 @@ TendermintURL = 'http://columbus.cosmos.com' ChainID = 'Malaga-420' Bech32Prefix = 'wasm' BlocksUntilTxTimeout = 20 -FeeToken = 'ucosm' +GasToken = 'ucosm' [[Cosmos.Nodes]] Name = 'secondary' diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 5ce56b429cb..aa98a138c86 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -9,25 +9,57 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [dev] +### Removed + +- Removed support for sending telemetry to the deprecated Explorer service. All nodes will have to remove `Explorer` related keys from TOML configuration and env vars. +- Removed default evmChainID logic where evmChainID was implicitly injected into the jobspecs based on node EVM chainID toml configuration. All newly created jobs(that have evmChainID field) will have to explicitly define evmChainID in the jobspec. +- Removed keyset migration that migrated v1 keys to v2 keys. All keys should've been migrated by now, and we don't permit creation of new v1 keys anymore + + All nodes will have to remove the following secret configurations: + * `Explorer.AccessKey` + * `Explorer.Secret` + + All nodes will have to remove the following configuration field: `ExplorerURL` + ### Fixed - - Unauthenticated users executing CLI commands previously generated a confusing error log, which is now removed: +- Unauthenticated users executing CLI commands previously generated a confusing error log, which is now removed: ```[ERROR] Error in transaction, rolling back: session missing or expired, please login again pg/transaction.go:118 ``` - - Fixed a bug that was preventing job runs to be displayed when the job `chainID` was disabled. -- `chainlink txs evm create` returns a transaction hash for the attempted transaction in the CLI. Previously only the sender, receipient and `unstarted` state were returned. +- Fixed a bug that was preventing job runs to be displayed when the job `chainID` was disabled. +- `chainlink txs evm create` returns a transaction hash for the attempted transaction in the CLI. Previously only the sender, recipient and `unstarted` state were returned. +- Fixed a bug when when `evmChainId` is requested instead of `id` or `evm-chain-id` in CLI error verbatim -... ## 2.5.0 - UNRELEASED +======= + +- Unauthenticated users executing CLI commands previously generated a confusing error log, which is now removed: + ``` + [ERROR] Error in transaction, rolling back: session missing or expired, please login again pg/transaction.go:118 + ``` +- Fixed a bug that was preventing job runs to be displayed when the job `chainID` was disabled. +- `chainlink txs evm create` returns a transaction hash for the attempted transaction in the CLI. Previously only the sender, receipient and `unstarted` state were returned. + +### Added + +- New prometheus metrics for mercury: + - `mercury_price_feed_missing` + - `mercury_price_feed_errors` + Nops may wish to add alerting on these. + + ### Upcoming Required Configuration Change - Starting in 2.6.0, chainlink nodes will no longer allow insecure configuration for production builds. Any TOML configuration that sets the following line will fail validation checks in `node start` or `node validate`: + ``` AllowSimplePasswords=true ``` - To migrate on production builds, update the database password set in Database.URL to be 16 - 50 characters without leading or trailing whitespace. URI parsing rules apply to the chosen password - refer to [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) for special character escape rules. - +### Added + +- Various Functions improvements ## 2.4.0 - 2023-08-21 diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 2bda2c9160a..f956d14c7aa 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -20,19 +20,12 @@ HTTPURL = 'https://foo.bar' # Required ## Global ```toml -ExplorerURL = 'ws://explorer.url' # Example InsecureFastScrypt = false # Default RootDir = '~/.chainlink' # Default ShutdownGracePeriod = '5s' # Default ``` -### ExplorerURL -```toml -ExplorerURL = 'ws://explorer.url' # Example -``` -ExplorerURL is the websocket URL used by the node to push stats. This variable is required to deliver telemetry. - ### InsecureFastScrypt :warning: **_ADVANCED_**: _Do not change this setting unless you know what you are doing._ ```toml @@ -5140,7 +5133,7 @@ BlockRate = '6s' # Default BlocksUntilTxTimeout = 30 # Default ConfirmPollPeriod = '1s' # Default FallbackGasPrice = '0.015' # Default -FeeToken = 'ucosm' # Default +GasToken = 'ucosm' # Default GasLimitMultiplier = '1.5' # Default MaxMsgsPerBatch = 100 # Default OCR2CachePollPeriod = '4s' # Default @@ -5191,11 +5184,11 @@ FallbackGasPrice = '0.015' # Default ``` FallbackGasPrice sets a fallback gas price to use when the estimator is not available. -### FeeToken +### GasToken ```toml -FeeToken = 'ucosm' # Default +GasToken = 'ucosm' # Default ``` -FeeToken is the token denomination which is being used to pay gas fees on this chain. +GasToken is the token denomination which is being used to pay gas fees on this chain. ### GasLimitMultiplier ```toml diff --git a/docs/SECRETS.md b/docs/SECRETS.md index 3bbf51cae6f..af316cab14b 100644 --- a/docs/SECRETS.md +++ b/docs/SECRETS.md @@ -51,30 +51,6 @@ AllowSimplePasswords skips the password complexity check normally enforced on UR Environment variable: `CL_DATABASE_ALLOW_SIMPLE_PASSWORDS` -## Explorer -```toml -[Explorer] -AccessKey = "access_key" # Example -Secret = "secret" # Example -``` - - -### AccessKey -```toml -AccessKey = "access_key" # Example -``` -AccessKey is the access key for authenticating with the Explorer. - -Environment variable: `CL_EXPLORER_ACCESS_KEY` - -### Secret -```toml -Secret = "secret" # Example -``` -Secret is the secret for authenticating with the Explorer. - -Environment variable: `CL_EXPLORER_SECRET` - ## Password ```toml [Password] @@ -135,6 +111,7 @@ Environment variable: `CL_PROMETHEUS_AUTH_TOKEN` Username = "A-Mercury-Username" # Example Password = "A-Mercury-Password" # Example URL = "https://example.com" # Example +LegacyURL = "https://example.v1.com" # Example ``` @@ -154,7 +131,13 @@ Password is used for basic auth of the Mercury endpoint ```toml URL = "https://example.com" # Example ``` -URL is the Mercury endpoint URL which is used by OCR2 Automation to access Mercury price feed +URL is the Mercury endpoint base URL used to access Mercury price feed + +### LegacyURL +```toml +LegacyURL = "https://example.v1.com" # Example +``` +LegacyURL is the Mercury legacy endpoint base URL used to access Mercury v0.2 price feed ## Threshold ```toml diff --git a/go.mod b/go.mod index 19efff0277c..2e580e19dc8 100644 --- a/go.mod +++ b/go.mod @@ -66,16 +66,16 @@ require ( github.com/shirou/gopsutil/v3 v3.23.8 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512 - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4 + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230912195355-fec1da7953fc github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 - github.com/smartcontractkit/ocr2keepers v0.7.21 + github.com/smartcontractkit/ocr2keepers v0.7.23 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb - github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e - github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e + github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 + github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wsrpc v0.7.2 github.com/spf13/cast v1.5.1 github.com/stretchr/testify v1.8.4 diff --git a/go.sum b/go.sum index 57938ebab7d..3db218d6c93 100644 --- a/go.sum +++ b/go.sum @@ -1375,10 +1375,10 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512 h1:DojChlaudA1HAxwQPKmt/EDf36OUeFJ0LJBYClauMyU= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4 h1:yArUq/0t126bl8BRtjLCf2NuHK35CDIkhc3M5P46apc= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230912195355-fec1da7953fc h1:mQCCjnDz2I1XlYv/fDyFnEB8ryAchlpz12Eg0f7n/N0= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230912195355-fec1da7953fc/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca h1:x7M0m512gtXw5Z4B1WJPZ52VgshoIv+IvHqQ8hsH4AE= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 h1:ByVauKFXphRlSNG47lNuxZ9aicu+r8AoNp933VRPpCw= @@ -1389,16 +1389,16 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 h1:rzbqGoScs9VHGnyCKF7AoQEuUfwJnzcKmGIfaczeanA= github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.21 h1:64CNFoUYVpoJqhQ39WTPIEKVKB5Z/wderX0pIsv/tbA= -github.com/smartcontractkit/ocr2keepers v0.7.21/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= +github.com/smartcontractkit/ocr2keepers v0.7.23 h1:hvMCHm9zTOKGELc40n+JLGmbiW1tkFnHW17qAtoVews= +github.com/smartcontractkit/ocr2keepers v0.7.23/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb/go.mod h1:HNUu4cJekUdsJbwRBCiOybtkPJEfGRELQPe2tkoDEyk= -github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e h1:faa7bAs8xCVsnJoNmAtV18la0wqBoaWSWFqNdjkPdAw= -github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= -github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e h1:JMCSFOQIYOh7zUYi9C3UQG9Lz5ECNejTURBN+Khhwz4= -github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= +github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= +github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= +github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= +github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= github.com/smartcontractkit/wsrpc v0.7.2 h1:iBXzMeg7vc5YoezIQBq896y25BARw7OKbhrb6vPbtRQ= github.com/smartcontractkit/wsrpc v0.7.2/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= diff --git a/integration-tests/Makefile b/integration-tests/Makefile index 110c119df75..287bb939635 100644 --- a/integration-tests/Makefile +++ b/integration-tests/Makefile @@ -78,30 +78,6 @@ run: # Need to set network first in case it's unset. Doesn't matter for the runn ## All commands will use 16 threads to run tests in parallel. To change this, use -test.parallel n # Smoke -.PHONY: test_smoke_raw # Run smoke tests without any gotestfmt or default args -test_smoke_raw: - go test $(args) ./smoke - -.PHONY: test_smoke -test_smoke: install_gotestfmt ## Run all smoke tests - TEST_LOG_LEVEL="disabled" \ - go test -timeout 24h -count=1 -json $(args) ./smoke 2>&1 | tee /tmp/gotest.log | gotestfmt - -.PHONY: test_smoke_simulated -test_smoke_simulated: install_gotestfmt ## Run all smoke tests on simulated blockchain - TEST_LOG_LEVEL="disabled" \ - SELECTED_NETWORKS="SIMULATED,SIMULATED_1,SIMULATED_2" \ - go test -timeout 1h -count=1 -json $(args) ./smoke 2>&1 | tee /tmp/gotest.log | gotestfmt - -.PHONY: test_smoke_verbose -test_smoke_verbose: ## Run all smoke tests with verbose logging - go test -timeout 24h -count=1 -v $(args) ./smoke - -.PHONY: test_smoke_simulated_verbose -test_smoke_simulated_verbose: ## Run all smoke tests with verbose logging - SELECTED_NETWORKS="SIMULATED,SIMULATED_1,SIMULATED_2" \ - go test -timeout 24h -count=1 -v $(args) ./smoke - .PHONY: test_smoke_product test_smoke_product: ## Run smoke tests for specific product ex: make test_smoke_product product="cron" args="--focus @cron -p" ARGS="$(args)" PRODUCT=$(product) ./scripts/run_product_tests diff --git a/integration-tests/README.md b/integration-tests/README.md index 3a2a59e0fbf..c0b673fa92b 100644 --- a/integration-tests/README.md +++ b/integration-tests/README.md @@ -2,205 +2,40 @@ Here lives the integration tests for chainlink, utilizing our [chainlink-testing-framework](https://github.com/smartcontractkit/chainlink-testing-framework). -## Full Setup +## NOTE: Move to Testcontainers -Prerequisites to run the tests from your local machine. Best for debugging and developing new tests, or checking changes to the framework. This can be a bit complex however, so if you just want to run the tests, see the [Just Run](#just-run) section. +If you have previously run these smoke tests using GitHub Actions or some sort of Kubernetes setup, that method is no longer necessary. We have moved the majority of our tests to utilize plain Docker containers (with the help of [Testcontainers](https://golang.testcontainers.org/)). This should make tests faster, more stable, and enable you to run them on your local machine without much hassle. -
- Details +## Requirements -### Install Dependencies +1. [Go](https://go.dev/) +2. [Docker](https://www.docker.com/) +3. You'll probably want to [increase the resources available to Docker](https://stackoverflow.com/questions/44533319/how-to-assign-more-memory-to-docker-container) as most tests require quite a few containers (e.g. OCR requires 6 Chainlink nodes, 6 databases, a simulated blockchain, and a mock server). -Run the below command to install all dependencies. +## Configure -```sh -make install_qa_tools -``` +See the [example.env](./example.env) file for environment variables you can set to configure things like network settings, Chainlink version, and log level. Remember to use `source .env` to activate your settings. -Or you can choose to do it manually. +## Build -
- Install Go +If you'd like to run the tests on a local build of Chainlink, you can point to your own docker image, or build a fresh one with `make`. - [Install](https://go.dev/doc/install) -
+`make build_docker_image image= tag=` -
- Install NodeJS +e.g. - [Install](https://nodejs.org/en/download/) -
+`make build_docker_image image=chainlink tag=test-tag` -
- Install Helm Charts +## Run - [Install Helm](https://helm.sh/docs/intro/install/#through-package-managers) if you don't already have it. Then add necessary charts with the below commands. +`go test ./smoke/_test.go` - ```sh - helm repo add chainlink-qa https://raw.githubusercontent.com/smartcontractkit/qa-charts/gh-pages/ - helm repo add bitnami https://charts.bitnami.com/bitnami - helm repo update - ``` +It's generally recommended to run only one test at a time on a local machine as it needs a lot of docker containers and can peg your resources otherwise. You will see docker containers spin up on your machine for each component of the test where you can inspect logs. -
+## Analyze -## Connect to a Kubernetes Cluster +You can see the results of each test in the terminal with normal `go test` output. If a test fails, logs of each Chainlink container will dump into the `smoke/logs/` folder for later analysis. You can also see these logs in CI uploaded as GitHub artifacts. -Integration tests require a connection to an actively running kubernetes cluster. [Minikube](https://minikube.sigs.k8s.io/docs/start/) -can work fine for some tests, but in order to run more rigorous tests, or to run with any parallelism, you'll need to either -increase minikube's resources significantly, or get a more substantial cluster. -This is necessary to deploy ephemeral testing environments, which include external adapters, chainlink nodes and their DBs, -as well as some simulated blockchains, all depending on the types of tests and networks being used. +## Running Soak, Performance, Benchmark, and Chaos Tests -### Setup Kubernetes Cluster using k3d - -[k3d](https://k3d.io/) is a lightweight wrapper to run k3s (a lightweight kubernetes distribution) in docker. It's a great way to run a local kubernetes cluster for testing. -To create a new cluster you can run: - -```sh -k3d cluster create test-k8s --registry-create test-k8s-registry:0.0.0.0:5000 -``` - -This will create a cluster with a local registry running on port 5000. You can then use the registry to push images to and pull images from. - -To build and push chainlink image to the registry you can run: - -```sh -make build_push_docker_image -```` - -To stop the cluster you can run: - -```sh -k3d cluster stop test-k8s -``` - -To start an existing cluster you can run: - -```sh -k3d cluster start test-k8s -``` - -## Configure Environment - -See the [example.env](./example.env) file and use it as a template for your own `.env` file. This allows you to configure general settings like what name to associate with your tests, and which Chainlink version to use when running them. - -You can also specify `EVM_KEYS` and `EVM_URLS` for running on live chains, or use specific identifiers as shown in the [example.env](./example.env) file. - -Other `EVM_*` variables are retrieved when running with the `@general` tag, and is helpful for doing quick sanity checks on new chains or when tweaking variables. - -**The tests will not automatically load your .env file. Remember to run `source .env` for changes to take effect.** - -## How to Run - -Most of the time, you'll want to run tests on a simulated chain, for the purposes of speed and cost. - -### Smoke - -Run all smoke tests with the below command. Will use your `SELECTED_NETWORKS` env var for which network to run on. - -```sh -make test_smoke # Run all smoke tests on the chosen SELECTED_NETWORKS -SELECTED_NETWORKS="GOERLI" make test_smoke # Run all smoke tests on GOERLI network -make test_smoke_simulated # Run all smoke tests on a simulated network -``` - -Run all smoke tests in parallel, only using simulated blockchains. *Note: As of now, you can only run tests in parallel on simulated chains, not on live ones. Running on parallel tests on live chains will give errors* - -```sh -make test_smoke_simulated args="-test.parallel=" -``` - -You can also run specific tests and debug tests in vscode by setting up your .vscode/settings.json with this information. Just replace all the "" with your information before running a test. - -```json -{ - "makefile.extensionOutputFolder": "./.vscode", - "go.testEnvVars": { - "LOG_LEVEL": "debug", - "SELECTED_NETWORKS": "SIMULATED,SIMULATED_1,SIMULATED_2", - "CHAINLINK_IMAGE":".dkr.ecr.us-west-2.amazonaws.com/chainlink", - "CHAINLINK_VERSION":"develop", - "CHAINLINK_ENV_USER":"", - "TEST_LOG_LEVEL":"debug", - "AWS_ACCESS_KEY_ID":"", - "AWS_SECRET_ACCESS_KEY":"", - "AWS_SESSION_TOKEN":"" - }, - "go.testTimeout": "900s" -} -``` - -You can also run your tests inside of kubernetes instead of from locally to reduce local resource usage and the number of ports that get forwarded to the cluster. This is not recommended for normal developement since building and pushing the image can be time heavy depending on your internet upload speeds. To do this you will want to either pull down an already built chainlink-tests image or build one yourself. To build and push one yourself you can run: - -```sh -make build_test_image tag= base_tag=latest suite="smoke soak chaos reorg migration performance" push=true -``` - -Once that is done building you can add this to your go.testEnvVars in .vscode/settings.json with the correct account number and tag filled out. - -```json - "TEST_SUITE": "smoke", - "TEST_ARGS": "-test.timeout 30m", - "ENV_JOB_IMAGE":".dkr.ecr.us-west-2.amazonaws.com/chainlink-env-tests:", -``` - -Once that is done you can run/debug your test using the vscode test view just like normal. - -### Soak - -Currently we have 2 soak tests, both can be triggered using make commands. - -```sh -make test_soak_ocr -make test_soak_keeper -``` - -Soak tests will pull all their network information from the env vars that you can set in the `.env` file. *Reminder to run `source .env` for changes to take effect.* - -To configure specific parameters of how the soak tests run (e.g. test length, number of contracts), adjust the values in your `.env` file, you can use `example.env` as reference - - -#### Running with custom image -On each PR navigate to the `integration-tests` job, here you will find the images for both chainlink-tests and core. In your env file you need to replace: - -`ENV_JOB_IMAGE="image-location/chainlink-tests:"` - -`CHAINLINK_IMAGE="public.ecr.aws/chainlink/chainlink"` - -`export CHAINLINK_VERSION=""` - -After all the env vars are exported, run the tests. This will kick off a remote runner that will be in charge of running the tests. Locally the test should pass quickly and a namespace will be displayed in the output e.g -`INF Creating new namespace Namespace=soak-ocr-goerli-testnet-957b2` - -#### Logs and monitoring -- Pod logs: `kubectl logs -n soak-ocr-goerli-testnet-957b2 -c node -f chainlink-0-1` -- Remote runner logs: `kubectl logs -n soak-ocr-goerli-testnet-957b2 -f remote-runner-cs2as` -- Navigate to Grafana chainlink testing insights for all logs - -### Performance - -Currently, all performance tests are only run on simulated blockchains. - -```sh -make test_perf -``` - -## Common Issues - -- When upgrading to a new version, it's possible the helm charts have changed. There are a myriad of errors that can result from this, so it's best to just try running `helm repo update` when encountering an error you're unsure of. -- Docker failing to pull image, make sure you are referencing the correct ECR repo in AWS since develop images are not pushed to the public one. - - If tests hang for some time this is usually the case, so make sure to check the logs each time tests are failing to start - -
- - -## Just Run - -If you're making changes to chainlink code, or just want to run some tests without a complex setup, follow the below steps. - -1. [Install Go](https://go.dev/doc/install) -2. [Install GitHub CLI](https://cli.github.com/) -3. Authenticate with GitHub CLI: `gh auth login` -4. `make run` -5. Follow the setup wizard and watch your tests run in the GitHub Action. \ No newline at end of file +These tests remain bound to a Kubernetes run environment, and require more complex setup and running instructions not documented here. We endeavor to make these easier to run and configure, but for the time being please seek a member of the QA/Test Tooling team if you want to run these. diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index 82187fd0cb8..e37c3738ff8 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -19,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink-env/environment" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/testreporters" "github.com/smartcontractkit/chainlink-testing-framework/utils" @@ -251,7 +252,7 @@ func TeardownSuite( failingLogLevel zapcore.Level, // Examines logs after the test, and fails the test if any Chainlink logs are found at or above provided level clients ...blockchain.EVMClient, ) error { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) if err := testreporters.WriteTeardownLogs(t, env, optionalTestReporter, failingLogLevel); err != nil { return errors.Wrap(err, "Error dumping environment logs, leaving environment running for manual retrieval") } @@ -295,7 +296,7 @@ func TeardownRemoteSuite( optionalTestReporter testreporters.TestReporter, // Optionally pass in a test reporter to log further metrics client blockchain.EVMClient, ) error { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) var err error if err = testreporters.SendReport(t, namespace, "./", optionalTestReporter); err != nil { l.Warn().Err(err).Msg("Error writing test report") diff --git a/integration-tests/actions/automation_ocr_helpers.go b/integration-tests/actions/automation_ocr_helpers.go index bfea6ec302c..fb94d6109b4 100644 --- a/integration-tests/actions/automation_ocr_helpers.go +++ b/integration-tests/actions/automation_ocr_helpers.go @@ -13,7 +13,7 @@ import ( "github.com/lib/pq" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "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/v2/core/store/models" @@ -48,7 +48,7 @@ func BuildAutoOCR2ConfigVarsWithKeyIndex( deltaStage time.Duration, keyIndex int, ) (contracts.OCRv2Config, error) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) S, oracleIdentities, err := GetOracleIdentitiesWithKeyIndex(chainlinkNodes, keyIndex) if err != nil { return contracts.OCRv2Config{}, err @@ -172,7 +172,7 @@ func CreateOCRKeeperJobs( keyIndex int, registryVersion ethereum.KeeperRegistryVersion, ) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) bootstrapNode := chainlinkNodes[0] bootstrapP2PIds, err := bootstrapNode.MustReadP2PKeys() require.NoError(t, err, "Shouldn't fail reading P2P keys from bootstrap node") diff --git a/integration-tests/actions/automation_ocr_helpers_local.go b/integration-tests/actions/automation_ocr_helpers_local.go index dce55e42275..86738b0247d 100644 --- a/integration-tests/actions/automation_ocr_helpers_local.go +++ b/integration-tests/actions/automation_ocr_helpers_local.go @@ -4,17 +4,14 @@ package actions import ( "encoding/json" "fmt" - "testing" "time" "github.com/ethereum/go-ethereum/common" "github.com/lib/pq" "github.com/pkg/errors" - "github.com/rs/zerolog/log" - "github.com/stretchr/testify/require" + "github.com/rs/zerolog" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" @@ -30,24 +27,23 @@ import ( ) func BuildAutoOCR2ConfigVarsLocal( - t *testing.T, + l zerolog.Logger, chainlinkNodes []*client.ChainlinkClient, registryConfig contracts.KeeperRegistrySettings, registrar string, deltaStage time.Duration, ) (contracts.OCRv2Config, error) { - return BuildAutoOCR2ConfigVarsWithKeyIndexLocal(t, chainlinkNodes, registryConfig, registrar, deltaStage, 0) + return BuildAutoOCR2ConfigVarsWithKeyIndexLocal(l, chainlinkNodes, registryConfig, registrar, deltaStage, 0) } func BuildAutoOCR2ConfigVarsWithKeyIndexLocal( - t *testing.T, + l zerolog.Logger, chainlinkNodes []*client.ChainlinkClient, registryConfig contracts.KeeperRegistrySettings, registrar string, deltaStage time.Duration, keyIndex int, ) (contracts.OCRv2Config, error) { - l := utils.GetTestLogger(t) S, oracleIdentities, err := GetOracleIdentitiesWithKeyIndexLocal(chainlinkNodes, keyIndex) if err != nil { return contracts.OCRv2Config{}, err @@ -136,13 +132,17 @@ func BuildAutoOCR2ConfigVarsWithKeyIndexLocal( var signers []common.Address for _, signer := range signerOnchainPublicKeys { - require.Equal(t, 20, len(signer), "OnChainPublicKey '%v' has wrong length for address", signer) + if len(signer) != 20 { + return contracts.OCRv2Config{}, fmt.Errorf("OnChainPublicKey '%v' has wrong length for address", signer) + } signers = append(signers, common.BytesToAddress(signer)) } var transmitters []common.Address for _, transmitter := range transmitterAccounts { - require.True(t, common.IsHexAddress(string(transmitter)), "TransmitAccount '%s' is not a valid Ethereum address", string(transmitter)) + if !common.IsHexAddress(string(transmitter)) { + return contracts.OCRv2Config{}, fmt.Errorf("TransmitAccount '%s' is not a valid Ethereum address", string(transmitter)) + } transmitters = append(transmitters, common.HexToAddress(string(transmitter))) } @@ -164,6 +164,7 @@ func BuildAutoOCR2ConfigVarsWithKeyIndexLocal( // CreateOCRKeeperJobs bootstraps the first node and to the other nodes sends ocr jobs func CreateOCRKeeperJobsLocal( + l zerolog.Logger, chainlinkNodes []*client.ChainlinkClient, registryAddr string, chainID int64, @@ -173,7 +174,7 @@ func CreateOCRKeeperJobsLocal( bootstrapNode := chainlinkNodes[0] bootstrapP2PIds, err := bootstrapNode.MustReadP2PKeys() if err != nil { - log.Error().Err(err).Msg("Shouldn't fail reading P2P keys from bootstrap node") + l.Error().Err(err).Msg("Shouldn't fail reading P2P keys from bootstrap node") return err } bootstrapP2PId := bootstrapP2PIds.Data[0].Attributes.PeerID @@ -201,7 +202,7 @@ func CreateOCRKeeperJobsLocal( } _, err = bootstrapNode.MustCreateJob(bootstrapSpec) if err != nil { - log.Error().Err(err).Msg("Shouldn't fail creating bootstrap job on bootstrap node") + l.Error().Err(err).Msg("Shouldn't fail creating bootstrap job on bootstrap node") return err } @@ -209,12 +210,12 @@ func CreateOCRKeeperJobsLocal( for nodeIndex := 1; nodeIndex < len(chainlinkNodes); nodeIndex++ { nodeTransmitterAddress, err := chainlinkNodes[nodeIndex].EthAddresses() if err != nil { - log.Error().Err(err).Msgf("Shouldn't fail getting primary ETH address from OCR node %d", nodeIndex+1) + l.Error().Err(err).Msgf("Shouldn't fail getting primary ETH address from OCR node %d", nodeIndex+1) return err } nodeOCRKeys, err := chainlinkNodes[nodeIndex].MustReadOCR2Keys() if err != nil { - log.Error().Err(err).Msgf("Shouldn't fail getting OCR keys from OCR node %d", nodeIndex+1) + l.Error().Err(err).Msgf("Shouldn't fail getting OCR keys from OCR node %d", nodeIndex+1) return err } var nodeOCRKeyId []string @@ -248,11 +249,11 @@ func CreateOCRKeeperJobsLocal( _, err = chainlinkNodes[nodeIndex].MustCreateJob(&autoOCR2JobSpec) if err != nil { - log.Error().Err(err).Msgf("Shouldn't fail creating OCR Task job on OCR node %d err: %+v", nodeIndex+1, err) + l.Error().Err(err).Msgf("Shouldn't fail creating OCR Task job on OCR node %d err: %+v", nodeIndex+1, err) return err } } - log.Info().Msg("Done creating OCR automation jobs") + l.Info().Msg("Done creating OCR automation jobs") return nil } diff --git a/integration-tests/actions/keeper_helpers.go b/integration-tests/actions/keeper_helpers.go index 98c9a51e1c8..f824e75019d 100644 --- a/integration-tests/actions/keeper_helpers.go +++ b/integration-tests/actions/keeper_helpers.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" @@ -27,6 +27,7 @@ func CreateKeeperJobs( chainlinkNodes []*client.ChainlinkK8sClient, keeperRegistry contracts.KeeperRegistry, ocrConfig contracts.OCRv2Config, + evmChainID string, ) { // Send keeper jobs to registry and chainlink nodes primaryNode := chainlinkNodes[0] @@ -49,6 +50,7 @@ func CreateKeeperJobs( Name: fmt.Sprintf("keeper-test-%s", keeperRegistry.Address()), ContractAddress: keeperRegistry.Address(), FromAddress: chainlinkNodeAddress, + EVMChainID: evmChainID, MinIncomingConfirmations: 1, }) require.NoError(t, err, "Creating KeeperV2 Job shouldn't fail") @@ -61,6 +63,7 @@ func CreateKeeperJobsWithKeyIndex( keeperRegistry contracts.KeeperRegistry, keyIndex int, ocrConfig contracts.OCRv2Config, + evmChainID string, ) { // Send keeper jobs to registry and chainlink nodes primaryNode := chainlinkNodes[0] @@ -83,6 +86,7 @@ func CreateKeeperJobsWithKeyIndex( Name: fmt.Sprintf("keeper-test-%s", keeperRegistry.Address()), ContractAddress: keeperRegistry.Address(), FromAddress: chainlinkNodeAddress[keyIndex], + EVMChainID: evmChainID, MinIncomingConfirmations: 1, }) require.NoError(t, err, "Creating KeeperV2 Job shouldn't fail") @@ -335,7 +339,7 @@ func RegisterUpkeepContracts(t *testing.T, linkToken contracts.LinkToken, linkFu } func RegisterUpkeepContractsWithCheckData(t *testing.T, linkToken contracts.LinkToken, linkFunds *big.Int, client blockchain.EVMClient, upkeepGasLimit uint32, registry contracts.KeeperRegistry, registrar contracts.KeeperRegistrar, numberOfContracts int, upkeepAddresses []string, checkData [][]byte, isLogTrigger bool) []*big.Int { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) registrationTxHashes := make([]common.Hash, 0) upkeepIds := make([]*big.Int, 0) for contractCount, upkeepAddress := range upkeepAddresses { @@ -394,7 +398,7 @@ func RegisterUpkeepContractsWithCheckData(t *testing.T, linkToken contracts.Link } func DeployKeeperConsumers(t *testing.T, contractDeployer contracts.ContractDeployer, client blockchain.EVMClient, numberOfContracts int, isLogTrigger bool) []contracts.KeeperConsumer { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) keeperConsumerContracts := make([]contracts.KeeperConsumer, 0) for contractCount := 0; contractCount < numberOfContracts; contractCount++ { @@ -437,7 +441,7 @@ func DeployKeeperConsumersPerformance( checkGasToBurn, // How much gas should be burned on checkUpkeep() calls performGasToBurn int64, // How much gas should be burned on performUpkeep() calls ) []contracts.KeeperConsumerPerformance { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) upkeeps := make([]contracts.KeeperConsumerPerformance, 0) for contractCount := 0; contractCount < numberOfContracts; contractCount++ { @@ -474,7 +478,7 @@ func DeployPerformDataChecker( numberOfContracts int, expectedData []byte, ) []contracts.KeeperPerformDataChecker { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) upkeeps := make([]contracts.KeeperPerformDataChecker, 0) for contractCount := 0; contractCount < numberOfContracts; contractCount++ { @@ -506,7 +510,7 @@ func DeployUpkeepCounters( testRange *big.Int, interval *big.Int, ) []contracts.UpkeepCounter { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) upkeepCounters := make([]contracts.UpkeepCounter, 0) for contractCount := 0; contractCount < numberOfContracts; contractCount++ { @@ -539,7 +543,7 @@ func DeployUpkeepPerformCounterRestrictive( testRange *big.Int, averageEligibilityCadence *big.Int, ) []contracts.UpkeepPerformCounterRestrictive { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) upkeepCounters := make([]contracts.UpkeepPerformCounterRestrictive, 0) for contractCount := 0; contractCount < numberOfContracts; contractCount++ { diff --git a/integration-tests/actions/keeper_helpers_local.go b/integration-tests/actions/keeper_helpers_local.go index 6fc7ef43dbe..d9d15b33a3e 100644 --- a/integration-tests/actions/keeper_helpers_local.go +++ b/integration-tests/actions/keeper_helpers_local.go @@ -3,26 +3,29 @@ package actions import ( "fmt" - "github.com/rs/zerolog/log" + "github.com/rs/zerolog" + "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" ) func CreateKeeperJobsLocal( + l zerolog.Logger, chainlinkNodes []*client.ChainlinkClient, keeperRegistry contracts.KeeperRegistry, ocrConfig contracts.OCRv2Config, + evmChainID string, ) ([]*client.Job, error) { // Send keeper jobs to registry and chainlink nodes primaryNode := chainlinkNodes[0] primaryNodeAddress, err := primaryNode.PrimaryEthAddress() if err != nil { - log.Error().Err(err).Msg("Reading ETH Keys from Chainlink Client shouldn't fail") + l.Error().Err(err).Msg("Reading ETH Keys from Chainlink Client shouldn't fail") return nil, err } nodeAddresses, err := ChainlinkNodeAddressesLocal(chainlinkNodes) if err != nil { - log.Error().Err(err).Msg("Retrieving on-chain wallet addresses for chainlink nodes shouldn't fail") + l.Error().Err(err).Msg("Retrieving on-chain wallet addresses for chainlink nodes shouldn't fail") return nil, err } nodeAddressesStr, payees := make([]string, 0), make([]string, 0) @@ -32,24 +35,25 @@ func CreateKeeperJobsLocal( } err = keeperRegistry.SetKeepers(nodeAddressesStr, payees, ocrConfig) if err != nil { - log.Error().Err(err).Msg("Setting keepers in the registry shouldn't fail") + l.Error().Err(err).Msg("Setting keepers in the registry shouldn't fail") return nil, err } jobs := []*client.Job{} for _, chainlinkNode := range chainlinkNodes { chainlinkNodeAddress, err := chainlinkNode.PrimaryEthAddress() if err != nil { - log.Error().Err(err).Msg("Error retrieving chainlink node address") + l.Error().Err(err).Msg("Error retrieving chainlink node address") return nil, err } job, err := chainlinkNode.MustCreateJob(&client.KeeperJobSpec{ Name: fmt.Sprintf("keeper-test-%s", keeperRegistry.Address()), ContractAddress: keeperRegistry.Address(), FromAddress: chainlinkNodeAddress, + EVMChainID: evmChainID, MinIncomingConfirmations: 1, }) if err != nil { - log.Error().Err(err).Msg("Creating KeeperV2 Job shouldn't fail") + l.Error().Err(err).Msg("Creating KeeperV2 Job shouldn't fail") return nil, err } jobs = append(jobs, job) diff --git a/integration-tests/actions/ocr2_helpers.go b/integration-tests/actions/ocr2_helpers.go index 3c37233a0d3..293ea2b73c0 100644 --- a/integration-tests/actions/ocr2_helpers.go +++ b/integration-tests/actions/ocr2_helpers.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/lib/pq" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" "golang.org/x/sync/errgroup" "gopkg.in/guregu/null.v4" @@ -360,13 +361,14 @@ func StartNewOCR2Round( ocrInstances []contracts.OffchainAggregatorV2, client blockchain.EVMClient, timeout time.Duration, + logger zerolog.Logger, ) error { for i := 0; i < len(ocrInstances); i++ { err := ocrInstances[i].RequestNewRound() if err != nil { return fmt.Errorf("requesting new OCR round %d have failed: %w", i+1, err) } - ocrRound := contracts.NewOffchainAggregatorV2RoundConfirmer(ocrInstances[i], big.NewInt(roundNumber), timeout) + ocrRound := contracts.NewOffchainAggregatorV2RoundConfirmer(ocrInstances[i], big.NewInt(roundNumber), timeout, logger) client.AddHeaderEventSubscription(ocrInstances[i].Address(), ocrRound) err = client.WaitForEvents() if err != nil { diff --git a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_config_helpers.go b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_config_helpers.go index 05b983c2f1e..ce693964323 100644 --- a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_config_helpers.go +++ b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_config_helpers.go @@ -16,7 +16,7 @@ import ( "go.dedis.ch/kyber/v3/group/edwards25519" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "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/libocr/offchainreporting2plus/confighelper" @@ -39,7 +39,7 @@ func CreateOCR2VRFJobs( chainID int64, keyIndex int, ) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) p2pV2Bootstrapper := createBootstrapJob(t, bootstrapNode, OCR2VRFPluginConfig.DKGConfig.DKGContractAddress, chainID) createNonBootstrapJobs(t, nonBootstrapNodes, OCR2VRFPluginConfig, chainID, keyIndex, p2pV2Bootstrapper) @@ -120,7 +120,7 @@ func BuildOCR2DKGConfigVars( t *testing.T, ocr2VRFPluginConfig *OCR2VRFPluginConfig, ) contracts.OCRv2Config { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) var onchainPublicKeys []common.Address for _, onchainPublicKey := range ocr2VRFPluginConfig.OCR2Config.OnchainPublicKeys { onchainPublicKeys = append(onchainPublicKeys, common.HexToAddress(onchainPublicKey)) @@ -272,7 +272,7 @@ func BuildOCR2VRFConfigVars( t *testing.T, ocr2VRFPluginConfig *OCR2VRFPluginConfig, ) contracts.OCRv2Config { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) var onchainPublicKeys []common.Address for _, onchainPublicKey := range ocr2VRFPluginConfig.OCR2Config.OnchainPublicKeys { onchainPublicKeys = append(onchainPublicKeys, common.HexToAddress(onchainPublicKey)) diff --git a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go index c550fe73a22..c123aaff6a2 100644 --- a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go +++ b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go @@ -13,7 +13,7 @@ import ( ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -25,7 +25,7 @@ import ( ) func SetAndWaitForVRFBeaconProcessToFinish(t *testing.T, ocr2VRFPluginConfig *OCR2VRFPluginConfig, vrfBeacon contracts.VRFBeacon) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) ocr2VrfConfig := BuildOCR2VRFConfigVars(t, ocr2VRFPluginConfig) l.Debug().Interface("OCR2 VRF Config", ocr2VrfConfig).Msg("OCR2 VRF Config prepared") @@ -45,7 +45,7 @@ func SetAndWaitForVRFBeaconProcessToFinish(t *testing.T, ocr2VRFPluginConfig *OC } func SetAndWaitForDKGProcessToFinish(t *testing.T, ocr2VRFPluginConfig *OCR2VRFPluginConfig, dkg contracts.DKG) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) ocr2DkgConfig := BuildOCR2DKGConfigVars(t, ocr2VRFPluginConfig) // set config for DKG OCR @@ -208,7 +208,7 @@ func RequestAndRedeemRandomness( confirmationDelay *big.Int, randomnessTransmissionEventTimeout time.Duration, ) *big.Int { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) receipt, err := consumer.RequestRandomness( numberOfRandomWordsToRequest, subscriptionID, @@ -244,7 +244,7 @@ func RequestRandomnessFulfillmentAndWaitForFulfilment( confirmationDelay *big.Int, randomnessTransmissionEventTimeout time.Duration, ) *big.Int { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) receipt, err := consumer.RequestRandomnessFulfillment( numberOfRandomWordsToRequest, subscriptionID, diff --git a/integration-tests/actions/ocr_helpers.go b/integration-tests/actions/ocr_helpers.go index bff96c73042..cfc8cfe589b 100644 --- a/integration-tests/actions/ocr_helpers.go +++ b/integration-tests/actions/ocr_helpers.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" + "github.com/rs/zerolog" "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" @@ -186,6 +187,7 @@ func CreateOCRJobs( workerNodes []*client.ChainlinkK8sClient, mockValue int, mockserver *ctfClient.MockserverClient, + evmChainID string, ) error { for _, ocrInstance := range ocrInstances { bootstrapP2PIds, err := bootstrapNode.MustReadP2PKeys() @@ -196,6 +198,7 @@ func CreateOCRJobs( bootstrapSpec := &client.OCRBootstrapJobSpec{ Name: fmt.Sprintf("bootstrap-%s", uuid.New().String()), ContractAddress: ocrInstance.Address(), + EVMChainID: evmChainID, P2PPeerID: bootstrapP2PId, IsBootstrapPeer: true, } @@ -240,6 +243,7 @@ func CreateOCRJobs( bootstrapPeers := []*client.ChainlinkClient{bootstrapNode.ChainlinkClient} ocrSpec := &client.OCRTaskJobSpec{ ContractAddress: ocrInstance.Address(), + EVMChainID: evmChainID, P2PPeerID: nodeP2PId, P2PBootstrapPeers: bootstrapPeers, KeyBundleID: nodeOCRKeyId, @@ -264,6 +268,7 @@ func CreateOCRJobsWithForwarder( workerNodes []*client.ChainlinkK8sClient, mockValue int, mockserver *ctfClient.MockserverClient, + evmChainID string, ) { for _, ocrInstance := range ocrInstances { bootstrapP2PIds, err := bootstrapNode.MustReadP2PKeys() @@ -272,6 +277,7 @@ func CreateOCRJobsWithForwarder( bootstrapSpec := &client.OCRBootstrapJobSpec{ Name: fmt.Sprintf("bootstrap-%s", uuid.New().String()), ContractAddress: ocrInstance.Address(), + EVMChainID: evmChainID, P2PPeerID: bootstrapP2PId, IsBootstrapPeer: true, } @@ -302,6 +308,7 @@ func CreateOCRJobsWithForwarder( bootstrapPeers := []*client.ChainlinkClient{bootstrapNode.ChainlinkClient} ocrSpec := &client.OCRTaskJobSpec{ ContractAddress: ocrInstance.Address(), + EVMChainID: evmChainID, P2PPeerID: nodeP2PId, P2PBootstrapPeers: bootstrapPeers, KeyBundleID: nodeOCRKeyId, @@ -320,13 +327,14 @@ func StartNewRound( roundNumber int64, ocrInstances []contracts.OffchainAggregator, client blockchain.EVMClient, + logger zerolog.Logger, ) error { for i := 0; i < len(ocrInstances); i++ { err := ocrInstances[i].RequestNewRound() if err != nil { return fmt.Errorf("requesting new OCR round %d have failed: %w", i+1, err) } - ocrRound := contracts.NewOffchainAggregatorRoundConfirmer(ocrInstances[i], big.NewInt(roundNumber), client.GetNetworkConfig().Timeout.Duration) + ocrRound := contracts.NewOffchainAggregatorRoundConfirmer(ocrInstances[i], big.NewInt(roundNumber), client.GetNetworkConfig().Timeout.Duration, logger) client.AddHeaderEventSubscription(ocrInstances[i].Address(), ocrRound) err = client.WaitForEvents() if err != nil { diff --git a/integration-tests/actions/ocr_helpers_local.go b/integration-tests/actions/ocr_helpers_local.go index 13fc01dcea6..ae2f3686daf 100644 --- a/integration-tests/actions/ocr_helpers_local.go +++ b/integration-tests/actions/ocr_helpers_local.go @@ -2,18 +2,20 @@ package actions import ( "fmt" + "math/big" + "strings" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" "github.com/pkg/errors" - "github.com/rs/zerolog/log" + "github.com/rs/zerolog" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "golang.org/x/sync/errgroup" + "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "golang.org/x/sync/errgroup" - "math/big" - "strings" ) /* @@ -140,6 +142,7 @@ func CreateOCRJobsLocal( workerNodes []*client.ChainlinkClient, mockValue int, mockserver *ctfClient.MockserverClient, + evmChainID string, ) error { for _, ocrInstance := range ocrInstances { bootstrapP2PIds, err := bootstrapNode.MustReadP2PKeys() @@ -150,6 +153,7 @@ func CreateOCRJobsLocal( bootstrapSpec := &client.OCRBootstrapJobSpec{ Name: fmt.Sprintf("bootstrap-%s", uuid.New().String()), ContractAddress: ocrInstance.Address(), + EVMChainID: evmChainID, P2PPeerID: bootstrapP2PId, IsBootstrapPeer: true, } @@ -194,6 +198,7 @@ func CreateOCRJobsLocal( bootstrapPeers := []*client.ChainlinkClient{bootstrapNode} ocrSpec := &client.OCRTaskJobSpec{ ContractAddress: ocrInstance.Address(), + EVMChainID: evmChainID, P2PPeerID: nodeP2PId, P2PBootstrapPeers: bootstrapPeers, KeyBundleID: nodeOCRKeyId, @@ -266,13 +271,14 @@ func TrackForwarderLocal( chainClient blockchain.EVMClient, authorizedForwarder common.Address, node *client.ChainlinkClient, + logger zerolog.Logger, ) error { chainID := chainClient.GetChainID() _, _, err := node.TrackForwarder(chainID, authorizedForwarder) if err != nil { return errors.Wrap(err, "failed to track forwarder") } - log.Info().Str("NodeURL", node.Config.URL). + logger.Info().Str("NodeURL", node.Config.URL). Str("ForwarderAddress", authorizedForwarder.Hex()). Str("ChaindID", chainID.String()). Msg("Forwarder tracked") @@ -353,6 +359,7 @@ func CreateOCRJobsWithForwarderLocal( workerNodes []*client.ChainlinkClient, mockValue int, mockserver *ctfClient.MockserverClient, + evmChainID string, ) error { for _, ocrInstance := range ocrInstances { bootstrapP2PIds, err := bootstrapNode.MustReadP2PKeys() @@ -363,6 +370,7 @@ func CreateOCRJobsWithForwarderLocal( bootstrapSpec := &client.OCRBootstrapJobSpec{ Name: fmt.Sprintf("bootstrap-%s", uuid.New().String()), ContractAddress: ocrInstance.Address(), + EVMChainID: evmChainID, P2PPeerID: bootstrapP2PId, IsBootstrapPeer: true, } @@ -407,6 +415,7 @@ func CreateOCRJobsWithForwarderLocal( bootstrapPeers := []*client.ChainlinkClient{bootstrapNode} ocrSpec := &client.OCRTaskJobSpec{ ContractAddress: ocrInstance.Address(), + EVMChainID: evmChainID, P2PPeerID: nodeP2PId, P2PBootstrapPeers: bootstrapPeers, KeyBundleID: nodeOCRKeyId, diff --git a/integration-tests/actions/operator_forwarder_helpers.go b/integration-tests/actions/operator_forwarder_helpers.go index 7add64fbe99..37b50c4fa9a 100644 --- a/integration-tests/actions/operator_forwarder_helpers.go +++ b/integration-tests/actions/operator_forwarder_helpers.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_factory" "github.com/smartcontractkit/chainlink/integration-tests/client" @@ -91,7 +91,7 @@ func ProcessNewEvent( contractABI *abi.ABI, chainClient blockchain.EVMClient, ) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) errorChan := make(chan error) eventConfirmed := make(chan bool) err := chainClient.ProcessEvent(eventDetails.Name, event, eventConfirmed, errorChan) @@ -138,7 +138,7 @@ func SubscribeOperatorFactoryEvents( chainClient blockchain.EVMClient, operatorFactoryInstance contracts.OperatorFactory, ) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) contractABI, err := operator_factory.OperatorFactoryMetaData.GetAbi() require.NoError(t, err, "Getting contract abi for OperatorFactory shouldn't fail") latestBlockNum, err := chainClient.LatestBlockNumber(context.Background()) @@ -186,7 +186,7 @@ func TrackForwarder( authorizedForwarder common.Address, node *client.ChainlinkK8sClient, ) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) chainID := chainClient.GetChainID() _, _, err := node.TrackForwarder(chainID, authorizedForwarder) require.NoError(t, err, "Forwarder track should be created") diff --git a/integration-tests/benchmark/keeper_test.go b/integration-tests/benchmark/keeper_test.go index 6ce0fb7138f..59406e51583 100644 --- a/integration-tests/benchmark/keeper_test.go +++ b/integration-tests/benchmark/keeper_test.go @@ -18,13 +18,13 @@ import ( "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-env/pkg/helm/reorg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) @@ -141,7 +141,7 @@ type NetworkConfig struct { } func TestAutomationBenchmark(t *testing.T) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) testEnvironment, benchmarkNetwork := SetupAutomationBenchmarkEnv(t) if testEnvironment.WillUseRemoteRunner() { return @@ -153,7 +153,7 @@ func TestAutomationBenchmark(t *testing.T) { l.Info().Str("Namespace", testEnvironment.Cfg.Namespace).Msg("Connected to Keepers Benchmark Environment") - chainClient, err := blockchain.NewEVMClient(benchmarkNetwork, testEnvironment) + chainClient, err := blockchain.NewEVMClient(benchmarkNetwork, testEnvironment, l) require.NoError(t, err, "Error connecting to blockchain") registryVersions := addRegistry(RegistryToTest) keeperBenchmarkTest := testsetups.NewKeeperBenchmarkTest( @@ -298,7 +298,7 @@ func getEnv(key, fallback string) string { } func SetupAutomationBenchmarkEnv(t *testing.T) (*environment.Environment, blockchain.EVMNetwork) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) testNetwork := networks.SelectedNetwork // Environment currently being used to run benchmark test on blockTime := "1" networkDetailTOML := `MinIncomingConfirmations = 1` diff --git a/integration-tests/chaos/automation_chaos_test.go b/integration-tests/chaos/automation_chaos_test.go index 0da3271785e..1b18b9f6ab7 100644 --- a/integration-tests/chaos/automation_chaos_test.go +++ b/integration-tests/chaos/automation_chaos_test.go @@ -18,13 +18,14 @@ import ( "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/networks" ) var ( @@ -108,7 +109,7 @@ const ( func TestAutomationChaos(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) testCases := map[string]struct { networkChart environment.ConnectedChart @@ -200,10 +201,11 @@ func TestAutomationChaos(t *testing.T) { err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=", 2, 5, ChaosGroupMajorityPlus) require.NoError(t, err) - chainClient, err := blockchain.NewEVMClient(network, testEnvironment) + chainClient, err := blockchain.NewEVMClient(network, testEnvironment, l) require.NoError(t, err, "Error connecting to blockchain") - contractDeployer, err := contracts.NewContractDeployer(chainClient) + contractDeployer, err := contracts.NewContractDeployer(chainClient, l) require.NoError(t, err, "Error building contract deployer") + chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) require.NoError(t, err, "Error connecting to Chainlink nodes") chainClient.ParallelTransactions(true) diff --git a/integration-tests/chaos/ocr2vrf_chaos_test.go b/integration-tests/chaos/ocr2vrf_chaos_test.go index 7d10107ba56..fd51fa55db5 100644 --- a/integration-tests/chaos/ocr2vrf_chaos_test.go +++ b/integration-tests/chaos/ocr2vrf_chaos_test.go @@ -16,6 +16,8 @@ import ( "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/smartcontractkit/chainlink/integration-tests/actions" @@ -24,12 +26,11 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" ) func TestOCR2VRFChaos(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) loadedNetwork := networks.SelectedNetwork defaultOCR2VRFSettings := map[string]interface{}{ @@ -139,9 +140,9 @@ func TestOCR2VRFChaos(t *testing.T) { err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=", 3, 5, ChaosGroupMajority) require.NoError(t, err) - chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment) + chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment, l) require.NoError(t, err, "Error connecting to blockchain") - contractDeployer, err := contracts.NewContractDeployer(chainClient) + contractDeployer, err := contracts.NewContractDeployer(chainClient, l) require.NoError(t, err, "Error building contract deployer") chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) require.NoError(t, err, "Error connecting to Chainlink nodes") diff --git a/integration-tests/chaos/ocr_chaos_test.go b/integration-tests/chaos/ocr_chaos_test.go index 58b4d5bea65..569a0d1b70c 100644 --- a/integration-tests/chaos/ocr_chaos_test.go +++ b/integration-tests/chaos/ocr_chaos_test.go @@ -20,13 +20,14 @@ import ( mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" ) var ( @@ -58,7 +59,7 @@ func TestMain(m *testing.M) { func TestOCRChaos(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) testCases := map[string]struct { networkChart environment.ConnectedChart clChart environment.ConnectedChart @@ -152,9 +153,9 @@ func TestOCRChaos(t *testing.T) { err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=", 2, 5, ChaosGroupMajorityPlus) require.NoError(t, err) - chainClient, err := blockchain.NewEVMClient(blockchain.SimulatedEVMNetwork, testEnvironment) + chainClient, err := blockchain.NewEVMClient(blockchain.SimulatedEVMNetwork, testEnvironment, l) require.NoError(t, err, "Connecting to blockchain nodes shouldn't fail") - cd, err := contracts.NewContractDeployer(chainClient) + cd, err := contracts.NewContractDeployer(chainClient, l) require.NoError(t, err, "Deploying contracts shouldn't fail") chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) @@ -184,7 +185,7 @@ func TestOCRChaos(t *testing.T) { require.NoError(t, err) err = chainClient.WaitForEvents() require.NoError(t, err) - err = actions.CreateOCRJobs(ocrInstances, bootstrapNode, workerNodes, 5, ms) + err = actions.CreateOCRJobs(ocrInstances, bootstrapNode, workerNodes, 5, ms, chainClient.GetChainID().String()) require.NoError(t, err) chaosApplied := false diff --git a/integration-tests/client/chainlink.go b/integration-tests/client/chainlink.go index 7d3bd0284d0..8a79cb3ec95 100644 --- a/integration-tests/client/chainlink.go +++ b/integration-tests/client/chainlink.go @@ -9,11 +9,13 @@ import ( "sync" "time" + "os" + "github.com/ethereum/go-ethereum/common" "github.com/go-resty/resty/v2" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" "golang.org/x/sync/errgroup" - "os" ) const ( @@ -39,10 +41,11 @@ type ChainlinkClient struct { pageSize int primaryEthAddress string ethAddresses []string + l zerolog.Logger } // NewChainlinkClient creates a new Chainlink model using a provided config -func NewChainlinkClient(c *ChainlinkConfig) (*ChainlinkClient, error) { +func NewChainlinkClient(c *ChainlinkConfig, logger zerolog.Logger) (*ChainlinkClient, error) { rc, err := initRestyClient(c.URL, c.Email, c.Password, c.HTTPTimeout) if err != nil { return nil, err @@ -55,6 +58,7 @@ func NewChainlinkClient(c *ChainlinkConfig) (*ChainlinkClient, error) { Config: c, APIClient: rc, pageSize: 25, + l: logger, }, nil } @@ -92,8 +96,8 @@ func (c *ChainlinkClient) URL() string { // CreateJobRaw creates a Chainlink job based on the provided spec string func (c *ChainlinkClient) CreateJobRaw(spec string) (*Job, *http.Response, error) { job := &Job{} - log.Info().Str("Node URL", c.Config.URL).Msg("Creating Job") - log.Trace().Str("Node URL", c.Config.URL).Str("Job Body", spec).Msg("Creating Job") + c.l.Info().Str("Node URL", c.Config.URL).Msg("Creating Job") + c.l.Trace().Str("Node URL", c.Config.URL).Str("Job Body", spec).Msg("Creating Job") resp, err := c.APIClient.R(). SetBody(&JobForm{ TOML: spec, @@ -123,8 +127,8 @@ func (c *ChainlinkClient) CreateJob(spec JobSpec) (*Job, *http.Response, error) if err != nil { return nil, nil, err } - log.Info().Str("Node URL", c.Config.URL).Str("Type", spec.Type()).Msg("Creating Job") - log.Trace().Str("Node URL", c.Config.URL).Str("Type", spec.Type()).Str("Spec", specString).Msg("Creating Job") + c.l.Info().Str("Node URL", c.Config.URL).Str("Type", spec.Type()).Msg("Creating Job") + c.l.Trace().Str("Node URL", c.Config.URL).Str("Type", spec.Type()).Str("Spec", specString).Msg("Creating Job") resp, err := c.APIClient.R(). SetBody(&JobForm{ TOML: specString, @@ -140,7 +144,7 @@ func (c *ChainlinkClient) CreateJob(spec JobSpec) (*Job, *http.Response, error) // ReadJobs reads all jobs from the Chainlink node func (c *ChainlinkClient) ReadJobs() (*ResponseSlice, *http.Response, error) { specObj := &ResponseSlice{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Getting Jobs") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Getting Jobs") resp, err := c.APIClient.R(). SetResult(&specObj). Get("/v2/jobs") @@ -153,7 +157,7 @@ func (c *ChainlinkClient) ReadJobs() (*ResponseSlice, *http.Response, error) { // ReadJob reads a job with the provided ID from the Chainlink node func (c *ChainlinkClient) ReadJob(id string) (*Response, *http.Response, error) { specObj := &Response{} - log.Info().Str(NodeURL, c.Config.URL).Str("ID", id).Msg("Reading Job") + c.l.Info().Str(NodeURL, c.Config.URL).Str("ID", id).Msg("Reading Job") resp, err := c.APIClient.R(). SetResult(&specObj). SetPathParams(map[string]string{ @@ -178,7 +182,7 @@ func (c *ChainlinkClient) MustDeleteJob(id string) error { // DeleteJob deletes a job with a provided ID from the Chainlink node func (c *ChainlinkClient) DeleteJob(id string) (*http.Response, error) { - log.Info().Str(NodeURL, c.Config.URL).Str("ID", id).Msg("Deleting Job") + c.l.Info().Str(NodeURL, c.Config.URL).Str("ID", id).Msg("Deleting Job") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "id": id, @@ -194,7 +198,7 @@ func (c *ChainlinkClient) DeleteJob(id string) (*http.Response, error) { func (c *ChainlinkClient) CreateSpec(spec string) (*Spec, *http.Response, error) { s := &Spec{} r := strings.NewReplacer("\n", "", " ", "", "\\", "") // Makes it more compact and readable for logging - log.Info().Str(NodeURL, c.Config.URL).Str("Spec", r.Replace(spec)).Msg("Creating Spec") + c.l.Info().Str(NodeURL, c.Config.URL).Str("Spec", r.Replace(spec)).Msg("Creating Spec") resp, err := c.APIClient.R(). SetBody([]byte(spec)). SetResult(&s). @@ -208,7 +212,7 @@ func (c *ChainlinkClient) CreateSpec(spec string) (*Spec, *http.Response, error) // ReadSpec reads a job spec with the provided ID on the Chainlink node func (c *ChainlinkClient) ReadSpec(id string) (*Response, *http.Response, error) { specObj := &Response{} - log.Info().Str(NodeURL, c.Config.URL).Str("ID", id).Msg("Reading Spec") + c.l.Info().Str(NodeURL, c.Config.URL).Str("ID", id).Msg("Reading Spec") resp, err := c.APIClient.R(). SetResult(&specObj). SetPathParams(map[string]string{ @@ -234,7 +238,7 @@ func (c *ChainlinkClient) MustReadRunsByJob(jobID string) (*JobRunsResponse, err // ReadRunsByJob reads all runs for a job func (c *ChainlinkClient) ReadRunsByJob(jobID string) (*JobRunsResponse, *http.Response, error) { runsObj := &JobRunsResponse{} - log.Debug().Str(NodeURL, c.Config.URL).Str("JobID", jobID).Msg("Reading runs for a job") + c.l.Debug().Str(NodeURL, c.Config.URL).Str("JobID", jobID).Msg("Reading runs for a job") resp, err := c.APIClient.R(). SetResult(&runsObj). SetPathParams(map[string]string{ @@ -249,7 +253,7 @@ func (c *ChainlinkClient) ReadRunsByJob(jobID string) (*JobRunsResponse, *http.R // DeleteSpec deletes a job spec with the provided ID from the Chainlink node func (c *ChainlinkClient) DeleteSpec(id string) (*http.Response, error) { - log.Info().Str(NodeURL, c.Config.URL).Str("ID", id).Msg("Deleting Spec") + c.l.Info().Str(NodeURL, c.Config.URL).Str("ID", id).Msg("Deleting Spec") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "id": id, @@ -272,7 +276,7 @@ func (c *ChainlinkClient) MustCreateBridge(bta *BridgeTypeAttributes) error { } func (c *ChainlinkClient) CreateBridge(bta *BridgeTypeAttributes) (*http.Response, error) { - log.Info().Str(NodeURL, c.Config.URL).Str("Name", bta.Name).Msg("Creating Bridge") + c.l.Info().Str(NodeURL, c.Config.URL).Str("Name", bta.Name).Msg("Creating Bridge") resp, err := c.APIClient.R(). SetBody(bta). Post("/v2/bridge_types") @@ -285,7 +289,7 @@ func (c *ChainlinkClient) CreateBridge(bta *BridgeTypeAttributes) (*http.Respons // ReadBridge reads a bridge from the Chainlink node based on the provided name func (c *ChainlinkClient) ReadBridge(name string) (*BridgeType, *http.Response, error) { bt := BridgeType{} - log.Info().Str(NodeURL, c.Config.URL).Str("Name", name).Msg("Reading Bridge") + c.l.Info().Str(NodeURL, c.Config.URL).Str("Name", name).Msg("Reading Bridge") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "name": name, @@ -300,7 +304,7 @@ func (c *ChainlinkClient) ReadBridge(name string) (*BridgeType, *http.Response, // DeleteBridge deletes a bridge on the Chainlink node based on the provided name func (c *ChainlinkClient) DeleteBridge(name string) (*http.Response, error) { - log.Info().Str(NodeURL, c.Config.URL).Str("Name", name).Msg("Deleting Bridge") + c.l.Info().Str(NodeURL, c.Config.URL).Str("Name", name).Msg("Deleting Bridge") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "name": name, @@ -315,7 +319,7 @@ func (c *ChainlinkClient) DeleteBridge(name string) (*http.Response, error) { // CreateOCRKey creates an OCRKey on the Chainlink node func (c *ChainlinkClient) CreateOCRKey() (*OCRKey, *http.Response, error) { ocrKey := &OCRKey{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Creating OCR Key") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Creating OCR Key") resp, err := c.APIClient.R(). SetResult(ocrKey). Post("/v2/keys/ocr") @@ -329,7 +333,7 @@ func (c *ChainlinkClient) CreateOCRKey() (*OCRKey, *http.Response, error) { // the request is unsuccessful func (c *ChainlinkClient) MustReadOCRKeys() (*OCRKeys, error) { ocrKeys := &OCRKeys{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Reading OCR Keys") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Reading OCR Keys") resp, err := c.APIClient.R(). SetResult(ocrKeys). Get("/v2/keys/ocr") @@ -350,7 +354,7 @@ func (c *ChainlinkClient) MustReadOCRKeys() (*OCRKeys, error) { // DeleteOCRKey deletes an OCRKey based on the provided ID func (c *ChainlinkClient) DeleteOCRKey(id string) (*http.Response, error) { - log.Info().Str(NodeURL, c.Config.URL).Str("ID", id).Msg("Deleting OCR Key") + c.l.Info().Str(NodeURL, c.Config.URL).Str("ID", id).Msg("Deleting OCR Key") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "id": id, @@ -365,7 +369,7 @@ func (c *ChainlinkClient) DeleteOCRKey(id string) (*http.Response, error) { // CreateOCR2Key creates an OCR2Key on the Chainlink node func (c *ChainlinkClient) CreateOCR2Key(chain string) (*OCR2Key, *http.Response, error) { ocr2Key := &OCR2Key{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Creating OCR2 Key") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Creating OCR2 Key") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "chain": chain, @@ -381,7 +385,7 @@ func (c *ChainlinkClient) CreateOCR2Key(chain string) (*OCR2Key, *http.Response, // ReadOCR2Keys reads all OCR2Keys from the Chainlink node func (c *ChainlinkClient) ReadOCR2Keys() (*OCR2Keys, *http.Response, error) { ocr2Keys := &OCR2Keys{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Reading OCR2 Keys") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Reading OCR2 Keys") resp, err := c.APIClient.R(). SetResult(ocr2Keys). Get("/v2/keys/ocr2") @@ -391,7 +395,7 @@ func (c *ChainlinkClient) ReadOCR2Keys() (*OCR2Keys, *http.Response, error) { // MustReadOCR2Keys reads all OCR2Keys from the Chainlink node returns err if response not 200 func (c *ChainlinkClient) MustReadOCR2Keys() (*OCR2Keys, error) { ocr2Keys := &OCR2Keys{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Reading OCR2 Keys") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Reading OCR2 Keys") resp, err := c.APIClient.R(). SetResult(ocr2Keys). Get("/v2/keys/ocr2") @@ -404,7 +408,7 @@ func (c *ChainlinkClient) MustReadOCR2Keys() (*OCR2Keys, error) { // DeleteOCR2Key deletes an OCR2Key based on the provided ID func (c *ChainlinkClient) DeleteOCR2Key(id string) (*http.Response, error) { - log.Info().Str(NodeURL, c.Config.URL).Str("ID", id).Msg("Deleting OCR2 Key") + c.l.Info().Str(NodeURL, c.Config.URL).Str("ID", id).Msg("Deleting OCR2 Key") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "id": id, @@ -419,7 +423,7 @@ func (c *ChainlinkClient) DeleteOCR2Key(id string) (*http.Response, error) { // CreateP2PKey creates an P2PKey on the Chainlink node func (c *ChainlinkClient) CreateP2PKey() (*P2PKey, *http.Response, error) { p2pKey := &P2PKey{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Creating P2P Key") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Creating P2P Key") resp, err := c.APIClient.R(). SetResult(p2pKey). Post("/v2/keys/p2p") @@ -433,7 +437,7 @@ func (c *ChainlinkClient) CreateP2PKey() (*P2PKey, *http.Response, error) { // the request is unsuccessful func (c *ChainlinkClient) MustReadP2PKeys() (*P2PKeys, error) { p2pKeys := &P2PKeys{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Reading P2P Keys") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Reading P2P Keys") resp, err := c.APIClient.R(). SetResult(p2pKeys). Get("/v2/keys/p2p") @@ -443,7 +447,7 @@ func (c *ChainlinkClient) MustReadP2PKeys() (*P2PKeys, error) { err = VerifyStatusCode(resp.StatusCode(), http.StatusOK) if len(p2pKeys.Data) == 0 { err = fmt.Errorf("Found no P2P Keys on the Chainlink node. Node URL: %s", c.Config.URL) - log.Err(err).Msg("Error getting P2P keys") + c.l.Err(err).Msg("Error getting P2P keys") return nil, err } for index := range p2pKeys.Data { @@ -454,7 +458,7 @@ func (c *ChainlinkClient) MustReadP2PKeys() (*P2PKeys, error) { // DeleteP2PKey deletes a P2PKey on the Chainlink node based on the provided ID func (c *ChainlinkClient) DeleteP2PKey(id int) (*http.Response, error) { - log.Info().Str(NodeURL, c.Config.URL).Int("ID", id).Msg("Deleting P2P Key") + c.l.Info().Str(NodeURL, c.Config.URL).Int("ID", id).Msg("Deleting P2P Key") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "id": fmt.Sprint(id), @@ -470,7 +474,7 @@ func (c *ChainlinkClient) DeleteP2PKey(id int) (*http.Response, error) { // the request is unsuccessful func (c *ChainlinkClient) MustReadETHKeys() (*ETHKeys, error) { ethKeys := ÐKeys{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Reading ETH Keys") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Reading ETH Keys") resp, err := c.APIClient.R(). SetResult(ethKeys). Get("/v2/keys/eth") @@ -479,7 +483,7 @@ func (c *ChainlinkClient) MustReadETHKeys() (*ETHKeys, error) { } err = VerifyStatusCode(resp.StatusCode(), http.StatusOK) if len(ethKeys.Data) == 0 { - log.Warn().Str(NodeURL, c.Config.URL).Msg("Found no ETH Keys on the node") + c.l.Warn().Str(NodeURL, c.Config.URL).Msg("Found no ETH Keys on the node") } return ethKeys, err } @@ -487,7 +491,7 @@ func (c *ChainlinkClient) MustReadETHKeys() (*ETHKeys, error) { // UpdateEthKeyMaxGasPriceGWei updates the maxGasPriceGWei for an eth key func (c *ChainlinkClient) UpdateEthKeyMaxGasPriceGWei(keyId string, gWei int) (*ETHKey, *http.Response, error) { ethKey := ÐKey{} - log.Info().Str(NodeURL, c.Config.URL).Str("ID", keyId).Int("maxGasPriceGWei", gWei).Msg("Update maxGasPriceGWei for eth key") + c.l.Info().Str(NodeURL, c.Config.URL).Str("ID", keyId).Int("maxGasPriceGWei", gWei).Msg("Update maxGasPriceGWei for eth key") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "keyId": keyId, @@ -608,7 +612,7 @@ func (c *ChainlinkClient) ExportEVMKeys() ([]*ExportedEVMKey, error) { exportedKeys = append(exportedKeys, exportedKey) } } - log.Info(). + c.l.Info(). Str(NodeURL, c.Config.URL). Str("Password", ChainlinkKeyPassword). Msg("Exported EVM Keys") @@ -636,7 +640,7 @@ func (c *ChainlinkClient) ExportEVMKeysForChain(chainid string) ([]*ExportedEVMK exportedKeys = append(exportedKeys, exportedKey) } } - log.Info(). + c.l.Info(). Str(NodeURL, c.Config.URL). Str("Password", ChainlinkKeyPassword). Msg("Exported EVM Keys") @@ -646,7 +650,7 @@ func (c *ChainlinkClient) ExportEVMKeysForChain(chainid string) ([]*ExportedEVMK // CreateTxKey creates a tx key on the Chainlink node func (c *ChainlinkClient) CreateTxKey(chain string, chainId string) (*TxKey, *http.Response, error) { txKey := &TxKey{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Creating Tx Key") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Creating Tx Key") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "chain": chain, @@ -663,7 +667,7 @@ func (c *ChainlinkClient) CreateTxKey(chain string, chainId string) (*TxKey, *ht // ReadTxKeys reads all tx keys from the Chainlink node func (c *ChainlinkClient) ReadTxKeys(chain string) (*TxKeys, *http.Response, error) { txKeys := &TxKeys{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Reading Tx Keys") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Reading Tx Keys") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "chain": chain, @@ -678,7 +682,7 @@ func (c *ChainlinkClient) ReadTxKeys(chain string) (*TxKeys, *http.Response, err // DeleteTxKey deletes an tx key based on the provided ID func (c *ChainlinkClient) DeleteTxKey(chain string, id string) (*http.Response, error) { - log.Info().Str(NodeURL, c.Config.URL).Str("ID", id).Msg("Deleting Tx Key") + c.l.Info().Str(NodeURL, c.Config.URL).Str("ID", id).Msg("Deleting Tx Key") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "chain": chain, @@ -695,7 +699,7 @@ func (c *ChainlinkClient) DeleteTxKey(chain string, id string) (*http.Response, // and returns error if the request is unsuccessful func (c *ChainlinkClient) MustReadTransactionAttempts() (*TransactionsData, error) { txsData := &TransactionsData{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Reading Transaction Attempts") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Reading Transaction Attempts") resp, err := c.APIClient.R(). SetResult(txsData). Get("/v2/tx_attempts") @@ -709,7 +713,7 @@ func (c *ChainlinkClient) MustReadTransactionAttempts() (*TransactionsData, erro // ReadTransactions reads all transactions made by the Chainlink node func (c *ChainlinkClient) ReadTransactions() (*TransactionsData, *http.Response, error) { txsData := &TransactionsData{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Reading Transactions") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Reading Transactions") resp, err := c.APIClient.R(). SetResult(txsData). Get("/v2/transactions") @@ -735,7 +739,7 @@ func (c *ChainlinkClient) MustSendNativeToken(amount *big.Int, fromAddress, toAd SetResult(txData). Post("/v2/transfers") - log.Info(). + c.l.Info(). Str(NodeURL, c.Config.URL). Str("From", fromAddress). Str("To", toAddress). @@ -751,7 +755,7 @@ func (c *ChainlinkClient) MustSendNativeToken(amount *big.Int, fromAddress, toAd // ReadVRFKeys reads all VRF keys from the Chainlink node func (c *ChainlinkClient) ReadVRFKeys() (*VRFKeys, *http.Response, error) { vrfKeys := &VRFKeys{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Reading VRF Keys") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Reading VRF Keys") resp, err := c.APIClient.R(). SetResult(vrfKeys). Get("/v2/keys/vrf") @@ -759,7 +763,7 @@ func (c *ChainlinkClient) ReadVRFKeys() (*VRFKeys, *http.Response, error) { return nil, nil, err } if len(vrfKeys.Data) == 0 { - log.Warn().Str(NodeURL, c.Config.URL).Msg("Found no VRF Keys on the node") + c.l.Warn().Str(NodeURL, c.Config.URL).Msg("Found no VRF Keys on the node") } return vrfKeys, resp.RawResponse, err } @@ -768,7 +772,7 @@ func (c *ChainlinkClient) ReadVRFKeys() (*VRFKeys, *http.Response, error) { // and returns error if the request is unsuccessful func (c *ChainlinkClient) MustCreateVRFKey() (*VRFKey, error) { vrfKey := &VRFKey{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Creating VRF Key") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Creating VRF Key") resp, err := c.APIClient.R(). SetResult(vrfKey). Post("/v2/keys/vrf") @@ -781,7 +785,7 @@ func (c *ChainlinkClient) MustCreateVRFKey() (*VRFKey, error) { // ExportVRFKey exports a vrf key by key id func (c *ChainlinkClient) ExportVRFKey(keyId string) (*VRFExportKey, *http.Response, error) { vrfExportKey := &VRFExportKey{} - log.Info().Str(NodeURL, c.Config.URL).Str("ID", keyId).Msg("Exporting VRF Key") + c.l.Info().Str(NodeURL, c.Config.URL).Str("ID", keyId).Msg("Exporting VRF Key") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "keyId": keyId, @@ -797,7 +801,7 @@ func (c *ChainlinkClient) ExportVRFKey(keyId string) (*VRFExportKey, *http.Respo // ImportVRFKey import vrf key func (c *ChainlinkClient) ImportVRFKey(vrfExportKey *VRFExportKey) (*VRFKey, *http.Response, error) { vrfKey := &VRFKey{} - log.Info().Str(NodeURL, c.Config.URL).Str("ID", vrfExportKey.VrfKey.Address).Msg("Importing VRF Key") + c.l.Info().Str(NodeURL, c.Config.URL).Str("ID", vrfExportKey.VrfKey.Address).Msg("Importing VRF Key") resp, err := c.APIClient.R(). SetBody(vrfExportKey). SetResult(vrfKey). @@ -812,7 +816,7 @@ func (c *ChainlinkClient) ImportVRFKey(vrfExportKey *VRFExportKey) (*VRFKey, *ht // and returns error if the request is unsuccessful func (c *ChainlinkClient) MustCreateDkgSignKey() (*DKGSignKey, error) { dkgSignKey := &DKGSignKey{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Creating DKG Sign Key") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Creating DKG Sign Key") resp, err := c.APIClient.R(). SetResult(dkgSignKey). Post("/v2/keys/dkgsign") @@ -826,7 +830,7 @@ func (c *ChainlinkClient) MustCreateDkgSignKey() (*DKGSignKey, error) { // and returns error if the request is unsuccessful func (c *ChainlinkClient) MustCreateDkgEncryptKey() (*DKGEncryptKey, error) { dkgEncryptKey := &DKGEncryptKey{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Creating DKG Encrypt Key") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Creating DKG Encrypt Key") resp, err := c.APIClient.R(). SetResult(dkgEncryptKey). Post("/v2/keys/dkgencrypt") @@ -839,7 +843,7 @@ func (c *ChainlinkClient) MustCreateDkgEncryptKey() (*DKGEncryptKey, error) { // MustReadDKGSignKeys reads all DKG Sign Keys from the Chainlink node returns err if response not 200 func (c *ChainlinkClient) MustReadDKGSignKeys() (*DKGSignKeys, error) { dkgSignKeys := &DKGSignKeys{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Reading DKG Sign Keys") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Reading DKG Sign Keys") resp, err := c.APIClient.R(). SetResult(dkgSignKeys). Get("/v2/keys/dkgsign") @@ -853,7 +857,7 @@ func (c *ChainlinkClient) MustReadDKGSignKeys() (*DKGSignKeys, error) { // MustReadDKGEncryptKeys reads all DKG Encrypt Keys from the Chainlink node returns err if response not 200 func (c *ChainlinkClient) MustReadDKGEncryptKeys() (*DKGEncryptKeys, error) { dkgEncryptKeys := &DKGEncryptKeys{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Reading DKG Encrypt Keys") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Reading DKG Encrypt Keys") resp, err := c.APIClient.R(). SetResult(dkgEncryptKeys). Get("/v2/keys/dkgencrypt") @@ -867,7 +871,7 @@ func (c *ChainlinkClient) MustReadDKGEncryptKeys() (*DKGEncryptKeys, error) { // 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{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Creating CSA Key") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Creating CSA Key") resp, err := c.APIClient.R(). SetResult(csaKey). Post("/v2/keys/csa") @@ -880,12 +884,12 @@ func (c *ChainlinkClient) CreateCSAKey() (*CSAKey, *http.Response, error) { // ReadCSAKeys reads CSA keys from the Chainlink node func (c *ChainlinkClient) ReadCSAKeys() (*CSAKeys, *http.Response, error) { csaKeys := &CSAKeys{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Reading CSA Keys") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Reading CSA Keys") resp, err := c.APIClient.R(). SetResult(csaKeys). Get("/v2/keys/csa") if len(csaKeys.Data) == 0 { - log.Warn().Str(NodeURL, c.Config.URL).Msg("Found no CSA Keys on the node") + c.l.Warn().Str(NodeURL, c.Config.URL).Msg("Found no CSA Keys on the node") } if err != nil { return nil, nil, err @@ -896,7 +900,7 @@ func (c *ChainlinkClient) ReadCSAKeys() (*CSAKeys, *http.Response, error) { // CreateEI creates an EI on the Chainlink node based on the provided attributes and returns the respective secrets func (c *ChainlinkClient) CreateEI(eia *EIAttributes) (*EIKeyCreate, *http.Response, error) { ei := EIKeyCreate{} - log.Info().Str(NodeURL, c.Config.URL).Str("Name", eia.Name).Msg("Creating External Initiator") + c.l.Info().Str(NodeURL, c.Config.URL).Str("Name", eia.Name).Msg("Creating External Initiator") resp, err := c.APIClient.R(). SetBody(eia). SetResult(&ei). @@ -910,7 +914,7 @@ func (c *ChainlinkClient) CreateEI(eia *EIAttributes) (*EIKeyCreate, *http.Respo // ReadEIs reads all of the configured EIs from the Chainlink node func (c *ChainlinkClient) ReadEIs() (*EIKeys, *http.Response, error) { ei := EIKeys{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Reading EI Keys") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Reading EI Keys") resp, err := c.APIClient.R(). SetResult(&ei). Get("/v2/external_initiators") @@ -922,7 +926,7 @@ func (c *ChainlinkClient) ReadEIs() (*EIKeys, *http.Response, error) { // DeleteEI deletes an external initiator in the Chainlink node based on the provided name func (c *ChainlinkClient) DeleteEI(name string) (*http.Response, error) { - log.Info().Str(NodeURL, c.Config.URL).Str("Name", name).Msg("Deleting EI") + c.l.Info().Str(NodeURL, c.Config.URL).Str("Name", name).Msg("Deleting EI") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "name": name, @@ -937,7 +941,7 @@ func (c *ChainlinkClient) DeleteEI(name string) (*http.Response, error) { // CreateCosmosChain creates a cosmos chain func (c *ChainlinkClient) CreateCosmosChain(chain *CosmosChainAttributes) (*CosmosChainCreate, *http.Response, error) { response := CosmosChainCreate{} - log.Info().Str(NodeURL, c.Config.URL).Str("Chain ID", chain.ChainID).Msg("Creating Cosmos Chain") + c.l.Info().Str(NodeURL, c.Config.URL).Str("Chain ID", chain.ChainID).Msg("Creating Cosmos Chain") resp, err := c.APIClient.R(). SetBody(chain). SetResult(&response). @@ -951,7 +955,7 @@ func (c *ChainlinkClient) CreateCosmosChain(chain *CosmosChainAttributes) (*Cosm // CreateCosmosNode creates a cosmos node func (c *ChainlinkClient) CreateCosmosNode(node *CosmosNodeAttributes) (*CosmosNodeCreate, *http.Response, error) { response := CosmosNodeCreate{} - log.Info().Str(NodeURL, c.Config.URL).Str("Name", node.Name).Msg("Creating Cosmos Node") + c.l.Info().Str(NodeURL, c.Config.URL).Str("Name", node.Name).Msg("Creating Cosmos Node") resp, err := c.APIClient.R(). SetBody(node). SetResult(&response). @@ -965,7 +969,7 @@ func (c *ChainlinkClient) CreateCosmosNode(node *CosmosNodeAttributes) (*CosmosN // CreateSolanaChain creates a solana chain func (c *ChainlinkClient) CreateSolanaChain(chain *SolanaChainAttributes) (*SolanaChainCreate, *http.Response, error) { response := SolanaChainCreate{} - log.Info().Str(NodeURL, c.Config.URL).Str("Chain ID", chain.ChainID).Msg("Creating Solana Chain") + c.l.Info().Str(NodeURL, c.Config.URL).Str("Chain ID", chain.ChainID).Msg("Creating Solana Chain") resp, err := c.APIClient.R(). SetBody(chain). SetResult(&response). @@ -979,7 +983,7 @@ func (c *ChainlinkClient) CreateSolanaChain(chain *SolanaChainAttributes) (*Sola // CreateSolanaNode creates a solana node func (c *ChainlinkClient) CreateSolanaNode(node *SolanaNodeAttributes) (*SolanaNodeCreate, *http.Response, error) { response := SolanaNodeCreate{} - log.Info().Str(NodeURL, c.Config.URL).Str("Name", node.Name).Msg("Creating Solana Node") + c.l.Info().Str(NodeURL, c.Config.URL).Str("Name", node.Name).Msg("Creating Solana Node") resp, err := c.APIClient.R(). SetBody(node). SetResult(&response). @@ -993,7 +997,7 @@ func (c *ChainlinkClient) CreateSolanaNode(node *SolanaNodeAttributes) (*SolanaN // CreateStarkNetChain creates a starknet chain func (c *ChainlinkClient) CreateStarkNetChain(chain *StarkNetChainAttributes) (*StarkNetChainCreate, *http.Response, error) { response := StarkNetChainCreate{} - log.Info().Str(NodeURL, c.Config.URL).Str("Chain ID", chain.ChainID).Msg("Creating StarkNet Chain") + c.l.Info().Str(NodeURL, c.Config.URL).Str("Chain ID", chain.ChainID).Msg("Creating StarkNet Chain") resp, err := c.APIClient.R(). SetBody(chain). SetResult(&response). @@ -1007,7 +1011,7 @@ func (c *ChainlinkClient) CreateStarkNetChain(chain *StarkNetChainAttributes) (* // CreateStarkNetNode creates a starknet node func (c *ChainlinkClient) CreateStarkNetNode(node *StarkNetNodeAttributes) (*StarkNetNodeCreate, *http.Response, error) { response := StarkNetNodeCreate{} - log.Info().Str(NodeURL, c.Config.URL).Str("Name", node.Name).Msg("Creating StarkNet Node") + c.l.Info().Str(NodeURL, c.Config.URL).Str("Name", node.Name).Msg("Creating StarkNet Node") resp, err := c.APIClient.R(). SetBody(node). SetResult(&response). @@ -1030,14 +1034,14 @@ func (c *ChainlinkClient) Profile(profileTime time.Duration, profileFunction fun profileResults := NewBlankChainlinkProfileResults() profileErrorGroup := new(errgroup.Group) var profileExecutedGroup sync.WaitGroup - log.Info().Int("Seconds to Profile", profileSeconds).Str(NodeURL, c.Config.URL).Msg("Starting Node PPROF session") + c.l.Info().Int("Seconds to Profile", profileSeconds).Str(NodeURL, c.Config.URL).Msg("Starting Node PPROF session") for _, rep := range profileResults.Reports { profileExecutedGroup.Add(1) profileReport := rep // The profile function returns with the profile results after the profile time frame has concluded // e.g. a profile API call of 5 seconds will start profiling, wait for 5 seconds, then send back results profileErrorGroup.Go(func() error { - log.Debug().Str("Type", profileReport.Type).Msg("PROFILING") + c.l.Debug().Str("Type", profileReport.Type).Msg("PROFILING") profileExecutedGroup.Done() resp, err := c.APIClient.R(). SetPathParams(map[string]string{ @@ -1054,7 +1058,7 @@ func (c *ChainlinkClient) Profile(profileTime time.Duration, profileFunction fun if err != nil { return err } - log.Debug().Str("Type", profileReport.Type).Msg("DONE PROFILING") + c.l.Debug().Str("Type", profileReport.Type).Msg("DONE PROFILING") profileReport.Data = resp.Body() return err }) @@ -1070,12 +1074,12 @@ func (c *ChainlinkClient) Profile(profileTime time.Duration, profileFunction fun actualSeconds := int(actualRunTime.Seconds()) if actualSeconds > profileSeconds { - log.Warn(). + c.l.Warn(). Int("Actual Seconds", actualSeconds). Int("Profile Seconds", profileSeconds). Msg("Your profile function took longer than expected to run, increase profileTime") } else if actualSeconds < profileSeconds && actualSeconds > 0 { - log.Warn(). + c.l.Warn(). Int("Actual Seconds", actualSeconds). Int("Profile Seconds", profileSeconds). Msg("Your profile function took shorter than expected to run, you can decrease profileTime") @@ -1174,7 +1178,7 @@ func (c *ChainlinkClient) TrackForwarder(chainID *big.Int, address common.Addres ChainID: chainID.String(), Address: address.Hex(), } - log.Debug().Str(NodeURL, c.Config.URL). + c.l.Debug().Str(NodeURL, c.Config.URL). Str("Forwarder address", (address).Hex()). Str("Chain ID", chainID.String()). Msg("Track forwarder") @@ -1196,7 +1200,7 @@ func (c *ChainlinkClient) TrackForwarder(chainID *big.Int, address common.Addres // GetForwarders get list of tracked forwarders func (c *ChainlinkClient) GetForwarders() (*Forwarders, *http.Response, error) { response := &Forwarders{} - log.Info().Str(NodeURL, c.Config.URL).Msg("Reading Tracked Forwarders") + c.l.Info().Str(NodeURL, c.Config.URL).Msg("Reading Tracked Forwarders") resp, err := c.APIClient.R(). SetResult(response). Get("/v2/nodes/evm/forwarders") diff --git a/integration-tests/client/chainlink_models.go b/integration-tests/client/chainlink_models.go index d1b2f8eae9d..6013e13e0fa 100644 --- a/integration-tests/client/chainlink_models.go +++ b/integration-tests/client/chainlink_models.go @@ -762,6 +762,7 @@ func (d *DirectRequestTxPipelineSpec) String() (string, error) { type DirectRequestJobSpec struct { Name string `toml:"name"` ContractAddress string `toml:"contractAddress"` + EVMChainID string `toml:"evmChainID"` ExternalJobID string `toml:"externalJobID"` MinIncomingConfirmations string `toml:"minIncomingConfirmations"` ObservationSource string `toml:"observationSource"` // List of commands for the Chainlink node @@ -777,6 +778,7 @@ schemaVersion = 1 name = "{{.Name}}" maxTaskDuration = "99999s" contractAddress = "{{.ContractAddress}}" +evmChainID = "{{.EVMChainID}}" externalJobID = "{{.ExternalJobID}}" minIncomingConfirmations = {{.MinIncomingConfirmations}} observationSource = """ @@ -789,6 +791,7 @@ observationSource = """ type FluxMonitorJobSpec struct { Name string `toml:"name"` ContractAddress string `toml:"contractAddress"` // Address of the Flux Monitor script + EVMChainID string `toml:"evmChainID"` // Not optional Precision int `toml:"precision"` // Optional Threshold float32 `toml:"threshold"` // Optional AbsoluteThreshold float32 `toml:"absoluteThreshold"` // Optional @@ -809,6 +812,7 @@ func (f *FluxMonitorJobSpec) String() (string, error) { schemaVersion = 1 name = "{{.Name}}" contractAddress = "{{.ContractAddress}}" +evmChainID = "{{.EVMChainID}}" precision ={{if not .Precision}} 0 {{else}} {{.Precision}} {{end}} threshold ={{if not .Threshold}} 0.5 {{else}} {{.Threshold}} {{end}} absoluteThreshold ={{if not .AbsoluteThreshold}} 0.1 {{else}} {{.AbsoluteThreshold}} {{end}} @@ -832,6 +836,7 @@ type KeeperJobSpec struct { Name string `toml:"name"` ContractAddress string `toml:"contractAddress"` FromAddress string `toml:"fromAddress"` // Hex representation of the from address + EVMChainID string `toml:"evmChainID"` // Not optional MinIncomingConfirmations int `toml:"minIncomingConfirmations"` } @@ -846,6 +851,7 @@ schemaVersion = 1 name = "{{.Name}}" contractAddress = "{{.ContractAddress}}" fromAddress = "{{.FromAddress}}" +evmChainID = "{{.EVMChainID}}" minIncomingConfirmations = {{.MinIncomingConfirmations}} ` return MarshallTemplate(k, "Keeper Job", keeperTemplateString) @@ -860,8 +866,9 @@ type OCRBootstrapJobSpec struct { TrackerPollInterval time.Duration `toml:"contractConfigTrackerPollInterval"` // Optional TrackerSubscribeInterval time.Duration `toml:"contractConfigTrackerSubscribeInterval"` // Optional ContractAddress string `toml:"contractAddress"` // Address of the OCR contract - IsBootstrapPeer bool `toml:"isBootstrapPeer"` // Typically true - P2PPeerID string `toml:"p2pPeerID"` // This node's P2P ID + EVMChainID string `toml:"evmChainID"` + IsBootstrapPeer bool `toml:"isBootstrapPeer"` // Typically true + P2PPeerID string `toml:"p2pPeerID"` // This node's P2P ID } // Type returns the type of the job @@ -876,6 +883,7 @@ contractConfigConfirmations ={{if not .ContractConfirmations}} 3 {{el contractConfigTrackerPollInterval ={{if not .TrackerPollInterval}} "1m" {{else}} {{.TrackerPollInterval}} {{end}} contractConfigTrackerSubscribeInterval ={{if not .TrackerSubscribeInterval}} "2m" {{else}} {{.TrackerSubscribeInterval}} {{end}} contractAddress = "{{.ContractAddress}}" +evmChainID = "{{.EVMChainID}}" p2pBootstrapPeers = [] isBootstrapPeer = {{.IsBootstrapPeer}} p2pPeerID = "{{.P2PPeerID}}"` @@ -892,13 +900,14 @@ type OCRTaskJobSpec struct { TrackerSubscribeInterval time.Duration `toml:"contractConfigTrackerSubscribeInterval"` // Optional ForwardingAllowed bool `toml:"forwardingAllowed"` // Optional, by default false ContractAddress string `toml:"contractAddress"` // Address of the OCR contract - P2PBootstrapPeers []*ChainlinkClient `toml:"p2pBootstrapPeers"` // P2P ID of the bootstrap node - IsBootstrapPeer bool `toml:"isBootstrapPeer"` // Typically false - P2PPeerID string `toml:"p2pPeerID"` // This node's P2P ID - KeyBundleID string `toml:"keyBundleID"` // ID of this node's OCR key bundle - MonitoringEndpoint string `toml:"monitoringEndpoint"` // Typically "chain.link:4321" - TransmitterAddress string `toml:"transmitterAddress"` // ETH address this node will use to transmit its answer - ObservationSource string `toml:"observationSource"` // List of commands for the Chainlink node + EVMChainID string `toml:"evmChainID"` + P2PBootstrapPeers []*ChainlinkClient `toml:"p2pBootstrapPeers"` // P2P ID of the bootstrap node + IsBootstrapPeer bool `toml:"isBootstrapPeer"` // Typically false + P2PPeerID string `toml:"p2pPeerID"` // This node's P2P ID + KeyBundleID string `toml:"keyBundleID"` // ID of this node's OCR key bundle + MonitoringEndpoint string `toml:"monitoringEndpoint"` // Typically "chain.link:4321" + TransmitterAddress string `toml:"transmitterAddress"` // ETH address this node will use to transmit its answer + ObservationSource string `toml:"observationSource"` // List of commands for the Chainlink node } // P2PData holds the remote ip and the peer id and port @@ -939,6 +948,7 @@ func (o *OCRTaskJobSpec) String() (string, error) { TrackerPollInterval time.Duration TrackerSubscribeInterval time.Duration ContractAddress string + EVMChainID string P2PBootstrapPeers []P2PData IsBootstrapPeer bool P2PPeerID string @@ -954,6 +964,7 @@ func (o *OCRTaskJobSpec) String() (string, error) { TrackerPollInterval: o.TrackerPollInterval, TrackerSubscribeInterval: o.TrackerSubscribeInterval, ContractAddress: o.ContractAddress, + EVMChainID: o.EVMChainID, P2PBootstrapPeers: peers, IsBootstrapPeer: o.IsBootstrapPeer, P2PPeerID: o.P2PPeerID, @@ -971,6 +982,7 @@ contractConfigConfirmations ={{if not .ContractConfirmations}} 3 {{el contractConfigTrackerPollInterval ={{if not .TrackerPollInterval}} "1m" {{else}} {{.TrackerPollInterval}} {{end}} contractConfigTrackerSubscribeInterval ={{if not .TrackerSubscribeInterval}} "2m" {{else}} {{.TrackerSubscribeInterval}} {{end}} contractAddress = "{{.ContractAddress}}" +evmChainID = "{{.EVMChainID}}" {{if .P2PBootstrapPeers}} p2pBootstrapPeers = [ {{range $peer := .P2PBootstrapPeers}} @@ -1186,6 +1198,7 @@ type VRFJobSpec struct { Name string `toml:"name"` CoordinatorAddress string `toml:"coordinatorAddress"` // Address of the VRF CoordinatorV2 contract PublicKey string `toml:"publicKey"` // Public key of the proving key + EVMChainID string `toml:"evmChainID"` ExternalJobID string `toml:"externalJobID"` ObservationSource string `toml:"observationSource"` // List of commands for the Chainlink node MinIncomingConfirmations int `toml:"minIncomingConfirmations"` @@ -1203,6 +1216,7 @@ name = "{{.Name}}" coordinatorAddress = "{{.CoordinatorAddress}}" minIncomingConfirmations = {{.MinIncomingConfirmations}} publicKey = "{{.PublicKey}}" +evmChainID = "{{.EVMChainID}}" externalJobID = "{{.ExternalJobID}}" observationSource = """ {{.ObservationSource}} diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index 4c4d2b87a81..a3adb6db13a 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" @@ -116,30 +117,30 @@ type ContractDeployer interface { } // NewContractDeployer returns an instance of a contract deployer based on the client type -func NewContractDeployer(bcClient blockchain.EVMClient) (ContractDeployer, error) { +func NewContractDeployer(bcClient blockchain.EVMClient, logger zerolog.Logger) (ContractDeployer, error) { switch clientImpl := bcClient.Get().(type) { case *blockchain.EthereumClient: - return NewEthereumContractDeployer(clientImpl), nil + return NewEthereumContractDeployer(clientImpl, logger), nil case *blockchain.KlaytnClient: - return &KlaytnContractDeployer{NewEthereumContractDeployer(clientImpl)}, nil + return &KlaytnContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil case *blockchain.MetisClient: - return &MetisContractDeployer{NewEthereumContractDeployer(clientImpl)}, nil + return &MetisContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil case *blockchain.ArbitrumClient: - return &MetisContractDeployer{NewEthereumContractDeployer(clientImpl)}, nil + return &MetisContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil case *blockchain.OptimismClient: - return &OptimismContractDeployer{NewEthereumContractDeployer(clientImpl)}, nil + return &OptimismContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil case *blockchain.RSKClient: - return &RSKContractDeployer{NewEthereumContractDeployer(clientImpl)}, nil + return &RSKContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil case *blockchain.PolygonClient: - return &PolygonContractDeployer{NewEthereumContractDeployer(clientImpl)}, nil + return &PolygonContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil case *blockchain.CeloClient: - return &CeloContractDeployer{NewEthereumContractDeployer(clientImpl)}, nil + return &CeloContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil case *blockchain.QuorumClient: - return &QuorumContractDeployer{NewEthereumContractDeployer(clientImpl)}, nil + return &QuorumContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil case *blockchain.BSCClient: - return &BSCContractDeployer{NewEthereumContractDeployer(clientImpl)}, nil + return &BSCContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil case *blockchain.ScrollClient: - return &ScrollContractDeployer{NewEthereumContractDeployer(clientImpl)}, nil + return &ScrollContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil } return nil, errors.New("unknown blockchain client implementation for contract deployer, register blockchain client in NewContractDeployer") } @@ -147,6 +148,7 @@ func NewContractDeployer(bcClient blockchain.EVMClient) (ContractDeployer, error // EthereumContractDeployer provides the implementations for deploying ETH (EVM) based contracts type EthereumContractDeployer struct { client blockchain.EVMClient + l zerolog.Logger } // KlaytnContractDeployer wraps ethereum contract deployments for Klaytn @@ -195,9 +197,10 @@ type ScrollContractDeployer struct { } // NewEthereumContractDeployer returns an instantiated instance of the ETH contract deployer -func NewEthereumContractDeployer(ethClient blockchain.EVMClient) *EthereumContractDeployer { +func NewEthereumContractDeployer(ethClient blockchain.EVMClient, logger zerolog.Logger) *EthereumContractDeployer { return &EthereumContractDeployer{ client: ethClient, + l: logger, } } @@ -451,6 +454,7 @@ func (e *EthereumContractDeployer) DeployLinkTokenContract() (LinkToken, error) client: e.client, instance: instance.(*link_token_interface.LinkToken), address: *linkTokenAddress, + l: e.l, }, err } @@ -469,6 +473,7 @@ func (e *EthereumContractDeployer) LoadLinkToken(address common.Address) (LinkTo address: address, client: e.client, instance: instance.(*link_token_interface.LinkToken), + l: e.l, }, err } @@ -551,6 +556,7 @@ func (e *EthereumContractDeployer) DeployOffChainAggregator( client: e.client, ocr: instance.(*offchainaggregator.OffchainAggregator), address: address, + l: e.l, }, err } @@ -569,6 +575,7 @@ func (e *EthereumContractDeployer) LoadOffChainAggregator(address *common.Addres address: address, client: e.client, ocr: instance.(*offchainaggregator.OffchainAggregator), + l: e.l, }, err } @@ -1423,5 +1430,6 @@ func (e *EthereumContractDeployer) DeployOffchainAggregatorV2( client: e.client, contract: instance.(*ocr2aggregator.OCR2Aggregator), address: address, + l: e.l, }, err } diff --git a/integration-tests/contracts/contract_loader.go b/integration-tests/contracts/contract_loader.go index 7517ef7ba7e..a790747e38d 100644 --- a/integration-tests/contracts/contract_loader.go +++ b/integration-tests/contracts/contract_loader.go @@ -2,8 +2,10 @@ package contracts import ( "errors" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/rs/zerolog" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_coordinator" @@ -12,6 +14,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier_proxy" ) // ContractLoader is an interface for abstracting the contract loading methods across network implementations @@ -24,23 +28,27 @@ type ContractLoader interface { LoadFunctionsCoordinator(addr string) (FunctionsCoordinator, error) LoadFunctionsRouter(addr string) (FunctionsRouter, error) LoadFunctionsLoadTestClient(addr string) (FunctionsLoadTestClient, error) + + // Mercury + LoadMercuryVerifier(addr string) (MercuryVerifier, error) + LoadMercuryVerifierProxy(addr string) (MercuryVerifierProxy, error) } // NewContractLoader returns an instance of a contract Loader based on the client type -func NewContractLoader(bcClient blockchain.EVMClient) (ContractLoader, error) { +func NewContractLoader(bcClient blockchain.EVMClient, logger zerolog.Logger) (ContractLoader, error) { switch clientImpl := bcClient.Get().(type) { case *blockchain.EthereumClient: - return NewEthereumContractLoader(clientImpl), nil + return NewEthereumContractLoader(clientImpl, logger), nil case *blockchain.KlaytnClient: - return &KlaytnContractLoader{NewEthereumContractLoader(clientImpl)}, nil + return &KlaytnContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil case *blockchain.MetisClient: - return &MetisContractLoader{NewEthereumContractLoader(clientImpl)}, nil + return &MetisContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil case *blockchain.ArbitrumClient: - return &ArbitrumContractLoader{NewEthereumContractLoader(clientImpl)}, nil + return &ArbitrumContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil case *blockchain.PolygonClient: - return &PolygonContractLoader{NewEthereumContractLoader(clientImpl)}, nil + return &PolygonContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil case *blockchain.OptimismClient: - return &OptimismContractLoader{NewEthereumContractLoader(clientImpl)}, nil + return &OptimismContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil } return nil, errors.New("unknown blockchain client implementation for contract Loader, register blockchain client in NewContractLoader") } @@ -48,6 +56,7 @@ func NewContractLoader(bcClient blockchain.EVMClient) (ContractLoader, error) { // EthereumContractLoader provides the implementations for deploying ETH (EVM) based contracts type EthereumContractLoader struct { client blockchain.EVMClient + l zerolog.Logger } // KlaytnContractLoader wraps ethereum contract deployments for Klaytn @@ -76,9 +85,10 @@ type OptimismContractLoader struct { } // NewEthereumContractLoader returns an instantiated instance of the ETH contract Loader -func NewEthereumContractLoader(ethClient blockchain.EVMClient) *EthereumContractLoader { +func NewEthereumContractLoader(ethClient blockchain.EVMClient, logger zerolog.Logger) *EthereumContractLoader { return &EthereumContractLoader{ client: ethClient, + l: logger, } } @@ -97,6 +107,7 @@ func (e *EthereumContractLoader) LoadLINKToken(addr string) (LinkToken, error) { client: e.client, instance: instance.(*link_token_interface.LinkToken), address: common.HexToAddress(addr), + l: e.l, }, err } @@ -133,6 +144,7 @@ func (e *EthereumContractLoader) LoadFunctionsRouter(addr string) (FunctionsRout client: e.client, instance: instance.(*functions_router.FunctionsRouter), address: common.HexToAddress(addr), + l: e.l, }, err } @@ -169,6 +181,7 @@ func (e *EthereumContractLoader) LoadOperatorContract(address common.Address) (O address: address, client: e.client, operator: instance.(*operator_wrapper.Operator), + l: e.l, }, err } @@ -189,3 +202,39 @@ func (e *EthereumContractLoader) LoadAuthorizedForwarder(address common.Address) authorizedForwarder: instance.(*authorized_forwarder.AuthorizedForwarder), }, err } + +// LoadMercuryVerifier returns Verifier contract deployed on given address +func (e *EthereumContractLoader) LoadMercuryVerifier(addr string) (MercuryVerifier, error) { + instance, err := e.client.LoadContract("Mercury Verifier", common.HexToAddress(addr), func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return verifier.NewVerifier(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumMercuryVerifier{ + client: e.client, + instance: instance.(*verifier.Verifier), + address: common.HexToAddress(addr), + }, err +} + +// LoadMercuryVerifierProxy returns VerifierProxy contract deployed on given address +func (e *EthereumContractLoader) LoadMercuryVerifierProxy(addr string) (MercuryVerifierProxy, error) { + instance, err := e.client.LoadContract("Mercury Verifier Proxy", common.HexToAddress(addr), func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return verifier_proxy.NewVerifierProxy(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumMercuryVerifierProxy{ + client: e.client, + instance: instance.(*verifier_proxy.VerifierProxy), + address: common.HexToAddress(addr), + }, err +} diff --git a/integration-tests/contracts/contract_models.go b/integration-tests/contracts/contract_models.go index 8e9d561f822..7bcddceae5e 100644 --- a/integration-tests/contracts/contract_models.go +++ b/integration-tests/contracts/contract_models.go @@ -367,3 +367,14 @@ type FunctionsLoadTestClient interface { SendRequest(times uint32, source string, encryptedSecretsReferences []byte, args []string, subscriptionId uint64, jobId [32]byte) error SendRequestWithDONHostedSecrets(times uint32, source string, slotID uint8, slotVersion uint64, args []string, subscriptionId uint64, donID [32]byte) error } + +type MercuryVerifier interface { + Address() string + Verify(signedReport []byte, sender common.Address) error +} + +type MercuryVerifierProxy interface { + Address() string + Verify(signedReport []byte, value *big.Int) (*types.Transaction, error) + VerifyBulk(signedReports [][]byte, value *big.Int) (*types.Transaction, error) +} diff --git a/integration-tests/contracts/ethereum_contracts.go b/integration-tests/contracts/ethereum_contracts.go index 5e937ad9b72..d11eefecd47 100644 --- a/integration-tests/contracts/ethereum_contracts.go +++ b/integration-tests/contracts/ethereum_contracts.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" @@ -46,6 +47,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/oracle_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/test_api_consumer_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier_proxy" ) // EthereumOracle oracle for "directrequest" job tests @@ -1113,6 +1116,7 @@ type FluxAggregatorRoundConfirmer struct { context context.Context cancel context.CancelFunc complete bool + l zerolog.Logger } // NewFluxAggregatorRoundConfirmer provides a new instance of a FluxAggregatorRoundConfirmer @@ -1120,6 +1124,7 @@ func NewFluxAggregatorRoundConfirmer( contract FluxAggregator, roundID *big.Int, timeout time.Duration, + logger zerolog.Logger, ) *FluxAggregatorRoundConfirmer { ctx, ctxCancel := context.WithTimeout(context.Background(), timeout) return &FluxAggregatorRoundConfirmer{ @@ -1128,6 +1133,7 @@ func NewFluxAggregatorRoundConfirmer( doneChan: make(chan struct{}), context: ctx, cancel: ctxCancel, + l: logger, } } @@ -1147,11 +1153,11 @@ func (f *FluxAggregatorRoundConfirmer) ReceiveHeader(header blockchain.NodeHeade "Header Number": header.Number.Uint64(), } if lr.Cmp(f.roundID) >= 0 { - log.Info().Fields(logFields).Msg("FluxAggregator round completed") + f.l.Info().Fields(logFields).Msg("FluxAggregator round completed") f.complete = true f.doneChan <- struct{}{} } else { - log.Debug().Fields(logFields).Msg("Waiting for FluxAggregator round") + f.l.Debug().Fields(logFields).Msg("Waiting for FluxAggregator round") } return nil } @@ -1179,6 +1185,7 @@ type EthereumLinkToken struct { client blockchain.EVMClient instance *link_token_interface.LinkToken address common.Address + l zerolog.Logger } // Fund the LINK Token contract with ETH to distribute the token @@ -1220,7 +1227,7 @@ func (l *EthereumLinkToken) Approve(to string, amount *big.Int) error { if err != nil { return err } - log.Info(). + l.l.Info(). Str("From", l.client.GetDefaultWallet().Address()). Str("To", to). Str("Amount", amount.String()). @@ -1238,7 +1245,7 @@ func (l *EthereumLinkToken) Transfer(to string, amount *big.Int) error { if err != nil { return err } - log.Info(). + l.l.Info(). Str("From", l.client.GetDefaultWallet().Address()). Str("To", to). Str("Amount", amount.String()). @@ -1260,7 +1267,7 @@ func (l *EthereumLinkToken) TransferAndCall(to string, amount *big.Int, data []b if err != nil { return nil, err } - log.Info(). + l.l.Info(). Str("From", l.client.GetDefaultWallet().Address()). Str("To", to). Str("Amount", amount.String()). @@ -1275,6 +1282,7 @@ type EthereumOffchainAggregator struct { client blockchain.EVMClient ocr *offchainaggregator.OffchainAggregator address *common.Address + l zerolog.Logger } // Fund sends specified currencies to the contract @@ -1320,7 +1328,7 @@ func (o *EthereumOffchainAggregator) SetPayees( payeesAddr = append(payeesAddr, common.HexToAddress(p)) } - log.Info(). + o.l.Info(). Str("Transmitters", fmt.Sprintf("%v", transmitters)). Str("Payees", fmt.Sprintf("%v", payees)). Str("OCR Address", o.Address()). @@ -1428,7 +1436,7 @@ func (o *EthereumOffchainAggregator) RequestNewRound() error { if err != nil { return err } - log.Info().Str("Contract Address", o.address.Hex()).Msg("New OCR round requested") + o.l.Info().Str("Contract Address", o.address.Hex()).Msg("New OCR round requested") return o.client.ProcessTransaction(tx) } @@ -1510,6 +1518,7 @@ type RunlogRoundConfirmer struct { doneChan chan struct{} context context.Context cancel context.CancelFunc + l zerolog.Logger } // NewRunlogRoundConfirmer provides a new instance of a RunlogRoundConfirmer @@ -1517,6 +1526,7 @@ func NewRunlogRoundConfirmer( contract APIConsumer, roundID *big.Int, timeout time.Duration, + logger zerolog.Logger, ) *RunlogRoundConfirmer { ctx, ctxCancel := context.WithTimeout(context.Background(), timeout) return &RunlogRoundConfirmer{ @@ -1525,6 +1535,7 @@ func NewRunlogRoundConfirmer( doneChan: make(chan struct{}), context: ctx, cancel: ctxCancel, + l: logger, } } @@ -1540,10 +1551,10 @@ func (o *RunlogRoundConfirmer) ReceiveHeader(_ blockchain.NodeHeader) error { "Waiting for Round": o.roundID.Int64(), } if currentRoundID.Cmp(o.roundID) >= 0 { - log.Info().Fields(logFields).Msg("Runlog round completed") + o.l.Info().Fields(logFields).Msg("Runlog round completed") o.doneChan <- struct{}{} } else { - log.Debug().Fields(logFields).Msg("Waiting for Runlog round") + o.l.Debug().Fields(logFields).Msg("Waiting for Runlog round") } return nil } @@ -1570,6 +1581,7 @@ type OffchainAggregatorRoundConfirmer struct { cancel context.CancelFunc blocksSinceAnswer uint complete bool + l zerolog.Logger } // NewOffchainAggregatorRoundConfirmer provides a new instance of a OffchainAggregatorRoundConfirmer @@ -1577,6 +1589,7 @@ func NewOffchainAggregatorRoundConfirmer( contract OffchainAggregator, roundID *big.Int, timeout time.Duration, + logger zerolog.Logger, ) *OffchainAggregatorRoundConfirmer { ctx, ctxCancel := context.WithTimeout(context.Background(), timeout) return &OffchainAggregatorRoundConfirmer{ @@ -1586,6 +1599,7 @@ func NewOffchainAggregatorRoundConfirmer( context: ctx, cancel: ctxCancel, complete: false, + l: logger, } } @@ -1607,11 +1621,11 @@ func (o *OffchainAggregatorRoundConfirmer) ReceiveHeader(_ blockchain.NodeHeader "Waiting for Round": o.roundID.Int64(), } if currRound.Cmp(o.roundID) >= 0 { - log.Info().Fields(logFields).Msg("OCR round completed") + o.l.Info().Fields(logFields).Msg("OCR round completed") o.doneChan <- struct{}{} o.complete = true } else { - log.Debug().Fields(logFields).Msg("Waiting on OCR Round") + o.l.Debug().Fields(logFields).Msg("Waiting on OCR Round") } return nil } @@ -1644,6 +1658,7 @@ type OffchainAggregatorV2RoundConfirmer struct { cancel context.CancelFunc blocksSinceAnswer uint complete bool + l zerolog.Logger } // NewOffchainAggregatorRoundConfirmer provides a new instance of a OffchainAggregatorRoundConfirmer @@ -1651,6 +1666,7 @@ func NewOffchainAggregatorV2RoundConfirmer( contract OffchainAggregatorV2, roundID *big.Int, timeout time.Duration, + logger zerolog.Logger, ) *OffchainAggregatorV2RoundConfirmer { ctx, ctxCancel := context.WithTimeout(context.Background(), timeout) return &OffchainAggregatorV2RoundConfirmer{ @@ -1660,6 +1676,7 @@ func NewOffchainAggregatorV2RoundConfirmer( context: ctx, cancel: ctxCancel, complete: false, + l: logger, } } @@ -1681,11 +1698,11 @@ func (o *OffchainAggregatorV2RoundConfirmer) ReceiveHeader(_ blockchain.NodeHead "Waiting for Round": o.roundID.Int64(), } if currRound.Cmp(o.roundID) >= 0 { - log.Info().Fields(logFields).Msg("OCR round completed") + o.l.Info().Fields(logFields).Msg("OCR round completed") o.doneChan <- struct{}{} o.complete = true } else { - log.Debug().Fields(logFields).Msg("Waiting on OCR Round") + o.l.Debug().Fields(logFields).Msg("Waiting on OCR Round") } return nil } @@ -1813,6 +1830,7 @@ type EthereumOperator struct { address common.Address client blockchain.EVMClient operator *operator_wrapper.Operator + l zerolog.Logger } func (e *EthereumOperator) Address() string { @@ -1824,7 +1842,7 @@ func (e *EthereumOperator) AcceptAuthorizedReceivers(forwarders []common.Address if err != nil { return err } - log.Info(). + e.l.Info(). Str("ForwardersAddresses", fmt.Sprint(forwarders)). Str("EoaAddresses", fmt.Sprint(eoa)). Msg("Accepting Authorized Receivers") @@ -1921,6 +1939,7 @@ type EthereumOffchainAggregatorV2 struct { address *common.Address client blockchain.EVMClient contract *ocr2aggregator.OCR2Aggregator + l zerolog.Logger } // OCRv2Config represents the config for the OCRv2 contract @@ -2006,7 +2025,7 @@ func (e *EthereumOffchainAggregatorV2) SetPayees(transmitters, payees []string) if err != nil { return err } - log.Info(). + e.l.Info(). Str("Transmitters", fmt.Sprintf("%v", transmitters)). Str("Payees", fmt.Sprintf("%v", payees)). Str("OCRv2 Address", e.Address()). @@ -2032,7 +2051,7 @@ func (e *EthereumOffchainAggregatorV2) SetConfig(ocrConfig *OCRv2Config) error { if err != nil { return err } - log.Info(). + e.l.Info(). Str("Address", e.Address()). Interface("Signers", ocrConfig.Signers). Interface("Transmitters", ocrConfig.Transmitters). @@ -2089,6 +2108,7 @@ type EthereumFunctionsRouter struct { address common.Address client blockchain.EVMClient instance *functions_router.FunctionsRouter + l zerolog.Logger } func (e *EthereumFunctionsRouter) Address() string { @@ -2112,7 +2132,7 @@ func (e *EthereumFunctionsRouter) CreateSubscriptionWithConsumer(consumer string return 0, err } for _, l := range r.Logs { - log.Info().Interface("Log", common.Bytes2Hex(l.Data)).Send() + e.l.Info().Interface("Log", common.Bytes2Hex(l.Data)).Send() } topicsMap := map[string]interface{}{} @@ -2121,14 +2141,14 @@ func (e *EthereumFunctionsRouter) CreateSubscriptionWithConsumer(consumer string return 0, err } for _, ev := range fabi.Events { - log.Info().Str("EventName", ev.Name).Send() + e.l.Info().Str("EventName", ev.Name).Send() } topicOneInputs := abi.Arguments{fabi.Events["SubscriptionCreated"].Inputs[0]} topicOneHash := []common.Hash{r.Logs[0].Topics[1:][0]} if err := abi.ParseTopicsIntoMap(topicsMap, topicOneInputs, topicOneHash); err != nil { return 0, errors.Wrap(err, "failed to decode topic value") } - log.Info().Interface("NewTopicsDecoded", topicsMap).Send() + e.l.Info().Interface("NewTopicsDecoded", topicsMap).Send() if topicsMap["subscriptionId"] == 0 { return 0, errors.New("failed to decode subscription ID after creation") } @@ -2244,3 +2264,65 @@ func (e *EthereumFunctionsLoadTestClient) SendRequestWithDONHostedSecrets(times } return e.client.ProcessTransaction(tx) } + +type EthereumMercuryVerifier struct { + address common.Address + client blockchain.EVMClient + instance *verifier.Verifier +} + +func (e *EthereumMercuryVerifier) Address() string { + return e.address.Hex() +} + +func (e *EthereumMercuryVerifier) Verify(signedReport []byte, sender common.Address) error { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := e.instance.Verify(opts, signedReport, sender) + if err != nil { + return err + } + return e.client.ProcessTransaction(tx) +} + +type EthereumMercuryVerifierProxy struct { + address common.Address + client blockchain.EVMClient + instance *verifier_proxy.VerifierProxy +} + +func (e *EthereumMercuryVerifierProxy) Address() string { + return e.address.Hex() +} + +func (e *EthereumMercuryVerifierProxy) Verify(signedReport []byte, value *big.Int) (*types.Transaction, error) { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if value != nil { + opts.Value = value + } + if err != nil { + return nil, err + } + tx, err := e.instance.Verify(opts, signedReport) + if err != nil { + return nil, err + } + return tx, e.client.ProcessTransaction(tx) +} + +func (e *EthereumMercuryVerifierProxy) VerifyBulk(signedReports [][]byte, value *big.Int) (*types.Transaction, error) { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if value != nil { + opts.Value = value + } + if err != nil { + return nil, err + } + tx, err := e.instance.VerifyBulk(opts, signedReports) + if err != nil { + return nil, err + } + return tx, e.client.ProcessTransaction(tx) +} diff --git a/integration-tests/contracts/ethereum_keeper_contracts.go b/integration-tests/contracts/ethereum_keeper_contracts.go index e4279c8bceb..afb6550bd2c 100644 --- a/integration-tests/contracts/ethereum_keeper_contracts.go +++ b/integration-tests/contracts/ethereum_keeper_contracts.go @@ -15,7 +15,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/rs/zerolog/log" + "github.com/rs/zerolog" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" goabi "github.com/umbracle/ethgo/abi" @@ -76,6 +76,7 @@ type KeeperRegistry interface { PauseUpkeep(id *big.Int) error UnpauseUpkeep(id *big.Int) error UpdateCheckData(id *big.Int, newCheckData []byte) error + SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) error } type KeeperConsumer interface { @@ -203,6 +204,7 @@ type EthereumKeeperRegistry struct { registry2_0 *keeper_registry_wrapper2_0.KeeperRegistry registry2_1 *i_keeper_registry_master_wrapper_2_1.IKeeperRegistryMaster address *common.Address + l zerolog.Logger } func (v *EthereumKeeperRegistry) Address() string { @@ -776,7 +778,7 @@ func (v *EthereumKeeperRegistry) CancelUpkeep(id *big.Int) error { } } - log.Info(). + v.l.Info(). Str("Upkeep ID", strconv.FormatInt(id.Int64(), 10)). Str("From", v.client.GetDefaultWallet().Address()). Str("TX Hash", tx.Hash().String()). @@ -903,6 +905,26 @@ func (v *EthereumKeeperRegistry) UpdateCheckData(id *big.Int, newCheckData []byt } } +// SetUpkeepTriggerConfig updates the trigger config of an upkeep (only for version 2.1) +func (v *EthereumKeeperRegistry) SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) error { + + switch v.version { + case ethereum.RegistryVersion_2_1: + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + + tx, err := v.registry2_1.SetUpkeepTriggerConfig(opts, id, triggerConfig) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) + default: + return fmt.Errorf("SetUpkeepTriggerConfig is not supported by keeper registry version %d", v.version) + } +} + // PauseUpkeep stops an upkeep from an upkeep func (v *EthereumKeeperRegistry) PauseUpkeep(id *big.Int) error { switch v.version { @@ -1111,6 +1133,7 @@ type KeeperConsumerRoundConfirmer struct { doneChan chan struct{} context context.Context cancel context.CancelFunc + l zerolog.Logger } // NewKeeperConsumerRoundConfirmer provides a new instance of a KeeperConsumerRoundConfirmer @@ -1118,6 +1141,7 @@ func NewKeeperConsumerRoundConfirmer( contract KeeperConsumer, counterValue int, timeout time.Duration, + logger zerolog.Logger, ) *KeeperConsumerRoundConfirmer { ctx, ctxCancel := context.WithTimeout(context.Background(), timeout) return &KeeperConsumerRoundConfirmer{ @@ -1126,6 +1150,7 @@ func NewKeeperConsumerRoundConfirmer( doneChan: make(chan struct{}), context: ctx, cancel: ctxCancel, + l: logger, } } @@ -1135,7 +1160,7 @@ func (o *KeeperConsumerRoundConfirmer) ReceiveHeader(_ blockchain.NodeHeader) er if err != nil { return err } - l := log.Info(). + l := o.l.Info(). Str("Contract Address", o.instance.Address()). Int64("Upkeeps", upkeeps.Int64()). Int("Required upkeeps", o.upkeepsValue) @@ -1179,6 +1204,7 @@ type KeeperConsumerPerformanceRoundConfirmer struct { metricsReporter *testreporters.KeeperBlockTimeTestReporter // Testreporter to track results complete bool + l zerolog.Logger } // NewKeeperConsumerPerformanceRoundConfirmer provides a new instance of a KeeperConsumerPerformanceRoundConfirmer @@ -1188,6 +1214,7 @@ func NewKeeperConsumerPerformanceRoundConfirmer( expectedBlockCadence int64, // Expected to upkeep every 5/10/20 blocks, for example blockRange int64, metricsReporter *testreporters.KeeperBlockTimeTestReporter, + logger zerolog.Logger, ) *KeeperConsumerPerformanceRoundConfirmer { ctx, cancelFunc := context.WithCancel(context.Background()) return &KeeperConsumerPerformanceRoundConfirmer{ @@ -1205,6 +1232,7 @@ func NewKeeperConsumerPerformanceRoundConfirmer( metricsReporter: metricsReporter, complete: false, lastBlockNum: 0, + l: logger, } } @@ -1227,22 +1255,22 @@ func (o *KeeperConsumerPerformanceRoundConfirmer) ReceiveHeader(receivedHeader b return err } if isEligible { - log.Trace(). + o.l.Trace(). Str("Contract Address", o.instance.Address()). Int64("Upkeeps Performed", upkeepCount.Int64()). Msg("Upkeep Now Eligible") } if upkeepCount.Int64() >= o.expectedUpkeepCount { // Upkeep was successful if o.blocksSinceSuccessfulUpkeep < o.blockCadence { // If there's an early upkeep, that's weird - log.Error(). + o.l.Error(). Str("Contract Address", o.instance.Address()). Int64("Upkeeps Performed", upkeepCount.Int64()). Int64("Expected Cadence", o.blockCadence). Int64("Actual Cadence", o.blocksSinceSuccessfulUpkeep). - Err(errors.New("Found an early Upkeep")) - return fmt.Errorf("Found an early Upkeep on contract %s", o.instance.Address()) + Err(errors.New("found an early Upkeep")) + return fmt.Errorf("found an early Upkeep on contract %s", o.instance.Address()) } else if o.blocksSinceSuccessfulUpkeep == o.blockCadence { // Perfectly timed upkeep - log.Info(). + o.l.Info(). Str("Contract Address", o.instance.Address()). Int64("Upkeeps Performed", upkeepCount.Int64()). Int64("Expected Cadence", o.blockCadence). @@ -1250,7 +1278,7 @@ func (o *KeeperConsumerPerformanceRoundConfirmer) ReceiveHeader(receivedHeader b Msg("Successful Upkeep on Expected Cadence") o.totalSuccessfulUpkeeps++ } else { // Late upkeep - log.Warn(). + o.l.Warn(). Str("Contract Address", o.instance.Address()). Int64("Upkeeps Performed", upkeepCount.Int64()). Int64("Expected Cadence", o.blockCadence). @@ -1265,7 +1293,7 @@ func (o *KeeperConsumerPerformanceRoundConfirmer) ReceiveHeader(receivedHeader b if o.blocksSinceSubscription > o.blockRange { if o.blocksSinceSuccessfulUpkeep > o.blockCadence { - log.Warn(). + o.l.Warn(). Str("Contract Address", o.instance.Address()). Int64("Upkeeps Performed", upkeepCount.Int64()). Int64("Expected Cadence", o.blockCadence). @@ -1275,7 +1303,7 @@ func (o *KeeperConsumerPerformanceRoundConfirmer) ReceiveHeader(receivedHeader b Msg("Finished Watching for Upkeeps While Waiting on a Late Upkeep") o.allMissedUpkeeps = append(o.allMissedUpkeeps, o.blocksSinceSuccessfulUpkeep-o.blockCadence) } else { - log.Info(). + o.l.Info(). Str("Contract Address", o.instance.Address()). Int64("Upkeeps Performed", upkeepCount.Int64()). Int64("Total Blocks Watched", o.blocksSinceSubscription). @@ -1344,6 +1372,7 @@ type KeeperConsumerBenchmarkRoundConfirmer struct { upkeepCount int64 // The count of upkeeps done so far allCheckDelays []int64 // Tracks the amount of blocks missed before an upkeep since it became eligible complete bool + l zerolog.Logger } // NewKeeperConsumerBenchmarkRoundConfirmer provides a new instance of a KeeperConsumerBenchmarkRoundConfirmer @@ -1357,6 +1386,7 @@ func NewKeeperConsumerBenchmarkRoundConfirmer( metricsReporter *testreporters.KeeperBenchmarkTestReporter, upkeepIndex int64, firstEligibleuffer int64, + logger zerolog.Logger, ) *KeeperConsumerBenchmarkRoundConfirmer { ctx, cancelFunc := context.WithCancel(context.Background()) return &KeeperConsumerBenchmarkRoundConfirmer{ @@ -1378,6 +1408,7 @@ func NewKeeperConsumerBenchmarkRoundConfirmer( upkeepIndex: upkeepIndex, firstBlockNum: 0, firstEligibleuffer: firstEligibleuffer, + l: logger, } } @@ -1402,7 +1433,7 @@ func (o *KeeperConsumerBenchmarkRoundConfirmer) ReceiveHeader(receivedHeader blo if upkeepCount.Int64() != o.upkeepCount+1 { return errors.New("upkeep count increased by more than 1 in a single block") } - log.Info(). + o.l.Info(). Uint64("Block_Number", receivedHeader.Number.Uint64()). Str("Upkeep_ID", o.upkeepID.String()). Str("Contract_Address", o.instance.Address()). @@ -1412,7 +1443,7 @@ func (o *KeeperConsumerBenchmarkRoundConfirmer) ReceiveHeader(receivedHeader blo Msg("Upkeep Performed") if o.blocksSinceEligible > o.upkeepSLA { - log.Warn(). + o.l.Warn(). Uint64("Block_Number", receivedHeader.Number.Uint64()). Str("Upkeep_ID", o.upkeepID.String()). Str("Contract_Address", o.instance.Address()). @@ -1435,7 +1466,7 @@ func (o *KeeperConsumerBenchmarkRoundConfirmer) ReceiveHeader(receivedHeader blo if o.blocksSinceEligible == 0 { // First time this upkeep became eligible o.countEligible++ - log.Info(). + o.l.Info(). Uint64("Block_Number", receivedHeader.Number.Uint64()). Str("Upkeep_ID", o.upkeepID.String()). Str("Contract_Address", o.instance.Address()). @@ -1448,7 +1479,7 @@ func (o *KeeperConsumerBenchmarkRoundConfirmer) ReceiveHeader(receivedHeader blo if o.blocksSinceSubscription >= o.blockRange || int64(o.lastBlockNum-o.firstBlockNum) >= o.blockRange { if o.blocksSinceEligible > 0 { if o.blocksSinceEligible > o.upkeepSLA { - log.Warn(). + o.l.Warn(). Uint64("Block_Number", receivedHeader.Number.Uint64()). Str("Upkeep_ID", o.upkeepID.String()). Str("Contract_Address", o.instance.Address()). @@ -1457,7 +1488,7 @@ func (o *KeeperConsumerBenchmarkRoundConfirmer) ReceiveHeader(receivedHeader blo Msg("Upkeep remained eligible at end of test and missed SLA") o.countMissed++ } else { - log.Info(). + o.l.Info(). Uint64("Block_Number", receivedHeader.Number.Uint64()). Str("Upkeep_ID", o.upkeepID.String()). Str("Contract_Address", o.instance.Address()). @@ -1469,7 +1500,7 @@ func (o *KeeperConsumerBenchmarkRoundConfirmer) ReceiveHeader(receivedHeader blo o.allCheckDelays = append(o.allCheckDelays, o.blocksSinceEligible) } - log.Info(). + o.l.Info(). Uint64("Block_Number", receivedHeader.Number.Uint64()). Str("Upkeep_ID", o.upkeepID.String()). Str("Contract_Address", o.instance.Address()). diff --git a/integration-tests/docker/docker.go b/integration-tests/docker/docker.go deleted file mode 100644 index d5803e0a163..00000000000 --- a/integration-tests/docker/docker.go +++ /dev/null @@ -1,30 +0,0 @@ -package docker - -import ( - "context" - "fmt" - - "github.com/google/uuid" - "github.com/rs/zerolog/log" - tc "github.com/testcontainers/testcontainers-go" -) - -func CreateNetwork() (*tc.DockerNetwork, error) { - uuidObj, _ := uuid.NewRandom() - var networkName = fmt.Sprintf("network-%s", uuidObj.String()) - network, err := tc.GenericNetwork(context.Background(), tc.GenericNetworkRequest{ - NetworkRequest: tc.NetworkRequest{ - Name: networkName, - CheckDuplicate: true, - }, - }) - if err != nil { - return nil, err - } - dockerNetwork, ok := network.(*tc.DockerNetwork) - if !ok { - return nil, fmt.Errorf("failed to cast network to *dockertest.Network") - } - log.Trace().Any("network", dockerNetwork).Msgf("created network") - return dockerNetwork, nil -} diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index 4c2213b03ee..e4182ca4c36 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -10,6 +10,7 @@ import ( "os" "strings" "sync" + "testing" "time" "github.com/ethereum/go-ethereum" @@ -17,12 +18,15 @@ import ( "github.com/google/uuid" "github.com/pelletier/go-toml/v2" "github.com/pkg/errors" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" tc "github.com/testcontainers/testcontainers-go" tcwait "github.com/testcontainers/testcontainers-go/wait" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/docker" "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/logwatch" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" @@ -48,6 +52,8 @@ type ClNode struct { lw *logwatch.LogWatch ContainerImage string ContainerVersion string + t *testing.T + l zerolog.Logger } type ClNodeOption = func(c *ClNode) @@ -87,6 +93,7 @@ func NewClNode(networks []string, nodeConfig *chainlink.Config, opts ...ClNodeOp }, NodeConfig: nodeConfig, PostgresDb: pgDb, + l: log.Logger, } for _, opt := range opts { opt(n) @@ -94,6 +101,13 @@ func NewClNode(networks []string, nodeConfig *chainlink.Config, opts ...ClNodeOp return n } +func (n *ClNode) WithTestLogger(t *testing.T) *ClNode { + n.l = logging.GetTestLogger(t) + n.t = t + n.PostgresDb.WithTestLogger(t) + return n +} + // Restart restarts only CL node, DB container is reused func (n *ClNode) Restart(cfg *chainlink.Config) error { if err := n.Container.Terminate(context.Background()); err != nil { @@ -151,8 +165,8 @@ func (n *ClNode) AddMercuryOCRJob(verifierAddr common.Address, fromBlock uint64, } bridges := utils.BuildBridges(eaUrls) - for _, b := range bridges { - err = n.API.MustCreateBridge(&b) + for index := range bridges { + err = n.API.MustCreateBridge(&bridges[index]) if err != nil { return nil, err } @@ -237,10 +251,19 @@ func (n *ClNode) StartContainer() error { if err != nil { return err } - container, err := tc.GenericContainer(context.Background(), tc.GenericContainerRequest{ + + l := tc.Logger + if n.t != nil { + l = logging.CustomT{ + T: n.t, + L: n.l, + } + } + container, err := docker.StartContainerWithRetry(n.l, tc.GenericContainerRequest{ ContainerRequest: *cReq, Started: true, Reuse: true, + Logger: l, }) if err != nil { return errors.Wrap(err, ErrStartCLNodeContainer) @@ -258,7 +281,7 @@ func (n *ClNode) StartContainer() error { if err != nil { return err } - log.Info().Str("containerName", n.ContainerName). + n.l.Info().Str("containerName", n.ContainerName). Str("clEndpoint", clEndpoint). Str("clInternalIP", ip). Msg("Started Chainlink Node container") @@ -267,11 +290,11 @@ func (n *ClNode) StartContainer() error { Email: "local@local.com", Password: "localdevpassword", InternalIP: ip, - }) + }, + n.l) if err != nil { return errors.Wrap(err, ErrConnectNodeClient) } - clClient.Config.InternalIP = n.ContainerName n.Container = container n.API = clClient diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index e90bf5618ab..8c4faadbd2b 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -1,24 +1,33 @@ package test_env import ( + "context" "encoding/json" + "fmt" + "io" "math/big" + "os" + "path/filepath" + "testing" + "time" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" tc "github.com/testcontainers/testcontainers-go" "golang.org/x/sync/errgroup" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/docker" "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/logwatch" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/docker" "github.com/smartcontractkit/chainlink/integration-tests/utils" ) @@ -34,17 +43,19 @@ type CLClusterTestEnv struct { /* components */ CLNodes []*ClNode - Geth *test_env.Geth // for tests using --dev networks - PrivateGethChain []test_env.PrivateGethChain // for tests using non-dev networks + Geth *test_env.Geth // for tests using --dev networks + PrivateChain []test_env.PrivateChain // for tests using non-dev networks MockServer *test_env.MockServer EVMClient blockchain.EVMClient ContractDeployer contracts.ContractDeployer ContractLoader contracts.ContractLoader + l zerolog.Logger + t *testing.T } func NewTestEnv() (*CLClusterTestEnv, error) { utils.SetupCoreDockerEnvLogger() - network, err := docker.CreateNetwork() + network, err := docker.CreateNetwork(log.Logger) if err != nil { return nil, err } @@ -53,22 +64,32 @@ func NewTestEnv() (*CLClusterTestEnv, error) { Network: network, Geth: test_env.NewGeth(networks), MockServer: test_env.NewMockServer(networks), + l: log.Logger, }, nil } -func NewTestEnvFromCfg(cfg *TestEnvConfig) (*CLClusterTestEnv, error) { +func (te *CLClusterTestEnv) WithTestLogger(t *testing.T) *CLClusterTestEnv { + te.t = t + te.l = logging.GetTestLogger(t) + te.Geth.WithTestLogger(t) + te.MockServer.WithTestLogger(t) + return te +} + +func NewTestEnvFromCfg(l zerolog.Logger, cfg *TestEnvConfig) (*CLClusterTestEnv, error) { utils.SetupCoreDockerEnvLogger() - network, err := docker.CreateNetwork() + network, err := docker.CreateNetwork(log.Logger) if err != nil { return nil, err } networks := []string{network.Name} - log.Info().Interface("Cfg", cfg).Send() + l.Info().Interface("Cfg", cfg).Send() return &CLClusterTestEnv{ Cfg: cfg, Network: network, Geth: test_env.NewGeth(networks, test_env.WithContainerName(cfg.Geth.ContainerName)), MockServer: test_env.NewMockServer(networks, test_env.WithContainerName(cfg.MockServer.ContainerName)), + l: log.Logger, }, nil } @@ -76,23 +97,39 @@ func (te *CLClusterTestEnv) ParallelTransactions(enabled bool) { te.EVMClient.ParallelTransactions(enabled) } -func (te *CLClusterTestEnv) WithPrivateGethChain(evmNetworks []blockchain.EVMNetwork) *CLClusterTestEnv { - var chains []test_env.PrivateGethChain +func (te *CLClusterTestEnv) WithPrivateChain(evmNetworks []blockchain.EVMNetwork) *CLClusterTestEnv { + var chains []test_env.PrivateChain for _, evmNetwork := range evmNetworks { n := evmNetwork - chains = append(chains, test_env.NewPrivateGethChain(&n, []string{te.Network.Name})) + pgc := test_env.NewPrivateGethChain(&n, []string{te.Network.Name}) + if te.t != nil { + pgc.GetPrimaryNode().WithTestLogger(te.t) + } + chains = append(chains, pgc) + var privateChain test_env.PrivateChain + switch n.SimulationType { + case "besu": + privateChain = test_env.NewPrivateBesuChain(&n, []string{te.Network.Name}) + default: + privateChain = test_env.NewPrivateGethChain(&n, []string{te.Network.Name}) + } + chains = append(chains, privateChain) } - te.PrivateGethChain = chains + te.PrivateChain = chains return te } -func (te *CLClusterTestEnv) StartPrivateGethChain() error { - for _, chain := range te.PrivateGethChain { - err := chain.PrimaryNode.Start() +func (te *CLClusterTestEnv) StartPrivateChain() error { + for _, chain := range te.PrivateChain { + primaryNode := chain.GetPrimaryNode() + if primaryNode == nil { + return errors.WithStack(fmt.Errorf("Primary node is nil in PrivateChain interface")) + } + err := primaryNode.Start() if err != nil { return err } - err = chain.PrimaryNode.ConnectToClient() + err = primaryNode.ConnectToClient() if err != nil { return err } @@ -134,6 +171,9 @@ func (te *CLClusterTestEnv) StartClNodes(nodeConfig *chainlink.Config, count int WithNodeContainerName(nodeContainerName), WithDbContainerName(dbContainerName), ) + if te.t != nil { + n.WithTestLogger(te.t) + } err := n.StartContainer() if err != nil { return err @@ -198,40 +238,83 @@ func (te *CLClusterTestEnv) Terminate() error { // Cleanup cleans the environment up after it's done being used, mainly for returning funds when on live networks. // Intended to be used as part of t.Cleanup() in tests. -func (te *CLClusterTestEnv) Cleanup() error { - log.Info().Msg("Attempting to return Chainlink node funds to default network wallets") +func (te *CLClusterTestEnv) Cleanup(t *testing.T) error { if te.EVMClient == nil { return errors.New("blockchain client is nil, unable to return funds from chainlink nodes") } if te.CLNodes == nil { return errors.New("chainlink nodes are nil, unable to return funds from chainlink nodes") } + + // Check if we need to return funds if te.EVMClient.NetworkSimulated() { - log.Info().Str("Network Name", te.EVMClient.GetNetworkName()). + te.l.Info().Str("Network Name", te.EVMClient.GetNetworkName()). Msg("Network is a simulated network. Skipping fund return.") + } else { + te.l.Info().Msg("Attempting to return Chainlink node funds to default network wallets") + for _, chainlinkNode := range te.CLNodes { + fundedKeys, err := chainlinkNode.API.ExportEVMKeysForChain(te.EVMClient.GetChainID().String()) + if err != nil { + return err + } + for _, key := range fundedKeys { + keyToDecrypt, err := json.Marshal(key) + if err != nil { + return err + } + // This can take up a good bit of RAM and time. When running on the remote-test-runner, this can lead to OOM + // issues. So we avoid running in parallel; slower, but safer. + decryptedKey, err := keystore.DecryptKey(keyToDecrypt, client.ChainlinkKeyPassword) + if err != nil { + return err + } + if err = te.EVMClient.ReturnFunds(decryptedKey.PrivateKey); err != nil { + return err + } + } + } + } + + // TODO: This is an imperfect and temporary solution, see TT-590 for a more sustainable solution + // Collect logs if the test failed + if !t.Failed() { return nil } - for _, chainlinkNode := range te.CLNodes { - fundedKeys, err := chainlinkNode.API.ExportEVMKeysForChain(te.EVMClient.GetChainID().String()) - if err != nil { - return err - } - for _, key := range fundedKeys { - keyToDecrypt, err := json.Marshal(key) + folder := fmt.Sprintf("./logs/%s-%s", t.Name(), time.Now().Format("2006-01-02T15-04-05")) + if err := os.MkdirAll(folder, os.ModePerm); err != nil { + return err + } + + te.l.Warn().Msg("Test failed, collecting logs") + eg := &errgroup.Group{} + for _, n := range te.CLNodes { + node := n + eg.Go(func() error { + logFileName := filepath.Join(folder, fmt.Sprintf("node-%s.log", node.ContainerName)) + logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY, 0644) if err != nil { return err } - // This can take up a good bit of RAM and time. When running on the remote-test-runner, this can lead to OOM - // issues. So we avoid running in parallel; slower, but safer. - decryptedKey, err := keystore.DecryptKey(keyToDecrypt, client.ChainlinkKeyPassword) + defer logFile.Close() + logReader, err := node.Container.Logs(context.Background()) if err != nil { return err } - if err = te.EVMClient.ReturnFunds(decryptedKey.PrivateKey); err != nil { + _, err = io.Copy(logFile, logReader) + if err != nil { return err } - } + te.l.Info().Str("Node", node.ContainerName).Str("File", logFileName).Msg("Wrote Logs") + return nil + }) + } + + if err := eg.Wait(); err != nil { + return err } + + te.l.Info().Str("Logs Location", folder).Msg("Wrote Logs for Failed Test") + return nil } diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index 27f98b36139..f3944b0ba96 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -1,19 +1,23 @@ package test_env import ( + "fmt" "math/big" "os" + "testing" "github.com/pkg/errors" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/logwatch" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" ) @@ -28,6 +32,8 @@ type CLTestEnvBuilder struct { externalAdapterCount int customNodeCsaKeys []string defaultNodeCsaKeys []string + l zerolog.Logger + t *testing.T /* funding */ ETHFunds *big.Float @@ -36,9 +42,16 @@ type CLTestEnvBuilder struct { func NewCLTestEnvBuilder() *CLTestEnvBuilder { return &CLTestEnvBuilder{ externalAdapterCount: 1, + l: log.Logger, } } +func (b *CLTestEnvBuilder) WithTestLogger(t *testing.T) *CLTestEnvBuilder { + b.t = t + b.l = logging.GetTestLogger(t) + return b +} + func (b *CLTestEnvBuilder) WithLogWatcher() *CLTestEnvBuilder { b.hasLogWatch = true return b @@ -94,7 +107,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } func (b *CLTestEnvBuilder) buildNewEnv(cfg *TestEnvConfig) (*CLClusterTestEnv, error) { - log.Info(). + b.l.Info(). Bool("hasGeth", b.hasGeth). Bool("hasMockServer", b.hasMockServer). Int("externalAdapterCount", b.externalAdapterCount). @@ -106,7 +119,7 @@ func (b *CLTestEnvBuilder) buildNewEnv(cfg *TestEnvConfig) (*CLClusterTestEnv, e var te *CLClusterTestEnv var err error if cfg != nil { - te, err = NewTestEnvFromCfg(cfg) + te, err = NewTestEnvFromCfg(b.l, cfg) if err != nil { return nil, err } @@ -117,6 +130,10 @@ func (b *CLTestEnvBuilder) buildNewEnv(cfg *TestEnvConfig) (*CLClusterTestEnv, e } } + if b.t != nil { + te.WithTestLogger(b.t) + } + if b.hasLogWatch { te.LogWatch, err = logwatch.NewLogWatch(nil, nil) if err != nil { @@ -135,19 +152,23 @@ func (b *CLTestEnvBuilder) buildNewEnv(cfg *TestEnvConfig) (*CLClusterTestEnv, e } } if b.nonDevGethNetworks != nil { - te.WithPrivateGethChain(b.nonDevGethNetworks) - err := te.StartPrivateGethChain() + te.WithPrivateChain(b.nonDevGethNetworks) + err := te.StartPrivateChain() if err != nil { return te, err } - var nonDevGethNetworks []blockchain.EVMNetwork - for i, n := range te.PrivateGethChain { - nonDevGethNetworks = append(nonDevGethNetworks, *n.NetworkConfig) - nonDevGethNetworks[i].URLs = []string{n.PrimaryNode.InternalWsUrl} - nonDevGethNetworks[i].HTTPURLs = []string{n.PrimaryNode.InternalHttpUrl} + var nonDevNetworks []blockchain.EVMNetwork + for i, n := range te.PrivateChain { + primaryNode := n.GetPrimaryNode() + if primaryNode == nil { + return te, errors.WithStack(fmt.Errorf("Primary node is nil in PrivateChain interface")) + } + nonDevNetworks = append(nonDevNetworks, *n.GetNetworkConfig()) + nonDevNetworks[i].URLs = []string{primaryNode.GetInternalWsUrl()} + nonDevNetworks[i].HTTPURLs = []string{primaryNode.GetInternalHttpUrl()} } - if nonDevGethNetworks == nil { - return nil, errors.New("cannot create nodes with custom config without nonDevGethNetworks") + if nonDevNetworks == nil { + return nil, errors.New("cannot create nodes with custom config without nonDevNetworks") } err = te.StartClNodes(b.clNodeConfig, b.clNodesCount) @@ -166,20 +187,20 @@ func (b *CLTestEnvBuilder) buildNewEnv(cfg *TestEnvConfig) (*CLClusterTestEnv, e } - bc, err := blockchain.NewEVMClientFromNetwork(networkConfig) + bc, err := blockchain.NewEVMClientFromNetwork(networkConfig, b.l) if err != nil { return nil, err } te.EVMClient = bc - cd, err := contracts.NewContractDeployer(bc) + cd, err := contracts.NewContractDeployer(bc, b.l) if err != nil { return nil, err } te.ContractDeployer = cd - cl, err := contracts.NewContractLoader(bc) + cl, err := contracts.NewContractLoader(bc, b.l) if err != nil { return nil, err } @@ -193,7 +214,7 @@ func (b *CLTestEnvBuilder) buildNewEnv(cfg *TestEnvConfig) (*CLClusterTestEnv, e if b.clNodeConfig != nil { cfg = b.clNodeConfig } else { - cfg = node.NewConfig(node.BaseConf, + cfg = node.NewConfig(node.NewBaseConfig(), node.WithOCR1(), node.WithP2Pv1(), ) diff --git a/integration-tests/example.env b/integration-tests/example.env index 8570fa86e1e..428f76b914e 100644 --- a/integration-tests/example.env +++ b/integration-tests/example.env @@ -4,7 +4,7 @@ ########## General Test Settings ########## export KEEP_ENVIRONMENTS="Never" # Always | OnFail | Never export CHAINLINK_IMAGE="public.ecr.aws/chainlink/chainlink" # Image repo to pull the Chainlink image from -export CHAINLINK_VERSION="1.13.0" # Version of the Chainlink image to pull +export CHAINLINK_VERSION="2.4.0" # Version of the Chainlink image to pull export CHAINLINK_ENV_USER="Satoshi-Nakamoto" # Name of the person running the tests (change to your own) export TEST_LOG_LEVEL="info" # info | debug | trace diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 1b1b3940ccf..9edf6d72be5 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -20,12 +20,12 @@ require ( github.com/rs/zerolog v1.30.0 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-env v0.36.0 - github.com/smartcontractkit/chainlink-testing-framework v1.16.3-0.20230901233155-c2c6e9c075c2 + github.com/smartcontractkit/chainlink-testing-framework v1.17.0 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 - github.com/smartcontractkit/ocr2keepers v0.7.21 + github.com/smartcontractkit/ocr2keepers v0.7.23 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 - github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e + github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wasp v0.3.0 github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.8.4 @@ -231,7 +231,7 @@ require ( github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce // indirect github.com/hdevalence/ed25519consensus v0.1.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect - github.com/holiman/uint256 v1.2.2 // indirect + github.com/holiman/uint256 v1.2.3 // indirect github.com/huandu/skiplist v1.2.0 // indirect github.com/huin/goupnp v1.0.3 // indirect github.com/imdario/mergo v0.3.16 // indirect @@ -383,12 +383,12 @@ require ( github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230912195355-fec1da7953fc // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 // indirect github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb // indirect - github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e // indirect + github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 2e77b16fe09..55686ce2ef4 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1395,8 +1395,8 @@ github.com/henvic/httpretty v0.0.6 h1:JdzGzKZBajBfnvlMALXXMVQWxWMF/ofTy8C3/OSUTx github.com/hetznercloud/hcloud-go v1.41.0 h1:KJGFRRc68QiVu4PrEP5BmCQVveCP2CM26UGQUKGpIUs= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.2.2 h1:TXKcSGc2WaxPD2+bmzAsVthL4+pEN0YwXcL5qED83vk= -github.com/holiman/uint256 v1.2.2/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= +github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= +github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= @@ -2248,34 +2248,34 @@ github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512 h1:DojChlaudA1HAxwQPKmt/EDf36OUeFJ0LJBYClauMyU= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= github.com/smartcontractkit/chainlink-env v0.36.0 h1:CFOjs0c0y3lrHi/fl5qseCH9EQa5W/6CFyOvmhe2VnA= github.com/smartcontractkit/chainlink-env v0.36.0/go.mod h1:NbRExHmJGnKSYXmvNuJx5VErSx26GtE1AEN/CRzYOg8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4 h1:yArUq/0t126bl8BRtjLCf2NuHK35CDIkhc3M5P46apc= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230912195355-fec1da7953fc h1:mQCCjnDz2I1XlYv/fDyFnEB8ryAchlpz12Eg0f7n/N0= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230912195355-fec1da7953fc/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca h1:x7M0m512gtXw5Z4B1WJPZ52VgshoIv+IvHqQ8hsH4AE= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 h1:ByVauKFXphRlSNG47lNuxZ9aicu+r8AoNp933VRPpCw= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918/go.mod h1:/yp/sqD8Iz5GU5fcercjrw0ivJF7HDcupYg+Gjr7EPg= -github.com/smartcontractkit/chainlink-testing-framework v1.16.3-0.20230901233155-c2c6e9c075c2 h1:llbIpJD17IXj0TPwE1r/bgB3X7Gkk9LKsxsXkTBmGe0= -github.com/smartcontractkit/chainlink-testing-framework v1.16.3-0.20230901233155-c2c6e9c075c2/go.mod h1:xtLIwNaVw/4zWSMnA7j8u1t9tKh0OykvIsYI4xZT3B4= +github.com/smartcontractkit/chainlink-testing-framework v1.17.0 h1:JcJwfawW7jfLBG+By5hGTVcNgKQ7bJCqvN9TEF3qBis= +github.com/smartcontractkit/chainlink-testing-framework v1.17.0/go.mod h1:Ry6fRPr8TwrIsYVNEF1pguAgzE3QW1s54tbLWnFtfI4= github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472 h1:x3kNwgFlDmbE/n0gTSRMt9GBDfsfGrs4X9b9arPZtFI= github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0= 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-20230816220705-665e93233ae5 h1:rzbqGoScs9VHGnyCKF7AoQEuUfwJnzcKmGIfaczeanA= github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.21 h1:64CNFoUYVpoJqhQ39WTPIEKVKB5Z/wderX0pIsv/tbA= -github.com/smartcontractkit/ocr2keepers v0.7.21/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= +github.com/smartcontractkit/ocr2keepers v0.7.23 h1:hvMCHm9zTOKGELc40n+JLGmbiW1tkFnHW17qAtoVews= +github.com/smartcontractkit/ocr2keepers v0.7.23/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb/go.mod h1:HNUu4cJekUdsJbwRBCiOybtkPJEfGRELQPe2tkoDEyk= -github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e h1:faa7bAs8xCVsnJoNmAtV18la0wqBoaWSWFqNdjkPdAw= -github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= -github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e h1:JMCSFOQIYOh7zUYi9C3UQG9Lz5ECNejTURBN+Khhwz4= -github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= +github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= +github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= +github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= +github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= github.com/smartcontractkit/wasp v0.3.0 h1:mueeLvpb6HyGNwILxCOKShDR6q18plQn7Gb1j3G/Qkk= github.com/smartcontractkit/wasp v0.3.0/go.mod h1:skquNdMbKxIrHi5O8Kyukf66AaaXuEpEEaSTxfHbhak= github.com/smartcontractkit/wsrpc v0.7.2 h1:iBXzMeg7vc5YoezIQBq896y25BARw7OKbhrb6vPbtRQ= diff --git a/integration-tests/load/functions/README.md b/integration-tests/load/functions/README.md index 6b80137cf48..d9eb9cc1ef3 100644 --- a/integration-tests/load/functions/README.md +++ b/integration-tests/load/functions/README.md @@ -13,21 +13,37 @@ See more config options in [config.toml](./config.toml) ## Usage -Soak `1 TX/sec - 40 requests per TX` -``` -go test -v -run TestFunctionsLoad/functions_soak_test -``` -Stress `1 TX/sec - 78 requests per TX` (max gas) -``` -go test -v -run TestFunctionsLoad/functions_stress_test -``` -Gateway `secrets_list` test +All tests are split by network and in 3 groups: +- HTTP payload only +- Secrets decoding payload only +- Realistic payload with args/http/secrets + +Load test client is [here](../../../contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsLoadTestClient.sol) + +Load is controlled with 2 params: +- RPS +- requests_per_call (generating more events in a loop in the contract) + +`Soak` is a stable workload for which there **must** be no issues + +`Stress` is a peak workload for which issues **must** be analyzed + +Load test client can execute `78 calls per request` at max (gas limit) + +Functions tests: ``` -go test -v -timeout 24h -run TestGatewayLoad/gateway_secrets_list_soak_test +go test -v -run TestFunctionsLoad/mumbai_functions_soak_test_http +go test -v -run TestFunctionsLoad/mumbai_functions_stress_test_http +go test -v -run TestFunctionsLoad/mumbai_functions_soak_test_only_secrets +go test -v -run TestFunctionsLoad/mumbai_functions_stress_test_only_secrets +go test -v -run TestFunctionsLoad/mumbai_functions_soak_test_real +go test -v -run TestFunctionsLoad/mumbai_functions_stress_test_real ``` -Gateway `secrets_set` test + +Gateway tests: ``` -go test -v -timeout 24h -run TestGatewayLoad/gateway_secrets_set_soak_test +go test -v -run TestGatewayLoad/gateway_secrets_list_soak_test +go test -v -run TestGatewayLoad/gateway_secrets_set_soak_test ``` Chaos suite can be combined with any test, can be found [here](../../chaos/functions/full.yaml) diff --git a/integration-tests/load/functions/config.go b/integration-tests/load/functions/config.go index b18549f460b..5c622401aba 100644 --- a/integration-tests/load/functions/config.go +++ b/integration-tests/load/functions/config.go @@ -18,7 +18,11 @@ const ( type PerformanceConfig struct { Soak *Soak `toml:"Soak"` + SecretsSoak *SecretsSoak `toml:"SecretsSoak"` + RealSoak *RealSoak `toml:"RealSoak"` Stress *Stress `toml:"Stress"` + SecretsStress *SecretsStress `toml:"SecretsStress"` + RealStress *RealStress `toml:"RealStress"` GatewayListSoak *GatewayListSoak `toml:"GatewayListSoak"` GatewaySetSoak *GatewaySetSoak `toml:"GatewaySetSoak"` Common *Common `toml:"Common"` @@ -27,18 +31,21 @@ type PerformanceConfig struct { type Common struct { Funding - LINKTokenAddr string `toml:"link_token_addr"` - Coordinator string `toml:"coordinator_addr"` - Router string `toml:"router_addr"` - LoadTestClient string `toml:"client_addr"` - SubscriptionID uint64 `toml:"subscription_id"` - DONID string `toml:"don_id"` - GatewayURL string `toml:"gateway_url"` - Receiver string `toml:"receiver"` - FunctionsCallPayload string `toml:"functions_call_payload"` - Secrets string `toml:"secrets"` - SecretsSlotID uint8 `toml:"secrets_slot_id"` - SecretsVersionID uint64 `toml:"secrets_version_id"` + LINKTokenAddr string `toml:"link_token_addr"` + Coordinator string `toml:"coordinator_addr"` + Router string `toml:"router_addr"` + LoadTestClient string `toml:"client_addr"` + SubscriptionID uint64 `toml:"subscription_id"` + DONID string `toml:"don_id"` + GatewayURL string `toml:"gateway_url"` + Receiver string `toml:"receiver"` + FunctionsCallPayloadHTTP string `toml:"functions_call_payload_http"` + FunctionsCallPayloadWithSecrets string `toml:"functions_call_payload_with_secrets"` + FunctionsCallPayloadReal string `toml:"functions_call_payload_real"` + SecretsSlotID uint8 `toml:"secrets_slot_id"` + SecretsVersionID uint64 `toml:"secrets_version_id"` + // Secrets these are for CI secrets + Secrets string `toml:"secrets"` } type Funding struct { @@ -52,12 +59,36 @@ type Soak struct { Duration *models.Duration `toml:"duration"` } +type SecretsSoak struct { + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *models.Duration `toml:"duration"` +} + +type RealSoak struct { + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *models.Duration `toml:"duration"` +} + type Stress struct { RPS int64 `toml:"rps"` RequestsPerCall uint32 `toml:"requests_per_call"` Duration *models.Duration `toml:"duration"` } +type SecretsStress struct { + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *models.Duration `toml:"duration"` +} + +type RealStress struct { + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *models.Duration `toml:"duration"` +} + type GatewayListSoak struct { RPS int64 `toml:"rps"` Duration *models.Duration `toml:"duration"` diff --git a/integration-tests/load/functions/config.toml b/integration-tests/load/functions/config.toml index f31342f0134..2de3ba9282c 100644 --- a/integration-tests/load/functions/config.toml +++ b/integration-tests/load/functions/config.toml @@ -8,6 +8,26 @@ rps = 1 requests_per_call = 78 duration = "10m" +[SecretsSoak] +rps = 1 +requests_per_call = 20 +duration = "10m" + +[SecretsStress] +rps = 1 +requests_per_call = 40 +duration = "10m" + +[RealSoak] +rps = 1 +requests_per_call = 20 +duration = "10m" + +[RealStress] +rps = 1 +requests_per_call = 40 +duration = "10m" + [GatewayListSoak] rps = 95 duration = "10m" @@ -20,18 +40,34 @@ duration = "10m" # Polygon Mumbai only for now receiver = "0x3098B6665589959711A48a6bAe5B7F2908f6a3bE" don_id = "fun-staging-mumbai-1" -gateway_url = "https://gateway-staging1.main.stage.cldev.sh" +gateway_url = "https://gateway-stg-one.main.stage.cldev.sh" link_token_addr = "0x326C977E6efc84E512bB9C30f76E30c160eD06FB" coordinator_addr = "0x6D6a83BB356b7242E88C1A2b290102fde26590D0" router_addr = "0x2673266D3Cd08b53494B5a92B66DEec7F1408E7A" -# comment both client and sub to automatically create a new pair + +# comment "client_addr" and "subscription_id" and test will create a new pair +# get it from logs and save client_addr = "0x89D4b58D859a536D0B888ecD5093eF5FF9e4F977" subscription_id = 47 sub_funds = 10 -#functions_call_payload = "const response = await Functions.makeHttpRequest({ url: 'http://dummyjson.com/products/1' }); return Functions.encodeUint256(response.data.id)" -functions_call_payload = "return Functions.encodeString(JSON.stringify(secrets))" +functions_call_payload_with_secrets = "return Functions.encodeString(JSON.stringify(secrets))" +functions_call_payload_http = """ +const response = await Functions.makeHttpRequest({ url: 'http://dummyjson.com/products/1' }); +return Functions.encodeUint256(response.data.id); +""" +functions_call_payload_real = """ +const arg1 = args[0]; +const arg2 = args[1]; +const arg3 = args[2]; +const arg4 = args[3]; + +const response = await Functions.makeHttpRequest({ url: 'http://dummyjson.com/products/${arg1}' }); +return Functions.encodeString(JSON.stringify(secrets)); +""" secrets_slot_id = 0 secrets_version = 1693945705 -# uncomment to upload new secrets to s4 -#secrets = "{\"ltsecret\": \"1\"}" \ No newline at end of file + +# uncomment to upload new secrets to s4 and use it in your run +# TODO: not working now +#secrets = "{\"secrets\": \"secretValue\"}" \ No newline at end of file diff --git a/integration-tests/load/functions/functions_test.go b/integration-tests/load/functions/functions_test.go index c178fcc5e21..7822035208e 100644 --- a/integration-tests/load/functions/functions_test.go +++ b/integration-tests/load/functions/functions_test.go @@ -21,7 +21,7 @@ func TestFunctionsLoad(t *testing.T) { MonitorLoadStats(t, ft, labels) - t.Run("functions soak test", func(t *testing.T) { + t.Run("mumbai functions soak test http", func(t *testing.T) { _, err := wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, @@ -35,8 +35,9 @@ func TestFunctionsLoad(t *testing.T) { ), Gun: NewSingleFunctionCallGun( ft, + ModeHTTPPayload, cfg.Soak.RequestsPerCall, - cfg.Common.FunctionsCallPayload, + cfg.Common.FunctionsCallPayloadHTTP, cfg.Common.SecretsSlotID, cfg.Common.SecretsVersionID, []string{}, @@ -50,7 +51,7 @@ func TestFunctionsLoad(t *testing.T) { require.NoError(t, err) }) - t.Run("functions stress test", func(t *testing.T) { + t.Run("mumbai functions stress test http", func(t *testing.T) { _, err = wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, @@ -64,8 +65,39 @@ func TestFunctionsLoad(t *testing.T) { ), Gun: NewSingleFunctionCallGun( ft, - cfg.Soak.RequestsPerCall, - cfg.Common.FunctionsCallPayload, + ModeHTTPPayload, + cfg.Stress.RequestsPerCall, + cfg.Common.FunctionsCallPayloadHTTP, + cfg.Common.SecretsSlotID, + cfg.Common.SecretsVersionID, + []string{}, + cfg.Common.SubscriptionID, + StringToByte32(cfg.Common.DONID), + ), + Labels: labels, + LokiConfig: wasp.NewEnvLokiConfig(), + })). + Run(true) + require.NoError(t, err) + }) + + t.Run("mumbai functions soak test only secrets", func(t *testing.T) { + _, err := wasp.NewProfile(). + Add(wasp.NewGenerator(&wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "functions_soak_gen", + RateLimitUnitDuration: 5 * time.Second, + CallTimeout: 3 * time.Minute, + Schedule: wasp.Plain( + cfg.SecretsSoak.RPS, + cfg.SecretsSoak.Duration.Duration(), + ), + Gun: NewSingleFunctionCallGun( + ft, + ModeSecretsOnlyPayload, + cfg.SecretsSoak.RequestsPerCall, + cfg.Common.FunctionsCallPayloadWithSecrets, cfg.Common.SecretsSlotID, cfg.Common.SecretsVersionID, []string{}, @@ -78,4 +110,94 @@ func TestFunctionsLoad(t *testing.T) { Run(true) require.NoError(t, err) }) + + t.Run("mumbai functions stress test only secrets", func(t *testing.T) { + _, err = wasp.NewProfile(). + Add(wasp.NewGenerator(&wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "functions_stress_gen", + RateLimitUnitDuration: 5 * time.Second, + CallTimeout: 3 * time.Minute, + Schedule: wasp.Plain( + cfg.SecretsStress.RPS, + cfg.SecretsStress.Duration.Duration(), + ), + Gun: NewSingleFunctionCallGun( + ft, + ModeSecretsOnlyPayload, + cfg.SecretsStress.RequestsPerCall, + cfg.Common.FunctionsCallPayloadWithSecrets, + cfg.Common.SecretsSlotID, + cfg.Common.SecretsVersionID, + []string{}, + cfg.Common.SubscriptionID, + StringToByte32(cfg.Common.DONID), + ), + Labels: labels, + LokiConfig: wasp.NewEnvLokiConfig(), + })). + Run(true) + require.NoError(t, err) + }) + + t.Run("mumbai functions soak test real", func(t *testing.T) { + _, err := wasp.NewProfile(). + Add(wasp.NewGenerator(&wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "functions_soak_gen", + RateLimitUnitDuration: 5 * time.Second, + CallTimeout: 3 * time.Minute, + Schedule: wasp.Plain( + cfg.RealSoak.RPS, + cfg.RealSoak.Duration.Duration(), + ), + Gun: NewSingleFunctionCallGun( + ft, + ModeReal, + cfg.RealSoak.RequestsPerCall, + cfg.Common.FunctionsCallPayloadReal, + cfg.Common.SecretsSlotID, + cfg.Common.SecretsVersionID, + []string{"1", "2", "3", "4"}, + cfg.Common.SubscriptionID, + StringToByte32(cfg.Common.DONID), + ), + Labels: labels, + LokiConfig: wasp.NewEnvLokiConfig(), + })). + Run(true) + require.NoError(t, err) + }) + + t.Run("mumbai functions stress test real", func(t *testing.T) { + _, err = wasp.NewProfile(). + Add(wasp.NewGenerator(&wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "functions_stress_gen", + RateLimitUnitDuration: 5 * time.Second, + CallTimeout: 3 * time.Minute, + Schedule: wasp.Plain( + cfg.RealStress.RPS, + cfg.RealStress.Duration.Duration(), + ), + Gun: NewSingleFunctionCallGun( + ft, + ModeReal, + cfg.RealStress.RequestsPerCall, + cfg.Common.FunctionsCallPayloadReal, + cfg.Common.SecretsSlotID, + cfg.Common.SecretsVersionID, + []string{"1", "2", "3", "4"}, + cfg.Common.SubscriptionID, + StringToByte32(cfg.Common.DONID), + ), + Labels: labels, + LokiConfig: wasp.NewEnvLokiConfig(), + })). + Run(true) + require.NoError(t, err) + }) } diff --git a/integration-tests/load/functions/gateway.go b/integration-tests/load/functions/gateway.go index 12406c79eb1..aefe4fbedc2 100644 --- a/integration-tests/load/functions/gateway.go +++ b/integration-tests/load/functions/gateway.go @@ -49,38 +49,36 @@ type RPCResponse struct { } `json:"result"` } -func UploadS4Secrets(rc *resty.Client, s4Cfg *S4SecretsCfg) error { +func UploadS4Secrets(rc *resty.Client, s4Cfg *S4SecretsCfg) (uint8, uint64, error) { key, err := crypto.HexToECDSA(s4Cfg.PrivateKey) if err != nil { - return err + return 0, 0, err } address := crypto.PubkeyToAddress(key.PublicKey) var payloadJSON []byte - if s4Cfg.Method == functions.MethodSecretsSet { - envelope := s4.Envelope{ - Address: address.Bytes(), - SlotID: s4Cfg.S4SetSlotID, - Version: s4Cfg.S4SetVersion, - Payload: []byte(s4Cfg.S4SetPayload), - Expiration: time.Now().UnixMilli() + s4Cfg.S4SetExpirationPeriod, - } - signature, err := envelope.Sign(key) - if err != nil { - return err - } + envelope := s4.Envelope{ + Address: address.Bytes(), + SlotID: s4Cfg.S4SetSlotID, + Version: s4Cfg.S4SetVersion, + Payload: []byte(s4Cfg.S4SetPayload), + Expiration: time.Now().UnixMilli() + s4Cfg.S4SetExpirationPeriod, + } + signature, err := envelope.Sign(key) + if err != nil { + return 0, 0, err + } - s4SetPayload := functions.SecretsSetRequest{ - SlotID: envelope.SlotID, - Version: envelope.Version, - Expiration: envelope.Expiration, - Payload: []byte(s4Cfg.S4SetPayload), - Signature: signature, - } + s4SetPayload := functions.SecretsSetRequest{ + SlotID: envelope.SlotID, + Version: envelope.Version, + Expiration: envelope.Expiration, + Payload: []byte(s4Cfg.S4SetPayload), + Signature: signature, + } - payloadJSON, err = json.Marshal(s4SetPayload) - if err != nil { - return err - } + payloadJSON, err = json.Marshal(s4SetPayload) + if err != nil { + return 0, 0, err } msg := &api.Message{ @@ -94,33 +92,33 @@ func UploadS4Secrets(rc *resty.Client, s4Cfg *S4SecretsCfg) error { err = msg.Sign(key) if err != nil { - return err + return 0, 0, err } codec := api.JsonRPCCodec{} rawMsg, err := codec.EncodeRequest(msg) if err != nil { - return err + return 0, 0, err } var result *RPCResponse resp, err := rc.R(). SetBody(rawMsg). Post(s4Cfg.GatewayURL) if err != nil { - return err + return 0, 0, err } if resp.StatusCode() != 200 { - return fmt.Errorf("status code was %d, expected 200", resp.StatusCode()) + return 0, 0, fmt.Errorf("status code was %d, expected 200", resp.StatusCode()) } if err := json.Unmarshal(resp.Body(), &result); err != nil { - return err + return 0, 0, err } log.Debug().Interface("Result", result).Msg("S4 secrets_set response result") for _, nodeResponse := range result.Result.Body.Payload.NodeResponses { if !nodeResponse.Body.Payload.Success { - return fmt.Errorf("node response was not succesful") + return 0, 0, fmt.Errorf("node response was not succesful") } } - return nil + return uint8(envelope.SlotID), envelope.Version, nil } func ListS4Secrets(rc *resty.Client, s4Cfg *S4SecretsCfg) error { diff --git a/integration-tests/load/functions/gateway_gun.go b/integration-tests/load/functions/gateway_gun.go index 5677e79b105..fd13922d0a7 100644 --- a/integration-tests/load/functions/gateway_gun.go +++ b/integration-tests/load/functions/gateway_gun.go @@ -36,7 +36,7 @@ func NewGatewaySecretsSetGun(cfg *PerformanceConfig, method string, pKey *ecdsa. } } -func callSetSecrets(m *GatewaySecretsSetGun) *wasp.CallResult { +func callSecretsSet(m *GatewaySecretsSetGun) *wasp.CallResult { randNum := strconv.Itoa(rand.Intn(100000)) randSlot := uint(rand.Intn(5)) version := uint64(time.Now().UnixNano()) @@ -58,8 +58,8 @@ func callSetSecrets(m *GatewaySecretsSetGun) *wasp.CallResult { if err != nil { return &wasp.CallResult{Error: err.Error(), Failed: true} } - if err := UploadS4Secrets(m.Resty, &S4SecretsCfg{ - GatewayURL: fmt.Sprintf("%s/user", m.Cfg.Common.GatewayURL), + _, _, err = UploadS4Secrets(m.Resty, &S4SecretsCfg{ + GatewayURL: m.Cfg.Common.GatewayURL, PrivateKey: os.Getenv("MUMBAI_KEYS"), MessageID: randNum, Method: "secrets_set", @@ -68,7 +68,8 @@ func callSetSecrets(m *GatewaySecretsSetGun) *wasp.CallResult { S4SetVersion: version, S4SetExpirationPeriod: expiration, S4SetPayload: secrets, - }); err != nil { + }) + if err != nil { return &wasp.CallResult{Error: err.Error(), Failed: true} } return &wasp.CallResult{} @@ -80,7 +81,7 @@ func callSecretsList(m *GatewaySecretsSetGun) *wasp.CallResult { version := uint64(time.Now().UnixNano()) expiration := int64(60 * 60 * 1000) if err := ListS4Secrets(m.Resty, &S4SecretsCfg{ - GatewayURL: fmt.Sprintf("%s/user", m.Cfg.Common.GatewayURL), + GatewayURL: fmt.Sprintf(m.Cfg.Common.GatewayURL), RecieverAddr: m.Cfg.Common.Receiver, PrivateKey: os.Getenv("MUMBAI_KEYS"), MessageID: randNum, @@ -100,7 +101,7 @@ func (m *GatewaySecretsSetGun) Call(_ *wasp.Generator) *wasp.CallResult { var res *wasp.CallResult switch m.Method { case "secrets_set": - res = callSetSecrets(m) + res = callSecretsSet(m) case "secrets_list": res = callSecretsList(m) default: diff --git a/integration-tests/load/functions/gateway_test.go b/integration-tests/load/functions/gateway_test.go index 946afdd711a..c8e63f92f2b 100644 --- a/integration-tests/load/functions/gateway_test.go +++ b/integration-tests/load/functions/gateway_test.go @@ -1,10 +1,12 @@ package loadfunctions import ( - "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" + "testing" + "github.com/smartcontractkit/wasp" "github.com/stretchr/testify/require" - "testing" + + "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" ) func TestGatewayLoad(t *testing.T) { diff --git a/integration-tests/load/functions/request_gun.go b/integration-tests/load/functions/request_gun.go index f939b2583ab..d9987eaa756 100644 --- a/integration-tests/load/functions/request_gun.go +++ b/integration-tests/load/functions/request_gun.go @@ -4,22 +4,41 @@ import ( "github.com/smartcontractkit/wasp" ) -/* SingleFunctionCallGun is a gun that constantly requests randomness for one feed */ +type TestMode int + +const ( + ModeHTTPPayload TestMode = iota + ModeSecretsOnlyPayload + ModeReal +) type SingleFunctionCallGun struct { - ft *FunctionsTest - times uint32 - source string - slotID uint8 - slotVersion uint64 - args []string - subscriptionId uint64 - jobId [32]byte + ft *FunctionsTest + mode TestMode + times uint32 + source string + slotID uint8 + slotVersion uint64 + encryptedSecrets []byte + args []string + subscriptionId uint64 + jobId [32]byte } -func NewSingleFunctionCallGun(ft *FunctionsTest, times uint32, source string, slotID uint8, slotVersion uint64, args []string, subscriptionId uint64, jobId [32]byte) *SingleFunctionCallGun { +func NewSingleFunctionCallGun( + ft *FunctionsTest, + mode TestMode, + times uint32, + source string, + slotID uint8, + slotVersion uint64, + args []string, + subscriptionId uint64, + jobId [32]byte, +) *SingleFunctionCallGun { return &SingleFunctionCallGun{ ft: ft, + mode: mode, times: times, source: source, slotID: slotID, @@ -30,8 +49,23 @@ func NewSingleFunctionCallGun(ft *FunctionsTest, times uint32, source string, sl } } -// Call implements example gun call, assertions on response bodies should be done here -func (m *SingleFunctionCallGun) Call(l *wasp.Generator) *wasp.CallResult { +func (m *SingleFunctionCallGun) callReal() *wasp.CallResult { + err := m.ft.LoadTestClient.SendRequestWithDONHostedSecrets( + m.times, + m.source, + m.slotID, + m.slotVersion, + m.args, + m.subscriptionId, + m.jobId, + ) + if err != nil { + return &wasp.CallResult{Error: err.Error(), Failed: true} + } + return &wasp.CallResult{} +} + +func (m *SingleFunctionCallGun) callWithSecrets() *wasp.CallResult { err := m.ft.LoadTestClient.SendRequestWithDONHostedSecrets( m.times, m.source, @@ -46,3 +80,32 @@ func (m *SingleFunctionCallGun) Call(l *wasp.Generator) *wasp.CallResult { } return &wasp.CallResult{} } + +func (m *SingleFunctionCallGun) callWithHttp() *wasp.CallResult { + err := m.ft.LoadTestClient.SendRequest( + m.times, + m.source, + []byte{}, + m.args, + m.subscriptionId, + m.jobId, + ) + if err != nil { + return &wasp.CallResult{Error: err.Error(), Failed: true} + } + return &wasp.CallResult{} +} + +// Call implements example gun call, assertions on response bodies should be done here +func (m *SingleFunctionCallGun) Call(_ *wasp.Generator) *wasp.CallResult { + switch m.mode { + case ModeSecretsOnlyPayload: + return m.callWithSecrets() + case ModeHTTPPayload: + return m.callWithHttp() + case ModeReal: + return m.callReal() + default: + panic("test mode must be ModeSecretsOnlyPayload, ModeHTTPPayload or ModeReal") + } +} diff --git a/integration-tests/load/functions/setup.go b/integration-tests/load/functions/setup.go index 0433b5beb61..5d44cbc698e 100644 --- a/integration-tests/load/functions/setup.go +++ b/integration-tests/load/functions/setup.go @@ -2,21 +2,22 @@ package loadfunctions import ( "crypto/ecdsa" - "fmt" + "math/big" + mrand "math/rand" + "os" + "strconv" + "time" + "github.com/ethereum/go-ethereum/crypto" "github.com/go-resty/resty/v2" "github.com/pkg/errors" "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" - "math/big" - mrand "math/rand" - "os" - "strconv" - "time" ) type FunctionsTest struct { @@ -49,16 +50,16 @@ type S4SecretsCfg struct { } func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { - bc, err := blockchain.NewEVMClientFromNetwork(networks.SelectedNetwork) + bc, err := blockchain.NewEVMClientFromNetwork(networks.SelectedNetwork, log.Logger) if err != nil { return nil, err } - cd, err := contracts.NewContractDeployer(bc) + cd, err := contracts.NewContractDeployer(bc, log.Logger) if err != nil { return nil, err } - cl, err := contracts.NewContractLoader(bc) + cl, err := contracts.NewContractLoader(bc, log.Logger) if err != nil { return nil, err } @@ -115,7 +116,7 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { if err != nil { return nil, errors.Wrap(err, "failed to get DON public key") } - log.Info().Hex("DONPublicKeyHex", donPubKey).Msg("Loaded coordinator keys") + log.Info().Hex("DONPublicKeyHex", donPubKey).Msg("Loaded DON key") tdh2pk, err := ParseTDH2Key(tpk) if err != nil { return nil, errors.Wrap(err, "failed to unmarshal tdh2 public key") @@ -126,8 +127,8 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { if err != nil { return nil, errors.Wrap(err, "failed to generate tdh2 secrets") } - if err := UploadS4Secrets(resty.New(), &S4SecretsCfg{ - GatewayURL: fmt.Sprintf("%s/user", cfg.Common.GatewayURL), + slotID, slotVersion, err := UploadS4Secrets(resty.New(), &S4SecretsCfg{ + GatewayURL: cfg.Common.GatewayURL, PrivateKey: cfg.MumbaiPrivateKey, MessageID: strconv.Itoa(mrand.Intn(100000-1) + 1), Method: "secrets_set", @@ -136,9 +137,16 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { S4SetVersion: uint64(time.Now().UnixNano()), S4SetExpirationPeriod: 60 * 60 * 1000, S4SetPayload: encryptedSecrets, - }); err != nil { + }) + if err != nil { return nil, errors.Wrap(err, "failed to upload secrets to S4") } + cfg.Common.SecretsSlotID = slotID + cfg.Common.SecretsVersionID = slotVersion + log.Info(). + Uint8("SlotID", slotID). + Uint64("SlotVersion", slotVersion). + Msg("Set new secret") } return &FunctionsTest{ EVMClient: bc, diff --git a/integration-tests/migration/upgrade_version_test.go b/integration-tests/migration/upgrade_version_test.go index 1f90bd123eb..d1d79de5eed 100644 --- a/integration-tests/migration/upgrade_version_test.go +++ b/integration-tests/migration/upgrade_version_test.go @@ -6,13 +6,15 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "os" + + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" ) func TestVersionUpgrade(t *testing.T) { t.Parallel() env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). WithGeth(). WithCLNodes(1). Build() diff --git a/integration-tests/networks/known_networks.go b/integration-tests/networks/known_networks.go deleted file mode 100644 index 4d12d6b5b60..00000000000 --- a/integration-tests/networks/known_networks.go +++ /dev/null @@ -1,598 +0,0 @@ -// Package networks holds all known network information for the tests -package networks - -import ( - "crypto/ecdsa" - "fmt" - "os" - "strings" - "time" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/rs/zerolog/log" - - "github.com/smartcontractkit/chainlink-testing-framework/utils" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/logging" -) - -// Pre-configured test networks and their connections -// Some networks with public RPC endpoints are already filled out, but make use of environment variables to use info like -// private RPC endpoints and private keys. -var ( - // To create replica of simulated EVM network, with different chain ids - AdditionalSimulatedChainIds = []int64{3337, 4337, 5337, 6337, 7337, 8337, 9337, 9338} - AdditionalSimulatedPvtKeys = []string{ - "5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a", - "7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6", - "47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a", - "8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba", - "92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e", - "4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356", - "dbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97", - "2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6", - } - // SelectedNetworks uses the SELECTED_NETWORKS env var to determine which network to run the test on. - // For use in tests that utilize multiple chains. For tests on one chain, see SelectedNetwork - // For CCIP use index 1 and 2 of SELECTED_NETWORKS to denote source and destination network respectively - SelectedNetworks []blockchain.EVMNetwork = determineSelectedNetworks() - // SelectedNetwork uses the first listed network in SELECTED_NETWORKS, for use in tests on only one chain - SelectedNetwork blockchain.EVMNetwork = SelectedNetworks[0] - - // SimulatedEVM represents a simulated network - SimulatedEVM blockchain.EVMNetwork = blockchain.SimulatedEVMNetwork - // generalEVM is a customizable network through environment variables - // This is getting little use, and causes some confusion. Can re-enable if people want it. - // generalEVM blockchain.EVMNetwork = blockchain.LoadNetworkFromEnvironment() - - // SimulatedevmNonDev1 represents a simulated network which can be used to deploy a non-dev geth node - SimulatedEVMNonDev1 = blockchain.EVMNetwork{ - Name: "source-chain", - Simulated: true, - ClientImplementation: blockchain.EthereumClientImplementation, - SupportsEIP1559: true, - ChainID: 1337, - PrivateKeys: []string{ - "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", - }, - URLs: []string{"ws://source-chain-ethereum-geth:8546"}, - HTTPURLs: []string{"http://source-chain-ethereum-geth:8544"}, - ChainlinkTransactionLimit: 500000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 10000, - DefaultGasLimit: 6000000, - } - - // SimulatedEVM_NON_DEV_2 represents a simulated network with chain id 2337 which can be used to deploy a non-dev geth node - SimulatedEVMNonDev2 = blockchain.EVMNetwork{ - Name: "dest-chain", - Simulated: true, - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 2337, - PrivateKeys: []string{ - "59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", - }, - URLs: []string{"ws://dest-chain-ethereum-geth:8546"}, - HTTPURLs: []string{"http://dest-chain-ethereum-geth:8544"}, - ChainlinkTransactionLimit: 500000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 10000, - DefaultGasLimit: 6000000, - } - - SimulatedEVMNonDev = blockchain.EVMNetwork{ - Name: "geth", - Simulated: true, - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 1337, - PrivateKeys: []string{ - "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", - }, - URLs: []string{"ws://geth-ethereum-geth:8546"}, - HTTPURLs: []string{"http://geth-ethereum-geth:8544"}, - ChainlinkTransactionLimit: 500000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 10000, - } - - EthereumMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Ethereum Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 1, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: 5 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - FinalityTag: true, - DefaultGasLimit: 6000000, - } - - // sepoliaTestnet https://sepolia.dev/ - SepoliaTestnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Sepolia Testnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 11155111, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - FinalityTag: true, - DefaultGasLimit: 6000000, - } - - // goerliTestnet https://goerli.net/ - GoerliTestnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Goerli Testnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 5, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: 5 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - FinalityTag: true, - DefaultGasLimit: 6000000, - } - - KlaytnMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Klaytn Mainnet", - SupportsEIP1559: false, - ClientImplementation: blockchain.KlaytnClientImplementation, - ChainID: 8217, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - // klaytnBaobab https://klaytn.foundation/ - KlaytnBaobab blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Klaytn Baobab", - SupportsEIP1559: false, - ClientImplementation: blockchain.KlaytnClientImplementation, - ChainID: 1001, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - MetisAndromeda blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Metis Andromeda", - SupportsEIP1559: false, - ClientImplementation: blockchain.MetisClientImplementation, - ChainID: 1088, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - // metisStardust https://www.metis.io/ - MetisStardust blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Metis Stardust", - SupportsEIP1559: false, - ClientImplementation: blockchain.MetisClientImplementation, - ChainID: 588, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - } - - ArbitrumMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Arbitrum Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.ArbitrumClientImplementation, - ChainID: 42161, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, - MinimumConfirmations: 0, - GasEstimationBuffer: 0, - FinalityTag: true, - DefaultGasLimit: 100000000, - } - - // arbitrumGoerli https://developer.offchainlabs.com/docs/public_chains - ArbitrumGoerli blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Arbitrum Goerli", - SupportsEIP1559: true, - ClientImplementation: blockchain.ArbitrumClientImplementation, - ChainID: 421613, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 0, - GasEstimationBuffer: 0, - FinalityTag: true, - DefaultGasLimit: 100000000, - } - - OptimismMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Optimism Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.OptimismClientImplementation, - ChainID: 10, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - FinalityTag: true, - DefaultGasLimit: 6000000, - } - - // optimismGoerli https://dev.optimism.io/kovan-to-goerli/ - OptimismGoerli blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Optimism Goerli", - SupportsEIP1559: true, - ClientImplementation: blockchain.OptimismClientImplementation, - ChainID: 420, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - FinalityTag: true, - DefaultGasLimit: 6000000, - } - - RSKMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "RSK Mainnet", - SupportsEIP1559: false, - ClientImplementation: blockchain.RSKClientImplementation, - ChainID: 30, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - } - - // rskTestnet https://www.rsk.co/ - RSKTestnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "RSK Testnet", - SupportsEIP1559: false, - ClientImplementation: blockchain.RSKClientImplementation, - ChainID: 31, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - } - - PolygonMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Polygon Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.PolygonClientImplementation, - ChainID: 137, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - FinalityDepth: 550, - DefaultGasLimit: 6000000, - } - - // PolygonMumbai https://mumbai.polygonscan.com/ - PolygonMumbai blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Polygon Mumbai", - SupportsEIP1559: true, - ClientImplementation: blockchain.PolygonClientImplementation, - ChainID: 80001, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: 3 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 100000, - FinalityDepth: 550, - DefaultGasLimit: 8000000, - } - - AvalancheMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Avalanche Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 43114, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - FinalityDepth: 35, - DefaultGasLimit: 6000000, - } - - AvalancheFuji = blockchain.EVMNetwork{ - Name: "Avalanche Fuji", - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 43113, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - FinalityDepth: 35, - DefaultGasLimit: 6000000, - } - - Quorum = blockchain.EVMNetwork{ - Name: "Quorum", - SupportsEIP1559: false, - ClientImplementation: blockchain.QuorumClientImplementation, - ChainID: 1337, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - BaseGoerli blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Base Goerli", - SupportsEIP1559: true, - ClientImplementation: blockchain.OptimismClientImplementation, - ChainID: 84531, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 0, - GasEstimationBuffer: 0, - } - - CeloAlfajores = blockchain.EVMNetwork{ - Name: "Celo Alfajores", - SupportsEIP1559: false, - ClientImplementation: blockchain.CeloClientImplementation, - ChainID: 44787, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - } - - ScrollSepolia = blockchain.EVMNetwork{ - Name: "Scroll Sepolia", - ClientImplementation: blockchain.ScrollClientImplementation, - ChainID: 534351, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - ScrollMainnet = blockchain.EVMNetwork{ - Name: "Scroll Mainnet", - ClientImplementation: blockchain.ScrollClientImplementation, - ChainID: 534352, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - CeloMainnet = blockchain.EVMNetwork{ - Name: "Celo", - ClientImplementation: blockchain.CeloClientImplementation, - ChainID: 42220, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - } - - BaseMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Base Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.OptimismClientImplementation, - ChainID: 8453, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 0, - GasEstimationBuffer: 0, - } - - BSCTestnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "BSC Testnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.BSCClientImplementation, - ChainID: 97, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 3, - GasEstimationBuffer: 0, - } - - BSCMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "BSC Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.BSCClientImplementation, - ChainID: 56, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 3, - GasEstimationBuffer: 0, - } - - MappedNetworks = map[string]blockchain.EVMNetwork{ - "SIMULATED": SimulatedEVM, - "SIMULATED_1": SimulatedEVMNonDev1, - "SIMULATED_2": SimulatedEVMNonDev2, - "SIMULATED_NONDEV": SimulatedEVMNonDev, - // "GENERAL": generalEVM, // See above - "ETHEREUM_MAINNET": EthereumMainnet, - "GOERLI": GoerliTestnet, - "SEPOLIA": SepoliaTestnet, - "KLAYTN_MAINNET": KlaytnMainnet, - "KLAYTN_BAOBAB": KlaytnBaobab, - "METIS_ANDROMEDA": MetisAndromeda, - "METIS_STARDUST": MetisStardust, - "ARBITRUM_MAINNET": ArbitrumMainnet, - "ARBITRUM_GOERLI": ArbitrumGoerli, - "OPTIMISM_MAINNET": OptimismMainnet, - "OPTIMISM_GOERLI": OptimismGoerli, - "BASE_GOERLI": BaseGoerli, - "CELO_ALFAJORES": CeloAlfajores, - "CELO_MAINNET": CeloMainnet, - "RSK": RSKTestnet, - "MUMBAI": PolygonMumbai, - "POLYGON_MAINNET": PolygonMainnet, - "AVALANCHE_FUJI": AvalancheFuji, - "AVALANCHE_MAINNET": AvalancheMainnet, - "QUORUM": Quorum, - "SCROLL_SEPOLIA": ScrollSepolia, - "SCROLL_MAINNET": ScrollMainnet, - "BASE_MAINNET": BaseMainnet, - "BSC_TESTNET": BSCTestnet, - "BSC_MAINNET": BSCMainnet, - } -) - -// determineSelectedNetworks uses `SELECTED_NETWORKS` to determine which networks to run the tests on. -// Use DetermineSelectedNetwork for tests that only use one network -func determineSelectedNetworks() []blockchain.EVMNetwork { - logging.Init() - selectedNetworks := make([]blockchain.EVMNetwork, 0) - rawSelectedNetworks := strings.ToUpper(os.Getenv("SELECTED_NETWORKS")) - setNetworkNames := strings.Split(rawSelectedNetworks, ",") - - for _, setNetworkName := range setNetworkNames { - if chosenNetwork, valid := MappedNetworks[setNetworkName]; valid { - log.Info(). - Interface("SELECTED_NETWORKS", setNetworkNames). - Str("Network Name", chosenNetwork.Name). - Msg("Read network choice from 'SELECTED_NETWORKS'") - setURLs(setNetworkName, &chosenNetwork) - setKeys(setNetworkName, &chosenNetwork) - selectedNetworks = append(selectedNetworks, chosenNetwork) - } else { - validNetworks := make([]string, 0) - for validNetwork := range MappedNetworks { - validNetworks = append(validNetworks, validNetwork) - } - log.Fatal(). - Interface("SELECTED_NETWORKS", setNetworkNames). - Str("Valid Networks", strings.Join(validNetworks, ", ")). - Msg("SELECTED_NETWORKS value is invalid. Use a valid network(s).") - } - } - return selectedNetworks -} - -// setURLs sets a network URL(s) based on env vars -func setURLs(prefix string, network *blockchain.EVMNetwork) { - prefix = strings.Trim(prefix, "_") - prefix = strings.ToUpper(prefix) - - if strings.Contains(prefix, "SIMULATED") { // Use defaults for SIMULATED - return - } - - wsEnvVar := fmt.Sprintf("%s_URLS", prefix) - httpEnvVar := fmt.Sprintf("%s_HTTP_URLS", prefix) - wsEnvURLs, err := utils.GetEnv(wsEnvVar) - if err != nil { - log.Fatal().Err(err).Str("env var", wsEnvVar).Msg("Error getting env var") - } - httpEnvURLs, err := utils.GetEnv(httpEnvVar) - if err != nil { - log.Fatal().Err(err).Str("env var", httpEnvVar).Msg("Error getting env var") - } - if wsEnvURLs == "" { - evmUrls, err := utils.GetEnv("EVM_URLS") - if err != nil { - log.Fatal().Err(err).Str("env var", "EVM_URLS").Msg("Error getting env var") - } - evmhttpUrls, err := utils.GetEnv("EVM_HTTP_URLS") - if err != nil { - log.Fatal().Err(err).Str("env var", "EVM_HTTP_URLS").Msg("Error getting env var") - } - wsURLs := strings.Split(evmUrls, ",") - httpURLs := strings.Split(evmhttpUrls, ",") - log.Warn().Msgf("No '%s' env var defined, defaulting to 'EVM_URLS'", wsEnvVar) - network.URLs = wsURLs - network.HTTPURLs = httpURLs - return - } - - wsURLs := strings.Split(wsEnvURLs, ",") - httpURLs := strings.Split(httpEnvURLs, ",") - network.URLs = wsURLs - network.HTTPURLs = httpURLs - log.Info().Msg("Read network URLs") -} - -// setKeys sets a network's private key(s) based on env vars -func setKeys(prefix string, network *blockchain.EVMNetwork) { - prefix = strings.Trim(prefix, "_") - prefix = strings.ToUpper(prefix) - - if strings.Contains(prefix, "SIMULATED") { // Use defaults for SIMULATED - return - } - - envVar := fmt.Sprintf("%s_KEYS", prefix) - keysFromEnv, err := utils.GetEnv(envVar) - if err != nil { - log.Fatal().Err(err).Str("env var", envVar).Msg("Error getting env var") - } - if keysFromEnv == "" { - log.Warn().Msg(fmt.Sprintf("No '%s' env var defined, defaulting to 'EVM_KEYS'", envVar)) - keysFromEnv = os.Getenv("EVM_KEYS") - } - keys := strings.Split(keysFromEnv, ",") - for i, key := range keys { - keys[i] = strings.TrimPrefix(key, "0x") - } - network.PrivateKeys = keys - - // log public keys for debugging - publicKeys := []string{} - for _, key := range network.PrivateKeys { - publicKey, err := privateKeyToAddress(key) - if err != nil { - log.Fatal().Err(err).Msg("Error getting public key from private key") - } - publicKeys = append(publicKeys, publicKey) - } - log.Info().Interface("Funding Addresses", publicKeys).Msg("Read network Keys") -} - -func privateKeyToAddress(privateKeyString string) (string, error) { - privateKey, err := crypto.HexToECDSA(privateKeyString) - if err != nil { - return "", err - } - publicKey := privateKey.Public() - publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) - if !ok { - return "", fmt.Errorf("error casting private key to public ECDSA key") - } - return crypto.PubkeyToAddress(*publicKeyECDSA).Hex(), nil -} diff --git a/integration-tests/performance/cron_test.go b/integration-tests/performance/cron_test.go index 933014a1698..c66a1803564 100644 --- a/integration-tests/performance/cron_test.go +++ b/integration-tests/performance/cron_test.go @@ -22,9 +22,10 @@ import ( ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) diff --git a/integration-tests/performance/directrequest_test.go b/integration-tests/performance/directrequest_test.go index 47a16de1091..98c03c2bb96 100644 --- a/integration-tests/performance/directrequest_test.go +++ b/integration-tests/performance/directrequest_test.go @@ -18,27 +18,27 @@ import ( mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" "github.com/google/uuid" ) func TestDirectRequestPerformance(t *testing.T) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) testEnvironment := setupDirectRequestTest(t) if testEnvironment.WillUseRemoteRunner() { return } - chainClient, err := blockchain.NewEVMClient(blockchain.SimulatedEVMNetwork, testEnvironment) + chainClient, err := blockchain.NewEVMClient(blockchain.SimulatedEVMNetwork, testEnvironment, l) require.NoError(t, err, "Connecting to blockchain nodes shouldn't fail") - contractDeployer, err := contracts.NewContractDeployer(chainClient) + contractDeployer, err := contracts.NewContractDeployer(chainClient, l) require.NoError(t, err, "Deploying contracts shouldn't fail") chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") @@ -82,6 +82,7 @@ func TestDirectRequestPerformance(t *testing.T) { Name: "direct_request", MinIncomingConfirmations: "1", ContractAddress: oracle.Address(), + EVMChainID: chainClient.GetChainID().String(), ExternalJobID: jobUUID.String(), ObservationSource: ost, }) diff --git a/integration-tests/performance/flux_test.go b/integration-tests/performance/flux_test.go index ecacce90ca7..2c33096a356 100644 --- a/integration-tests/performance/flux_test.go +++ b/integration-tests/performance/flux_test.go @@ -19,25 +19,25 @@ import ( mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) func TestFluxPerformance(t *testing.T) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) testEnvironment, testNetwork := setupFluxTest(t) if testEnvironment.WillUseRemoteRunner() { return } - chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment) + chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment, l) require.NoError(t, err, "Connecting to blockchain nodes shouldn't fail") - contractDeployer, err := contracts.NewContractDeployer(chainClient) + contractDeployer, err := contracts.NewContractDeployer(chainClient, l) require.NoError(t, err, "Deploying contracts shouldn't fail") chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") @@ -99,6 +99,7 @@ func TestFluxPerformance(t *testing.T) { fluxSpec := &client.FluxMonitorJobSpec{ Name: fmt.Sprintf("flux-monitor-%s", adapterUUID), ContractAddress: fluxInstance.Address(), + EVMChainID: chainClient.GetChainID().String(), Threshold: 0, AbsoluteThreshold: 0, PollTimerPeriod: 15 * time.Second, // min 15s @@ -115,7 +116,7 @@ func TestFluxPerformance(t *testing.T) { return } fluxRoundTimeout := 2 * time.Minute - fluxRound := contracts.NewFluxAggregatorRoundConfirmer(fluxInstance, big.NewInt(1), fluxRoundTimeout) + fluxRound := contracts.NewFluxAggregatorRoundConfirmer(fluxInstance, big.NewInt(1), fluxRoundTimeout, l) chainClient.AddHeaderEventSubscription(fluxInstance.Address(), fluxRound) err = chainClient.WaitForEvents() require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") @@ -133,7 +134,7 @@ func TestFluxPerformance(t *testing.T) { require.Equal(t, int64(3), data.AllocatedFunds.Int64(), "Expected allocated funds to be %d, but found %d", int64(3), data.AllocatedFunds.Int64()) - fluxRound = contracts.NewFluxAggregatorRoundConfirmer(fluxInstance, big.NewInt(2), fluxRoundTimeout) + fluxRound = contracts.NewFluxAggregatorRoundConfirmer(fluxInstance, big.NewInt(2), fluxRoundTimeout, l) chainClient.AddHeaderEventSubscription(fluxInstance.Address(), fluxRound) err = mockServer.SetValuePath(adapterPath, 1e10) require.NoError(t, err, "Setting value path in mock server shouldn't fail") diff --git a/integration-tests/performance/keeper_test.go b/integration-tests/performance/keeper_test.go index 346f0897d47..7ab0f53d0d0 100644 --- a/integration-tests/performance/keeper_test.go +++ b/integration-tests/performance/keeper_test.go @@ -18,13 +18,13 @@ import ( "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver" mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) @@ -44,7 +44,7 @@ var keeperDefaultRegistryConfig = contracts.KeeperRegistrySettings{ } func TestKeeperPerformance(t *testing.T) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) testEnvironment, chainClient, chainlinkNodes, contractDeployer, linkToken := setupKeeperTest(t, "basic-smoke") if testEnvironment.WillUseRemoteRunner() { return @@ -67,7 +67,7 @@ func TestKeeperPerformance(t *testing.T) { // Not the last node, hence not all nodes started profiling yet. return } - actions.CreateKeeperJobs(t, chainlinkNodes, registry, contracts.OCRv2Config{}) + actions.CreateKeeperJobs(t, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) err := chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -173,9 +173,10 @@ PerformGasOverhead = 150_000` return testEnvironment, nil, nil, nil, nil } - chainClient, err := blockchain.NewEVMClient(network, testEnvironment) + l := logging.GetTestLogger(t) + chainClient, err := blockchain.NewEVMClient(network, testEnvironment, l) require.NoError(t, err, "Connecting to blockchain nodes shouldn't fail") - contractDeployer, err := contracts.NewContractDeployer(chainClient) + contractDeployer, err := contracts.NewContractDeployer(chainClient, l) require.NoError(t, err, "Deploying contracts shouldn't fail") chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") diff --git a/integration-tests/performance/ocr_test.go b/integration-tests/performance/ocr_test.go index 25791161bc2..d3d29049653 100644 --- a/integration-tests/performance/ocr_test.go +++ b/integration-tests/performance/ocr_test.go @@ -17,11 +17,13 @@ import ( mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) @@ -31,10 +33,10 @@ func TestOCRBasic(t *testing.T) { if testEnvironment.WillUseRemoteRunner() { return } - - chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment) + l := logging.GetTestLogger(t) + chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment, l) require.NoError(t, err, "Connecting to blockchain nodes shouldn't fail") - contractDeployer, err := contracts.NewContractDeployer(chainClient) + contractDeployer, err := contracts.NewContractDeployer(chainClient, l) require.NoError(t, err, "Deploying contracts shouldn't fail") chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) @@ -57,9 +59,9 @@ func TestOCRBasic(t *testing.T) { require.NoError(t, err, "Error waiting for events") profileFunction := func(chainlinkNode *client.ChainlinkClient) { - err = actions.CreateOCRJobs(ocrInstances, bootstrapNode, workerNodes, 5, mockServer) + err = actions.CreateOCRJobs(ocrInstances, bootstrapNode, workerNodes, 5, mockServer, chainClient.GetChainID().String()) require.NoError(t, err) - err = actions.StartNewRound(1, ocrInstances, chainClient) + err = actions.StartNewRound(1, ocrInstances, chainClient, l) require.NoError(t, err) answer, err := ocrInstances[0].GetLatestAnswer(context.Background()) @@ -68,7 +70,7 @@ func TestOCRBasic(t *testing.T) { err = mockServer.SetValuePath("ocr", 10) require.NoError(t, err) - err = actions.StartNewRound(2, ocrInstances, chainClient) + err = actions.StartNewRound(2, ocrInstances, chainClient, l) require.NoError(t, err) answer, err = ocrInstances[0].GetLatestAnswer(context.Background()) diff --git a/integration-tests/performance/vrf_test.go b/integration-tests/performance/vrf_test.go index 2074eecaf78..af3a3ecba81 100644 --- a/integration-tests/performance/vrf_test.go +++ b/integration-tests/performance/vrf_test.go @@ -16,26 +16,26 @@ import ( "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) func TestVRFBasic(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) testEnvironment, testNetwork := setupVRFTest(t) if testEnvironment.WillUseRemoteRunner() { return } - chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment) + chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment, l) require.NoError(t, err, "Connecting client shouldn't fail") - cd, err := contracts.NewContractDeployer(chainClient) + cd, err := contracts.NewContractDeployer(chainClient, l) require.NoError(t, err, "Deploying contracts shouldn't fail") chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") diff --git a/integration-tests/reorg/automation_reorg_test.go b/integration-tests/reorg/automation_reorg_test.go index 4a75d92d5d1..ab439e59f29 100644 --- a/integration-tests/reorg/automation_reorg_test.go +++ b/integration-tests/reorg/automation_reorg_test.go @@ -17,13 +17,14 @@ import ( "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" "github.com/smartcontractkit/chainlink-env/pkg/helm/reorg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/networks" ) var ( @@ -123,7 +124,7 @@ const ( * normal pace after the event. */ func TestAutomationReorg(t *testing.T) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) network := networks.SelectedNetwork cd, err := chainlink.NewDeployment(numberOfNodes, defaultAutomationSettings) @@ -146,9 +147,9 @@ func TestAutomationReorg(t *testing.T) { return } - chainClient, err := blockchain.NewEVMClient(network, testEnvironment) + chainClient, err := blockchain.NewEVMClient(network, testEnvironment, l) require.NoError(t, err, "Error connecting to blockchain") - contractDeployer, err := contracts.NewContractDeployer(chainClient) + contractDeployer, err := contracts.NewContractDeployer(chainClient, l) require.NoError(t, err, "Error building contract deployer") chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) require.NoError(t, err, "Error connecting to Chainlink nodes") diff --git a/integration-tests/reorg/reorg_test.go b/integration-tests/reorg/reorg_test.go index d6ac5ce1cf1..5666d8c7540 100644 --- a/integration-tests/reorg/reorg_test.go +++ b/integration-tests/reorg/reorg_test.go @@ -1,6 +1,7 @@ package reorg import ( + "context" "fmt" "math/big" "os" @@ -23,13 +24,13 @@ import ( ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/utils" - "context" "github.com/onsi/gomega" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" ) const ( @@ -90,6 +91,7 @@ func CleanupReorgTest( func TestDirectRequestReorg(t *testing.T) { logging.Init() + l := logging.GetTestLogger(t) testEnvironment := environment.New(&environment.Config{ TTL: 1 * time.Hour, Test: t, @@ -130,9 +132,9 @@ func TestDirectRequestReorg(t *testing.T) { err = testEnvironment.AddHelmCharts(chainlinkDeployment).Run() require.NoError(t, err, "Error adding to test environment") - chainClient, err := blockchain.NewEVMClient(networkSettings, testEnvironment) + chainClient, err := blockchain.NewEVMClient(networkSettings, testEnvironment, l) require.NoError(t, err, "Error connecting to blockchain") - cd, err := contracts.NewContractDeployer(chainClient) + cd, err := contracts.NewContractDeployer(chainClient, l) require.NoError(t, err, "Error building contract deployer") chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) require.NoError(t, err, "Error connecting to Chainlink nodes") @@ -180,6 +182,7 @@ func TestDirectRequestReorg(t *testing.T) { Name: "direct_request", MinIncomingConfirmations: minIncomingConfirmations, ContractAddress: oracle.Address(), + EVMChainID: chainClient.GetChainID().String(), ExternalJobID: jobUUID.String(), ObservationSource: ost, }) diff --git a/integration-tests/runner_helpers.go b/integration-tests/runner_helpers.go index 17950064575..43268a703ac 100644 --- a/integration-tests/runner_helpers.go +++ b/integration-tests/runner_helpers.go @@ -12,12 +12,12 @@ import ( "strings" "time" - gh "github.com/cli/go-gh/v2" + "github.com/cli/go-gh/v2" "github.com/ethereum/go-ethereum/crypto" "github.com/manifoldco/promptui" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink/integration-tests/networks" + "github.com/smartcontractkit/chainlink-testing-framework/networks" ) func waitForWorkflowRun(branch, ghUser string) (string, error) { diff --git a/integration-tests/scripts/buildTestMatrixList.sh b/integration-tests/scripts/buildTestMatrixList.sh index 25f72715095..7f058b5b659 100755 --- a/integration-tests/scripts/buildTestMatrixList.sh +++ b/integration-tests/scripts/buildTestMatrixList.sh @@ -14,6 +14,7 @@ cd "$SCRIPT_DIR"/../ || exit 1 FILENAME=$1 MATRIX_JOB_NAME=$2 NODE_LABEL=$3 +NODE_COUNT=$4 # Get list of test names from JSON file JSONFILE="${FILENAME}_test_list.json" @@ -25,13 +26,18 @@ matrix_output() { local job_name=$2 local test_name=$3 local node_label=$4 + local node_count=$5 local counter_out=$(printf "%02d\n" $counter) - echo -n "{\"name\": \"${job_name}-${counter_out}\", \"file\": \"${job_name}\",\"nodes\": 1, \"os\": \"${node_label}\", \"pyroscope_env\": \"ci-smoke-${job_name}-evm-simulated\", \"run\": \"-run '^${test_name}$'\"}" + echo -n "{\"name\": \"${job_name}-${counter_out}\", \"file\": \"${job_name}\",\"nodes\": ${node_count}, \"os\": \"${node_label}\", \"pyroscope_env\": \"ci-smoke-${job_name}-evm-simulated\", \"run\": \"-run '^${test_name}$'\"}" } # Read the JSON file and loop through 'tests' and 'run' jq -c '.tests[]' ${JSONFILE} | while read -r test; do testName=$(echo ${test} | jq -r '.name') + label=$(echo ${test} | jq -r '.label // empty') + effective_node_label=${label:-$NODE_LABEL} + node_count=$(echo ${test} | jq -r '.nodes // empty') + effective_node_count=${node_count:-$NODE_COUNT} subTests=$(echo ${test} | jq -r '.run[]?.name // empty') output="" @@ -41,14 +47,14 @@ jq -c '.tests[]' ${JSONFILE} | while read -r test; do if [ $COUNTER -ne 1 ]; then echo -n "," fi - matrix_output $COUNTER $MATRIX_JOB_NAME "${testName}/${subTest}" ${NODE_LABEL} + matrix_output $COUNTER $MATRIX_JOB_NAME "${testName}/${subTest}" ${effective_node_label} ${effective_node_count} ((COUNTER++)) done else if [ $COUNTER -ne 1 ]; then echo -n "," fi - matrix_output $COUNTER $MATRIX_JOB_NAME "${testName}" ${NODE_LABEL} + matrix_output $COUNTER $MATRIX_JOB_NAME "${testName}" ${effective_node_label} ${effective_node_count} ((COUNTER++)) fi diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 109f681ea81..76ee75b21ba 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -9,11 +9,13 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/common" "github.com/onsi/gomega" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-env/logging" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/smartcontractkit/chainlink/integration-tests/actions" @@ -21,12 +23,15 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" + cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) +var utilsABI = cltypes.MustGetABI(automation_utils_2_1.AutomationUtilsABI) + const ( automationDefaultUpkeepGasLimit = uint32(2500000) automationDefaultLinkFunds = int64(9e18) @@ -80,8 +85,6 @@ func TestAutomationBasic(t *testing.T) { func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { t.Parallel() - l := utils.GetTestLogger(t) - registryVersions := map[string]ethereum.KeeperRegistryVersion{ "registry_2_0": ethereum.RegistryVersion_2_0, "registry_2_1_conditional": ethereum.RegistryVersion_2_1, @@ -93,6 +96,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() + l := logging.GetTestLogger(t) var ( upgradeImage string @@ -206,6 +210,172 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { } } +func TestSetUpkeepTriggerConfig(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + + chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( + t, "set-trigger-config", ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, false, + ) + + consumers, upkeepIDs := actions.DeployConsumers( + t, + registry, + registrar, + linkToken, + contractDeployer, + chainClient, + defaultAmountOfUpkeeps, + big.NewInt(automationDefaultLinkFunds), + automationDefaultUpkeepGasLimit, + true, + ) + + // Start log trigger based upkeeps for all consumers + for i := 0; i < len(consumers); i++ { + err := consumers[i].Start() + if err != nil { + return + } + } + + l.Info().Msg("Waiting for all upkeeps to perform") + gom := gomega.NewGomegaWithT(t) + 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++ { + counter, err := consumers[i].Counter(context.Background()) + require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) + expect := 5 + l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep Index", i).Msg("Number of upkeeps performed") + g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", int64(expect)), + "Expected consumer counter to be greater than %d, but got %d", expect, counter.Int64()) + } + }, "5m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~2m for performing each upkeep 5 times, ~2m buffer + + topic0InBytesMatch := [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, + } // bytes representation of 0x3d53a39550e04688065827f3bb86584cb007ab9ebca7ebd528e7301c9c31eb5d + + topic0InBytesNoMatch := [32]byte{ + 62, 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, + } // changed the first byte from 61 to 62 to make it not match + + 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, + } // bytes representation of 0x0000000000000000000000000000000000000000000000000000000000000000 + + // Update the trigger config so no upkeeps are triggered + for i := 0; i < len(consumers); i++ { + upkeepAddr := consumers[i].Address() + + logTriggerConfigStruct := automation_utils_2_1.LogTriggerConfig{ + ContractAddress: common.HexToAddress(upkeepAddr), + FilterSelector: 0, + Topic0: topic0InBytesNoMatch, + Topic1: bytes0, + Topic2: bytes0, + Topic3: bytes0, + } + encodedLogTriggerConfig, err := utilsABI.Methods["_logTriggerConfig"].Inputs.Pack(&logTriggerConfigStruct) + if err != nil { + return + } + + err = registry.SetUpkeepTriggerConfig(upkeepIDs[i], encodedLogTriggerConfig) + require.NoError(t, err, "Could not set upkeep trigger config at index %d", i) + } + + err := chainClient.WaitForEvents() + require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") + + var countersAfterSetNoMatch = make([]*big.Int, len(upkeepIDs)) + + // Wait for 10 seconds to let in-flight upkeeps finish + time.Sleep(10 * time.Second) + for i := 0; i < len(upkeepIDs); i++ { + // Obtain the amount of times the upkeep has been executed so far + countersAfterSetNoMatch[i], err = consumers[i].Counter(context.Background()) + require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) + l.Info().Int64("Upkeep Count", countersAfterSetNoMatch[i].Int64()).Int("Upkeep Index", i).Msg("Upkeep") + } + + l.Info().Msg("Making sure the counter stays consistent") + gom.Consistently(func(g gomega.Gomega) { + for i := 0; i < len(upkeepIDs); i++ { + // Expect the counter to remain constant (At most increase by 2 to account for stale performs) because the upkeep trigger config is not met + bufferCount := int64(2) + latestCounter, err := consumers[i].Counter(context.Background()) + g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) + g.Expect(latestCounter.Int64()).Should(gomega.BeNumerically("<=", countersAfterSetNoMatch[i].Int64()+bufferCount), + "Expected consumer counter to remain less than or equal to %d, but got %d", + countersAfterSetNoMatch[i].Int64()+bufferCount, latestCounter.Int64()) + } + }, "1m", "1s").Should(gomega.Succeed()) + + // Update the trigger config, so upkeeps start performing again + for i := 0; i < len(consumers); i++ { + upkeepAddr := consumers[i].Address() + + logTriggerConfigStruct := automation_utils_2_1.LogTriggerConfig{ + ContractAddress: common.HexToAddress(upkeepAddr), + FilterSelector: 0, + Topic0: topic0InBytesMatch, + Topic1: bytes0, + Topic2: bytes0, + Topic3: bytes0, + } + encodedLogTriggerConfig, err := utilsABI.Methods["_logTriggerConfig"].Inputs.Pack(&logTriggerConfigStruct) + if err != nil { + return + } + + err = registry.SetUpkeepTriggerConfig(upkeepIDs[i], encodedLogTriggerConfig) + require.NoError(t, err, "Could not set upkeep trigger config at index %d", i) + } + + err = chainClient.WaitForEvents() + require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") + + var countersAfterSetMatch = make([]*big.Int, len(upkeepIDs)) + + for i := 0; i < len(upkeepIDs); i++ { + // Obtain the amount of times the upkeep has been executed so far + countersAfterSetMatch[i], err = consumers[i].Counter(context.Background()) + require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) + l.Info().Int64("Upkeep Count", countersAfterSetMatch[i].Int64()).Int("Upkeep Index", i).Msg("Upkeep") + } + + // Wait for 30 seconds to make sure backend is ready + time.Sleep(30 * time.Second) + // Start the consumers again + for i := 0; i < len(consumers); i++ { + err := consumers[i].Start() + if err != nil { + return + } + } + + l.Info().Msg("Making sure the counter starts increasing again") + 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++ { + counter, err := consumers[i].Counter(context.Background()) + require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) + expect := int64(5) + l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep Index", i).Msg("Number of upkeeps performed") + g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", countersAfterSetMatch[i].Int64()+expect), + "Expected consumer counter to be greater than %d, but got %d", countersAfterSetMatch[i].Int64()+expect, counter.Int64()) + } + }, "5m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~2m for performing each upkeep 5 times, ~2m buffer +} + func TestAutomationAddFunds(t *testing.T) { t.Parallel() registryVersions := map[string]ethereum.KeeperRegistryVersion{ @@ -258,8 +428,6 @@ func TestAutomationAddFunds(t *testing.T) { func TestAutomationPauseUnPause(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) - registryVersions := map[string]ethereum.KeeperRegistryVersion{ "registry_2_0": ethereum.RegistryVersion_2_0, "registry_2_1": ethereum.RegistryVersion_2_1, @@ -270,6 +438,7 @@ func TestAutomationPauseUnPause(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() + l := logging.GetTestLogger(t) chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "pause-unpause", registryVersion, defaultOCRRegistryConfig, false, ) @@ -342,8 +511,6 @@ func TestAutomationPauseUnPause(t *testing.T) { func TestAutomationRegisterUpkeep(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) - registryVersions := map[string]ethereum.KeeperRegistryVersion{ "registry_2_0": ethereum.RegistryVersion_2_0, "registry_2_1": ethereum.RegistryVersion_2_1, @@ -354,6 +521,7 @@ func TestAutomationRegisterUpkeep(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() + l := logging.GetTestLogger(t) chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "register-upkeep", registryVersion, defaultOCRRegistryConfig, false, ) @@ -415,7 +583,6 @@ func TestAutomationRegisterUpkeep(t *testing.T) { func TestAutomationPauseRegistry(t *testing.T) { t.Parallel() - registryVersions := map[string]ethereum.KeeperRegistryVersion{ "registry_2_0": ethereum.RegistryVersion_2_0, "registry_2_1": ethereum.RegistryVersion_2_1, @@ -473,8 +640,6 @@ func TestAutomationPauseRegistry(t *testing.T) { func TestAutomationKeeperNodesDown(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) - registryVersions := map[string]ethereum.KeeperRegistryVersion{ "registry_2_0": ethereum.RegistryVersion_2_0, "registry_2_1": ethereum.RegistryVersion_2_1, @@ -485,6 +650,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() + l := logging.GetTestLogger(t) chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "keeper-nodes-down", registryVersion, defaultOCRRegistryConfig, false, ) @@ -560,7 +726,6 @@ func TestAutomationKeeperNodesDown(t *testing.T) { func TestAutomationPerformSimulation(t *testing.T) { t.Parallel() - registryVersions := map[string]ethereum.KeeperRegistryVersion{ "registry_2_0": ethereum.RegistryVersion_2_0, "registry_2_1": ethereum.RegistryVersion_2_1, @@ -624,8 +789,6 @@ func TestAutomationPerformSimulation(t *testing.T) { func TestAutomationCheckPerformGasLimit(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) - registryVersions := map[string]ethereum.KeeperRegistryVersion{ "registry_2_0": ethereum.RegistryVersion_2_0, "registry_2_1": ethereum.RegistryVersion_2_1, @@ -636,6 +799,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() + l := logging.GetTestLogger(t) chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "gas-limit", registryVersion, defaultOCRRegistryConfig, false, ) @@ -716,7 +880,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { highCheckGasLimit := automationDefaultRegistryConfig highCheckGasLimit.CheckGasLimit = uint32(5000000) highCheckGasLimit.RegistryVersion = registryVersion - ocrConfig, err := actions.BuildAutoOCR2ConfigVarsLocal(t, nodesWithoutBootstrap, highCheckGasLimit, registrar.Address(), 30*time.Second) + ocrConfig, err := actions.BuildAutoOCR2ConfigVarsLocal(l, nodesWithoutBootstrap, highCheckGasLimit, registrar.Address(), 30*time.Second) require.NoError(t, err, "Error building OCR config") err = registry.SetConfig(highCheckGasLimit, ocrConfig) @@ -738,8 +902,6 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { func TestUpdateCheckData(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) - registryVersions := map[string]ethereum.KeeperRegistryVersion{ "registry_2_0": ethereum.RegistryVersion_2_0, "registry_2_1": ethereum.RegistryVersion_2_1, @@ -750,6 +912,7 @@ func TestUpdateCheckData(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() + l := logging.GetTestLogger(t) chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "update-check-data", registryVersion, defaultOCRRegistryConfig, false, ) @@ -825,12 +988,13 @@ func setupAutomationTestDocker( contracts.KeeperRegistrar, *test_env.CLClusterTestEnv, ) { + l := logging.GetTestLogger(t) // Add registry version to config registryConfig.RegistryVersion = registryVersion network := networks.SelectedNetwork // build the node config - clNodeConfig := node.NewConfig(node.BaseConf) + clNodeConfig := node.NewConfig(node.NewBaseConfig()) syncInterval := models.MustMakeDuration(5 * time.Minute) clNodeConfig.Feature.LogPoller = it_utils.Ptr[bool](true) clNodeConfig.OCR2.Enabled = it_utils.Ptr[bool](true) @@ -843,6 +1007,7 @@ func setupAutomationTestDocker( // launch the environment env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). WithGeth(). WithMockServer(1). WithCLNodes(5). @@ -875,9 +1040,9 @@ func setupAutomationTestDocker( err = linkToken.Transfer(registry.Address(), big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(defaultAmountOfUpkeeps)))) require.NoError(t, err, "Funding keeper registry contract shouldn't fail") - err = actions.CreateOCRKeeperJobsLocal(nodeClients, registry.Address(), network.ChainID, 0, registryVersion) + err = actions.CreateOCRKeeperJobsLocal(l, nodeClients, registry.Address(), network.ChainID, 0, registryVersion) require.NoError(t, err, "Error creating OCR Keeper Jobs") - ocrConfig, err := actions.BuildAutoOCR2ConfigVarsLocal(t, workerNodes, registryConfig, registrar.Address(), 30*time.Second) + ocrConfig, err := actions.BuildAutoOCR2ConfigVarsLocal(l, workerNodes, registryConfig, registrar.Address(), 30*time.Second) require.NoError(t, err, "Error building OCR config vars") err = registry.SetConfig(automationDefaultRegistryConfig, ocrConfig) require.NoError(t, err, "Registry config should be set successfully") diff --git a/integration-tests/smoke/automation_test.go_test_list.json b/integration-tests/smoke/automation_test.go_test_list.json index badb7d6b3eb..d5311641ce7 100644 --- a/integration-tests/smoke/automation_test.go_test_list.json +++ b/integration-tests/smoke/automation_test.go_test_list.json @@ -2,105 +2,51 @@ "tests": [ { "name": "TestAutomationBasic", - "run": [ - { - "name": "registry_2_0" - }, - { - "name": "registry_2_1_conditional" - }, - { - "name": "registry_2_1_logtrigger" - } - ] + "label": "ubuntu20.04-32cores-128GB", + "nodes": 3 + }, + { + "name": "TestSetUpkeepTriggerConfig" }, { "name": "TestAutomationAddFunds", - "run": [ - { - "name": "registry_2_0" - }, - { - "name": "registry_2_1" - } - ] + "label": "ubuntu20.04-32cores-128GB", + "nodes": 2 }, { "name": "TestAutomationPauseUnPause", - "run": [ - { - "name": "registry_2_0" - }, - { - "name": "registry_2_1" - } - ] + "label": "ubuntu20.04-16cores-64GB", + "nodes": 2 }, { "name": "TestAutomationRegisterUpkeep", - "run": [ - { - "name": "registry_2_0" - }, - { - "name": "registry_2_1" - } - ] + "label": "ubuntu20.04-16cores-64GB", + "nodes": 2 }, { "name": "TestAutomationPauseRegistry", - "run": [ - { - "name": "registry_2_0" - }, - { - "name": "registry_2_1" - } - ] + "label": "ubuntu20.04-16cores-64GB", + "nodes": 2 }, { "name": "TestAutomationKeeperNodesDown", - "run": [ - { - "name": "registry_2_0" - }, - { - "name": "registry_2_1" - } - ] + "label": "ubuntu20.04-16cores-64GB", + "nodes": 2 }, { "name": "TestAutomationPerformSimulation", - "run": [ - { - "name": "registry_2_0" - }, - { - "name": "registry_2_1" - } - ] + "label": "ubuntu20.04-16cores-64GB", + "nodes": 2 }, { "name": "TestAutomationCheckPerformGasLimit", - "run": [ - { - "name": "registry_2_0" - }, - { - "name": "registry_2_1" - } - ] + "label": "ubuntu20.04-32cores-128GB", + "nodes": 2 }, { "name": "TestUpdateCheckData", - "run": [ - { - "name": "registry_2_0" - }, - { - "name": "registry_2_1" - } - ] + "label": "ubuntu20.04-32cores-128GB", + "nodes": 2 } ] } diff --git a/integration-tests/smoke/cron_test.go b/integration-tests/smoke/cron_test.go index 0285e2d23c7..717ff8db1e9 100644 --- a/integration-tests/smoke/cron_test.go +++ b/integration-tests/smoke/cron_test.go @@ -8,7 +8,7 @@ import ( "github.com/onsi/gomega" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" @@ -16,16 +16,17 @@ import ( func TestCronBasic(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). WithGeth(). WithMockServer(1). WithCLNodes(1). Build() require.NoError(t, err) t.Cleanup(func() { - if err := env.Cleanup(); err != nil { + if err := env.Cleanup(t); err != nil { l.Error().Err(err).Msg("Error cleaning up test environment") } }) diff --git a/integration-tests/smoke/flux_test.go b/integration-tests/smoke/flux_test.go index c4cd02b857d..ed907e9e460 100644 --- a/integration-tests/smoke/flux_test.go +++ b/integration-tests/smoke/flux_test.go @@ -12,7 +12,7 @@ import ( "github.com/google/uuid" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" @@ -22,16 +22,17 @@ import ( func TestFluxBasic(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). WithGeth(). WithMockServer(1). WithCLNodes(3). Build() require.NoError(t, err) t.Cleanup(func() { - if err := env.Cleanup(); err != nil { + if err := env.Cleanup(t); err != nil { l.Error().Err(err).Msg("Error cleaning up test environment") } }) @@ -93,6 +94,7 @@ func TestFluxBasic(t *testing.T) { fluxSpec := &client.FluxMonitorJobSpec{ Name: fmt.Sprintf("flux-monitor-%s", adapterUUID), ContractAddress: fluxInstance.Address(), + EVMChainID: env.EVMClient.GetChainID().String(), Threshold: 0, AbsoluteThreshold: 0, PollTimerPeriod: 15 * time.Second, // min 15s @@ -105,7 +107,7 @@ func TestFluxBasic(t *testing.T) { // initial value set is performed before jobs creation fluxRoundTimeout := 1 * time.Minute - fluxRound := contracts.NewFluxAggregatorRoundConfirmer(fluxInstance, big.NewInt(1), fluxRoundTimeout) + fluxRound := contracts.NewFluxAggregatorRoundConfirmer(fluxInstance, big.NewInt(1), fluxRoundTimeout, l) env.EVMClient.AddHeaderEventSubscription(fluxInstance.Address(), fluxRound) err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") @@ -122,7 +124,7 @@ func TestFluxBasic(t *testing.T) { require.Equal(t, int64(3), data.AllocatedFunds.Int64(), "Expected allocated funds to be %d, but found %d", int64(3), data.AllocatedFunds.Int64()) - fluxRound = contracts.NewFluxAggregatorRoundConfirmer(fluxInstance, big.NewInt(2), fluxRoundTimeout) + fluxRound = contracts.NewFluxAggregatorRoundConfirmer(fluxInstance, big.NewInt(2), fluxRoundTimeout, l) env.EVMClient.AddHeaderEventSubscription(fluxInstance.Address(), fluxRound) err = env.MockServer.Client.SetValuePath(adapterPath, 1e10) require.NoError(t, err, "Setting value path in mock server shouldn't fail") diff --git a/integration-tests/smoke/forwarder_ocr_test.go b/integration-tests/smoke/forwarder_ocr_test.go index e4cf5cb0527..f0d20e5245c 100644 --- a/integration-tests/smoke/forwarder_ocr_test.go +++ b/integration-tests/smoke/forwarder_ocr_test.go @@ -8,7 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" @@ -16,9 +16,10 @@ import ( func TestForwarderOCRBasic(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). WithGeth(). WithMockServer(1). WithForwarders(). @@ -27,7 +28,7 @@ func TestForwarderOCRBasic(t *testing.T) { Build() require.NoError(t, err) t.Cleanup(func() { - if err := env.Cleanup(); err != nil { + if err := env.Cleanup(t); err != nil { l.Error().Err(err).Msg("Error cleaning up test environment") } }) @@ -54,7 +55,7 @@ func TestForwarderOCRBasic(t *testing.T) { t, operators[i], authorizedForwarders[i], []common.Address{workerNodeAddresses[i]}, env.EVMClient, env.ContractLoader, ) require.NoError(t, err, "Accepting Authorize Receivers on Operator shouldn't fail") - err = actions.TrackForwarderLocal(env.EVMClient, authorizedForwarders[i], workerNodes[i]) + err = actions.TrackForwarderLocal(env.EVMClient, authorizedForwarders[i], workerNodes[i], l) require.NoError(t, err) err = env.EVMClient.WaitForEvents() } @@ -68,9 +69,9 @@ func TestForwarderOCRBasic(t *testing.T) { ) require.NoError(t, err, "Error deploying OCR contracts") - err = actions.CreateOCRJobsWithForwarderLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockServer.Client) + err = actions.CreateOCRJobsWithForwarderLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockServer.Client, env.EVMClient.GetChainID().String()) require.NoError(t, err, "failed to setup forwarder jobs") - err = actions.StartNewRound(1, ocrInstances, env.EVMClient) + err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) require.NoError(t, err) err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") @@ -82,7 +83,7 @@ func TestForwarderOCRBasic(t *testing.T) { err = actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockServer.Client) require.NoError(t, err) - err = actions.StartNewRound(2, ocrInstances, env.EVMClient) + err = actions.StartNewRound(2, ocrInstances, env.EVMClient, l) require.NoError(t, err) err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") diff --git a/integration-tests/smoke/forwarders_ocr2_test.go b/integration-tests/smoke/forwarders_ocr2_test.go index 81c521ff387..2f7c4fa21d9 100644 --- a/integration-tests/smoke/forwarders_ocr2_test.go +++ b/integration-tests/smoke/forwarders_ocr2_test.go @@ -10,7 +10,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" @@ -19,12 +19,13 @@ import ( func TestForwarderOCR2Basic(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). WithGeth(). WithMockServer(1). - WithCLNodeConfig(node.NewConfig(node.BaseConf, + WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), node.WithOCR2(), node.WithP2Pv2(), )). @@ -34,7 +35,7 @@ func TestForwarderOCR2Basic(t *testing.T) { Build() require.NoError(t, err) t.Cleanup(func() { - if err := env.Cleanup(); err != nil { + if err := env.Cleanup(t); err != nil { l.Error().Err(err).Msg("Error cleaning up test environment") } }) @@ -60,7 +61,7 @@ func TestForwarderOCR2Basic(t *testing.T) { for i := range workerNodes { actions.AcceptAuthorizedReceiversOperator(t, operators[i], authorizedForwarders[i], []common.Address{workerNodeAddresses[i]}, env.EVMClient, env.ContractLoader) require.NoError(t, err, "Accepting Authorized Receivers on Operator shouldn't fail") - err = actions.TrackForwarderLocal(env.EVMClient, authorizedForwarders[i], workerNodes[i]) + err = actions.TrackForwarderLocal(env.EVMClient, authorizedForwarders[i], workerNodes[i], l) require.NoError(t, err, "failed to track forwarders") err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") @@ -89,7 +90,7 @@ func TestForwarderOCR2Basic(t *testing.T) { err = actions.ConfigureOCRv2AggregatorContracts(env.EVMClient, ocrv2Config, ocrInstances) require.NoError(t, err, "Error configuring OCRv2 aggregator contracts") - err = actions.StartNewOCR2Round(1, ocrInstances, env.EVMClient, time.Minute*10) + err = actions.StartNewOCR2Round(1, ocrInstances, env.EVMClient, time.Minute*10, l) require.NoError(t, err) answer, err := ocrInstances[0].GetLatestAnswer(context.Background()) @@ -100,7 +101,7 @@ func TestForwarderOCR2Basic(t *testing.T) { ocrRoundVal := (5 + i) % 10 err = env.MockServer.Client.SetValuePath("ocr2", ocrRoundVal) require.NoError(t, err) - err = actions.StartNewOCR2Round(int64(i), ocrInstances, env.EVMClient, time.Minute*10) + err = actions.StartNewOCR2Round(int64(i), ocrInstances, env.EVMClient, time.Minute*10, l) require.NoError(t, err) answer, err = ocrInstances[0].GetLatestAnswer(context.Background()) diff --git a/integration-tests/smoke/keeper_test.go b/integration-tests/smoke/keeper_test.go index f07c42ab3d8..0e4cb7ce041 100644 --- a/integration-tests/smoke/keeper_test.go +++ b/integration-tests/smoke/keeper_test.go @@ -13,7 +13,8 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/integration-tests/actions" @@ -75,17 +76,18 @@ var ( func TestKeeperBasicSmoke(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) registryVersions := []ethereum.KeeperRegistryVersion{ ethereum.RegistryVersion_1_1, ethereum.RegistryVersion_1_2, ethereum.RegistryVersion_1_3, } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) - - for _, registryVersion := range registryVersions { + for _, rv := range registryVersions { + registryVersion := rv t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -99,7 +101,7 @@ func TestKeeperBasicSmoke(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(chainlinkNodes, registry, contracts.OCRv2Config{}) + _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -150,17 +152,18 @@ func TestKeeperBasicSmoke(t *testing.T) { func TestKeeperBlockCountPerTurn(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) registryVersions := []ethereum.KeeperRegistryVersion{ ethereum.RegistryVersion_1_1, ethereum.RegistryVersion_1_2, ethereum.RegistryVersion_1_3, } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) - - for _, registryVersion := range registryVersions { + for _, rv := range registryVersions { + registryVersion := rv t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -174,7 +177,7 @@ func TestKeeperBlockCountPerTurn(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(chainlinkNodes, registry, contracts.OCRv2Config{}) + _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -259,10 +262,12 @@ func TestKeeperSimulation(t *testing.T) { ethereum.RegistryVersion_1_3, } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) - - for _, registryVersion := range registryVersions { + for _, rv := range registryVersions { + registryVersion := rv t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) registry, _, consumersPerformance, upkeepIDs := actions.DeployPerformanceKeeperContracts( t, registryVersion, @@ -280,7 +285,7 @@ func TestKeeperSimulation(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(chainlinkNodes, registry, contracts.OCRv2Config{}) + _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -325,14 +330,16 @@ func TestKeeperSimulation(t *testing.T) { func TestKeeperCheckPerformGasLimit(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) registryVersions := []ethereum.KeeperRegistryVersion{ ethereum.RegistryVersion_1_2, ethereum.RegistryVersion_1_3, } - for _, registryVersion := range registryVersions { + for _, rv := range registryVersions { + registryVersion := rv t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) registry, _, consumersPerformance, upkeepIDs := actions.DeployPerformanceKeeperContracts( t, @@ -351,7 +358,7 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(chainlinkNodes, registry, contracts.OCRv2Config{}) + _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -435,17 +442,18 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { func TestKeeperRegisterUpkeep(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) registryVersions := []ethereum.KeeperRegistryVersion{ ethereum.RegistryVersion_1_1, ethereum.RegistryVersion_1_2, ethereum.RegistryVersion_1_3, } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) - - for _, registryVersion := range registryVersions { + for _, rv := range registryVersions { + registryVersion := rv t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) registry, registrar, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -459,7 +467,7 @@ func TestKeeperRegisterUpkeep(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(chainlinkNodes, registry, contracts.OCRv2Config{}) + _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -529,10 +537,12 @@ func TestKeeperAddFunds(t *testing.T) { ethereum.RegistryVersion_1_3, } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) - - for _, registryVersion := range registryVersions { + for _, rv := range registryVersions { + registryVersion := rv t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -546,7 +556,7 @@ func TestKeeperAddFunds(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(chainlinkNodes, registry, contracts.OCRv2Config{}) + _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -584,17 +594,18 @@ func TestKeeperAddFunds(t *testing.T) { func TestKeeperRemove(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) registryVersions := []ethereum.KeeperRegistryVersion{ ethereum.RegistryVersion_1_1, ethereum.RegistryVersion_1_2, ethereum.RegistryVersion_1_3, } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) - - for _, registryVersion := range registryVersions { + for _, rv := range registryVersions { + registryVersion := rv t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -608,7 +619,7 @@ func TestKeeperRemove(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(chainlinkNodes, registry, contracts.OCRv2Config{}) + _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -667,10 +678,12 @@ func TestKeeperPauseRegistry(t *testing.T) { ethereum.RegistryVersion_1_3, } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) - - for _, registryVersion := range registryVersions { + for _, rv := range registryVersions { + registryVersion := rv t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -684,7 +697,7 @@ func TestKeeperPauseRegistry(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(chainlinkNodes, registry, contracts.OCRv2Config{}) + _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -730,6 +743,7 @@ func TestKeeperPauseRegistry(t *testing.T) { func TestKeeperMigrateRegistry(t *testing.T) { t.Parallel() + l := logging.GetTestLogger(t) chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, @@ -744,7 +758,7 @@ func TestKeeperMigrateRegistry(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(chainlinkNodes, registry, contracts.OCRv2Config{}) + _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -763,7 +777,7 @@ func TestKeeperMigrateRegistry(t *testing.T) { ) // Set the jobs for the second registry - _, err = actions.CreateKeeperJobsLocal(chainlinkNodes, secondRegistry, contracts.OCRv2Config{}) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, secondRegistry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -811,15 +825,17 @@ func TestKeeperMigrateRegistry(t *testing.T) { func TestKeeperNodeDown(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) registryVersions := []ethereum.KeeperRegistryVersion{ ethereum.RegistryVersion_1_1, ethereum.RegistryVersion_1_2, ethereum.RegistryVersion_1_3, } - for _, registryVersion := range registryVersions { + for _, rv := range registryVersions { + registryVersion := rv t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, @@ -834,7 +850,7 @@ func TestKeeperNodeDown(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - jobs, err := actions.CreateKeeperJobsLocal(chainlinkNodes, registry, contracts.OCRv2Config{}) + jobs, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -925,7 +941,7 @@ type nodeAndJob struct { func TestKeeperPauseUnPauseUpkeep(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, @@ -940,7 +956,7 @@ func TestKeeperPauseUnPauseUpkeep(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(chainlinkNodes, registry, contracts.OCRv2Config{}) + _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -1015,7 +1031,7 @@ func TestKeeperPauseUnPauseUpkeep(t *testing.T) { func TestKeeperUpdateCheckData(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) registry, _, performDataChecker, upkeepIDs := actions.DeployPerformDataCheckerContracts( t, @@ -1031,7 +1047,7 @@ func TestKeeperUpdateCheckData(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(chainlinkNodes, registry, contracts.OCRv2Config{}) + _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -1082,16 +1098,17 @@ func setupKeeperTest(t *testing.T) ( contracts.LinkToken, *test_env.CLClusterTestEnv, ) { - clNodeConfig := node.NewConfig(node.BaseConf) + clNodeConfig := node.NewConfig(node.NewBaseConfig()) turnLookBack := int64(0) syncInterval := models.MustMakeDuration(5 * time.Second) performGasOverhead := uint32(150000) clNodeConfig.Keeper.TurnLookBack = &turnLookBack clNodeConfig.Keeper.Registry.SyncInterval = &syncInterval clNodeConfig.Keeper.Registry.PerformGasOverhead = &performGasOverhead - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). WithGeth(). WithMockServer(1). WithCLNodes(5). @@ -1100,7 +1117,7 @@ func setupKeeperTest(t *testing.T) ( Build() require.NoError(t, err, "Error deploying test environment") t.Cleanup(func() { - if err := env.Cleanup(); err != nil { + if err := env.Cleanup(t); err != nil { l.Error().Err(err).Msg("Error cleaning up test environment") } }) diff --git a/integration-tests/smoke/keeper_test.go_test_list.json b/integration-tests/smoke/keeper_test.go_test_list.json index 864dbfdb1cf..dfa2c49358c 100644 --- a/integration-tests/smoke/keeper_test.go_test_list.json +++ b/integration-tests/smoke/keeper_test.go_test_list.json @@ -1,64 +1,52 @@ { "tests": [ { - "name": "TestKeeperBasicSmoke" + "name": "TestKeeperBasicSmoke", + "label": "ubuntu20.04-32cores-128GB", + "nodes": 3 }, { "name": "TestKeeperBlockCountPerTurn", - "run": [ - { - "name": "registry_1_1" - }, - { - "name": "registry_1_2" - }, - { - "name": "registry_1_3" - } - ] + "label": "ubuntu20.04-32cores-128GB", + "nodes": 3 }, { - "name": "TestKeeperSimulation" + "name": "TestKeeperSimulation", + "label": "ubuntu20.04-16cores-64GB", + "nodes": 2 }, { "name": "TestKeeperCheckPerformGasLimit", - "run": [ - { - "name": "registry_1_2" - }, - { - "name": "registry_1_3" - } - ] + "label": "ubuntu20.04-16cores-64GB", + "nodes": 3 }, { - "name": "TestKeeperRegisterUpkeep" + "name": "TestKeeperRegisterUpkeep", + "label": "ubuntu20.04-16cores-64GB", + "nodes": 3 }, { - "name": "TestKeeperAddFunds" + "name": "TestKeeperAddFunds", + "label": "ubuntu20.04-16cores-64GB", + "nodes": 3 }, { - "name": "TestKeeperRemove" + "name": "TestKeeperRemove", + "label": "ubuntu20.04-32cores-128GB", + "nodes": 3 }, { - "name": "TestKeeperPauseRegistry" + "name": "TestKeeperPauseRegistry", + "label": "ubuntu20.04-16cores-64GB", + "nodes": 2 }, { "name": "TestKeeperMigrateRegistry" }, { "name": "TestKeeperNodeDown", - "run": [ - { - "name": "registry_1_1" - }, - { - "name": "registry_1_2" - }, - { - "name": "registry_1_3" - } - ] + "label": "ubuntu20.04-32cores-128GB", + "nodes": 3 }, { "name": "TestKeeperPauseUnPauseUpkeep" diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index 6588586c39d..db11f187f5a 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -16,24 +16,25 @@ import ( "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver" mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" ) // Tests a basic OCRv2 median feed func TestOCRv2Basic(t *testing.T) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). WithGeth(). WithMockServer(1). - WithCLNodeConfig(node.NewConfig(node.BaseConf, + WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), node.WithOCR2(), node.WithP2Pv2(), )). @@ -42,7 +43,7 @@ func TestOCRv2Basic(t *testing.T) { Build() require.NoError(t, err) t.Cleanup(func() { - if err := env.Cleanup(); err != nil { + if err := env.Cleanup(t); err != nil { l.Error().Err(err).Msg("Error cleaning up test environment") } }) @@ -80,7 +81,7 @@ func TestOCRv2Basic(t *testing.T) { err = actions.ConfigureOCRv2AggregatorContracts(env.EVMClient, ocrv2Config, aggregatorContracts) require.NoError(t, err, "Error configuring OCRv2 aggregator contracts") - err = actions.StartNewOCR2Round(1, aggregatorContracts, env.EVMClient, time.Minute*5) + err = actions.StartNewOCR2Round(1, aggregatorContracts, env.EVMClient, time.Minute*5, l) require.NoError(t, err, "Error starting new OCR2 round") roundData, err := aggregatorContracts[0].GetRound(context.Background(), big.NewInt(1)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") @@ -91,7 +92,7 @@ func TestOCRv2Basic(t *testing.T) { err = env.MockServer.Client.SetValuePath("ocr2", 10) require.NoError(t, err) - err = actions.StartNewOCR2Round(2, aggregatorContracts, env.EVMClient, time.Minute*5) + err = actions.StartNewOCR2Round(2, aggregatorContracts, env.EVMClient, time.Minute*5, l) require.NoError(t, err) roundData, err = aggregatorContracts[0].GetRound(context.Background(), big.NewInt(2)) diff --git a/integration-tests/smoke/ocr2vrf_test.go b/integration-tests/smoke/ocr2vrf_test.go index 504750fdafb..c9f689ca7ae 100644 --- a/integration-tests/smoke/ocr2vrf_test.go +++ b/integration-tests/smoke/ocr2vrf_test.go @@ -13,6 +13,8 @@ import ( "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" eth "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/smartcontractkit/chainlink/integration-tests/actions" @@ -21,21 +23,20 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" ) func TestOCR2VRFRedeemModel(t *testing.T) { t.Parallel() t.Skip("VRFv3 is on pause, skipping") - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) testEnvironment, testNetwork := setupOCR2VRFEnvironment(t) if testEnvironment.WillUseRemoteRunner() { return } - chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment) + chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment, l) require.NoError(t, err, "Error connecting to blockchain") - contractDeployer, err := contracts.NewContractDeployer(chainClient) + contractDeployer, err := contracts.NewContractDeployer(chainClient, l) require.NoError(t, err, "Error building contract deployer") chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) require.NoError(t, err, "Error connecting to Chainlink nodes") @@ -89,15 +90,15 @@ func TestOCR2VRFRedeemModel(t *testing.T) { func TestOCR2VRFFulfillmentModel(t *testing.T) { t.Parallel() t.Skip("VRFv3 is on pause, skipping") - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) testEnvironment, testNetwork := setupOCR2VRFEnvironment(t) if testEnvironment.WillUseRemoteRunner() { return } - chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment) + chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment, l) require.NoError(t, err, "Error connecting to blockchain") - contractDeployer, err := contracts.NewContractDeployer(chainClient) + contractDeployer, err := contracts.NewContractDeployer(chainClient, l) require.NoError(t, err, "Error building contract deployer") chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) require.NoError(t, err, "Error connecting to Chainlink nodes") diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index 50d6abe662b..56d045fa097 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" @@ -15,9 +15,10 @@ import ( func TestOCRBasic(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). WithGeth(). WithMockServer(1). WithCLNodes(6). @@ -25,7 +26,7 @@ func TestOCRBasic(t *testing.T) { Build() require.NoError(t, err) t.Cleanup(func() { - if err := env.Cleanup(); err != nil { + if err := env.Cleanup(t); err != nil { l.Error().Err(err).Msg("Error cleaning up test environment") } }) @@ -43,10 +44,10 @@ func TestOCRBasic(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") - err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockServer.Client) + err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockServer.Client, env.EVMClient.GetChainID().String()) require.NoError(t, err) - err = actions.StartNewRound(1, ocrInstances, env.EVMClient) + err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) require.NoError(t, err) answer, err := ocrInstances[0].GetLatestAnswer(context.Background()) @@ -55,7 +56,7 @@ func TestOCRBasic(t *testing.T) { err = actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockServer.Client) require.NoError(t, err) - err = actions.StartNewRound(2, ocrInstances, env.EVMClient) + err = actions.StartNewRound(2, ocrInstances, env.EVMClient, l) require.NoError(t, err) answer, err = ocrInstances[0].GetLatestAnswer(context.Background()) diff --git a/integration-tests/smoke/runlog_test.go b/integration-tests/smoke/runlog_test.go index cd2a099b142..0bfc41eca71 100644 --- a/integration-tests/smoke/runlog_test.go +++ b/integration-tests/smoke/runlog_test.go @@ -11,7 +11,7 @@ import ( "github.com/onsi/gomega" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" @@ -19,9 +19,10 @@ import ( func TestRunLogBasic(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). WithGeth(). WithMockServer(1). WithCLNodes(1). @@ -29,7 +30,7 @@ func TestRunLogBasic(t *testing.T) { Build() require.NoError(t, err) t.Cleanup(func() { - if err := env.Cleanup(); err != nil { + if err := env.Cleanup(t); err != nil { l.Error().Err(err).Msg("Error cleaning up test environment") } }) @@ -68,6 +69,7 @@ func TestRunLogBasic(t *testing.T) { Name: fmt.Sprintf("direct-request-%s", uuid.NewString()), MinIncomingConfirmations: "1", ContractAddress: oracle.Address(), + EVMChainID: env.EVMClient.GetChainID().String(), ExternalJobID: jobUUID.String(), ObservationSource: ost, }) diff --git a/integration-tests/smoke/vrf_test.go b/integration-tests/smoke/vrf_test.go index 0e12b185a6a..47f8cd8e30f 100644 --- a/integration-tests/smoke/vrf_test.go +++ b/integration-tests/smoke/vrf_test.go @@ -11,7 +11,7 @@ import ( "github.com/onsi/gomega" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv1" @@ -21,9 +21,10 @@ import ( func TestVRFBasic(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). WithGeth(). WithMockServer(1). WithCLNodes(1). @@ -31,7 +32,7 @@ func TestVRFBasic(t *testing.T) { Build() require.NoError(t, err) t.Cleanup(func() { - if err := env.Cleanup(); err != nil { + if err := env.Cleanup(t); err != nil { l.Error().Err(err).Msg("Error cleaning up test environment") } }) @@ -66,6 +67,7 @@ func TestVRFBasic(t *testing.T) { MinIncomingConfirmations: 1, PublicKey: pubKeyCompressed, ExternalJobID: jobUUID.String(), + EVMChainID: env.EVMClient.GetChainID().String(), ObservationSource: ost, }) require.NoError(t, err, "Creating VRF Job shouldn't fail") diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index 41f9d2ee5ee..18e9efeae44 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -9,7 +9,7 @@ import ( "github.com/onsi/gomega" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" @@ -20,16 +20,17 @@ import ( func TestVRFv2Basic(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). WithGeth(). WithCLNodes(1). WithFunding(vrfConst.ChainlinkNodeFundingAmountEth). Build() require.NoError(t, err) t.Cleanup(func() { - if err := env.Cleanup(); err != nil { + if err := env.Cleanup(t); err != nil { l.Error().Err(err).Msg("Error cleaning up test environment") } }) diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index 9b6dc5a8626..bec31c5681f 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" @@ -18,16 +18,17 @@ import ( func TestVRFv2PlusBilling(t *testing.T) { t.Parallel() - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). WithGeth(). WithCLNodes(1). WithFunding(vrfv2plus_constants.ChainlinkNodeFundingAmountEth). Build() require.NoError(t, err, "error creating test env") t.Cleanup(func() { - if err := env.Cleanup(); err != nil { + if err := env.Cleanup(t); err != nil { l.Error().Err(err).Msg("Error cleaning up test environment") } }) @@ -109,6 +110,7 @@ func TestVRFv2PlusBilling(t *testing.T) { subNativeTokenBalanceBeforeRequest := subscription.EthBalance jobRunsBeforeTest, err := env.CLNodes[0].API.MustReadRunsByJob(job.Job.Data.ID) + require.NoError(t, err, "error reading job runs") // test and assert err = vrfv2PlusContracts.LoadTestConsumer.RequestRandomness( diff --git a/integration-tests/soak/forwarder_ocr_test.go b/integration-tests/soak/forwarder_ocr_test.go index e8bcea0f5b8..bc02f367892 100644 --- a/integration-tests/soak/forwarder_ocr_test.go +++ b/integration-tests/soak/forwarder_ocr_test.go @@ -5,14 +5,14 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) func TestForwarderOCRSoak(t *testing.T) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) // Use this variable to pass in any custom EVM specific TOML values to your Chainlink nodes customNetworkTOML := `[EVM.Transactions] ForwardersEnabled = true` diff --git a/integration-tests/soak/ocr_test.go b/integration-tests/soak/ocr_test.go index c0fd0a4525f..b2375f13ac2 100644 --- a/integration-tests/soak/ocr_test.go +++ b/integration-tests/soak/ocr_test.go @@ -5,14 +5,14 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) func TestOCRSoak(t *testing.T) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) // Use this variable to pass in any custom EVM specific TOML values to your Chainlink nodes customNetworkTOML := `` // Uncomment below for debugging TOML issues on the node diff --git a/integration-tests/testsetups/don_evm_chain.go b/integration-tests/testsetups/don_evm_chain.go index a9e69b32f49..545d9515801 100644 --- a/integration-tests/testsetups/don_evm_chain.go +++ b/integration-tests/testsetups/don_evm_chain.go @@ -3,6 +3,7 @@ package testsetups import ( "testing" + "github.com/rs/zerolog" "github.com/stretchr/testify/require" e "github.com/smartcontractkit/chainlink-env/environment" @@ -25,6 +26,7 @@ type DonChain struct { LinkTokenContract contracts.LinkToken ChainlinkNodes []*client.ChainlinkK8sClient Mockserver *ctfClient.MockserverClient + l zerolog.Logger } type DonChainConfig struct { @@ -35,10 +37,11 @@ type DonChainConfig struct { ChainlinkValues map[string]interface{} } -func NewDonChain(conf *DonChainConfig) *DonChain { +func NewDonChain(conf *DonChainConfig, logger zerolog.Logger) *DonChain { return &DonChain{ conf: conf, EVMNetwork: conf.EVMNetwork, + l: logger, } } @@ -59,10 +62,10 @@ func (s *DonChain) Deploy() { func (s *DonChain) initializeClients() { var err error network := *s.conf.EVMNetwork - s.EVMClient, err = blockchain.NewEVMClient(network, s.conf.Env) + s.EVMClient, err = blockchain.NewEVMClient(network, s.conf.Env, s.l) require.NoError(s.conf.T, err, "Connecting to blockchain nodes shouldn't fail") - s.ContractDeployer, err = contracts.NewContractDeployer(s.EVMClient) + s.ContractDeployer, err = contracts.NewContractDeployer(s.EVMClient, s.l) require.NoError(s.conf.T, err) s.ChainlinkNodes, err = client.ConnectChainlinkNodes(s.conf.Env) diff --git a/integration-tests/testsetups/keeper_benchmark.go b/integration-tests/testsetups/keeper_benchmark.go index 7e862467266..ba0cc23b23b 100644 --- a/integration-tests/testsetups/keeper_benchmark.go +++ b/integration-tests/testsetups/keeper_benchmark.go @@ -19,8 +19,8 @@ import ( "github.com/smartcontractkit/chainlink-env/environment" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/logging" reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" - "github.com/smartcontractkit/chainlink-testing-framework/utils" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_1" @@ -100,7 +100,7 @@ func NewKeeperBenchmarkTest(inputs KeeperBenchmarkTestInputs) *KeeperBenchmarkTe // Setup prepares contracts for the test func (k *KeeperBenchmarkTest) Setup(t *testing.T, env *environment.Environment) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) startTime := time.Now() k.TestReporter.Summary.StartTime = startTime.UnixMilli() k.ensureInputValues(t) @@ -116,7 +116,7 @@ func (k *KeeperBenchmarkTest) Setup(t *testing.T, env *environment.Environment) var err error // Connect to networks and prepare for contract deployment - k.contractDeployer, err = contracts.NewContractDeployer(k.chainClient) + k.contractDeployer, err = contracts.NewContractDeployer(k.chainClient, l) require.NoError(t, err, "Building a new contract deployer shouldn't fail") k.chainlinkNodes, err = client.ConnectChainlinkNodes(k.env) require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") @@ -202,7 +202,7 @@ func (k *KeeperBenchmarkTest) Setup(t *testing.T, env *environment.Environment) // Run runs the keeper benchmark test func (k *KeeperBenchmarkTest) Run(t *testing.T) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) u := k.Inputs.Upkeeps k.TestReporter.Summary.Load.TotalCheckGasPerBlock = int64(u.NumberOfUpkeeps) * u.CheckGasToBurn k.TestReporter.Summary.Load.TotalPerformGasPerBlock = int64((float64(u.NumberOfUpkeeps) / @@ -246,7 +246,7 @@ func (k *KeeperBenchmarkTest) Run(t *testing.T) { // Give time for OCR nodes to bootstrap time.Sleep(1 * time.Minute) } else { - actions.CreateKeeperJobsWithKeyIndex(t, k.chainlinkNodes, k.keeperRegistries[rIndex], txKeyId, ocrConfig) + actions.CreateKeeperJobsWithKeyIndex(t, k.chainlinkNodes, k.keeperRegistries[rIndex], txKeyId, ocrConfig, k.chainClient.GetChainID().String()) } err = k.chainClient.WaitForEvents() require.NoError(t, err, "Error waiting for registry setConfig") @@ -264,6 +264,7 @@ func (k *KeeperBenchmarkTest) Run(t *testing.T) { &k.TestReporter, int64(index), inputs.Upkeeps.FirstEligibleBuffer, + l, ), ) } @@ -323,7 +324,7 @@ func (k *KeeperBenchmarkTest) subscribeToUpkeepPerformedEvent( metricsReporter *testreporters.KeeperBenchmarkTestReporter, rIndex int, ) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) contractABI, err := keeper_registry_wrapper1_1.KeeperRegistryMetaData.GetAbi() require.NoError(t, err, "Error getting ABI") switch k.Inputs.RegistryVersions[rIndex] { @@ -476,7 +477,7 @@ func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts( t *testing.T, index int, ) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) registryVersion := k.Inputs.RegistryVersions[index] k.Inputs.KeeperRegistrySettings.RegistryVersion = registryVersion upkeep := k.Inputs.Upkeeps @@ -587,7 +588,7 @@ func DeployKeeperConsumersBenchmark( contractDeployer contracts.ContractDeployer, client blockchain.EVMClient, ) contracts.AutomationConsumerBenchmark { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) // Deploy consumer keeperConsumerInstance, err := contractDeployer.DeployKeeperConsumerBenchmark() diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go index 1c210af1174..5f12995cc06 100644 --- a/integration-tests/testsetups/ocr.go +++ b/integration-tests/testsetups/ocr.go @@ -22,7 +22,6 @@ import ( "github.com/kelseyhightower/envconfig" "github.com/pelletier/go-toml/v2" "github.com/rs/zerolog" - "github.com/rs/zerolog/log" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-env/environment" @@ -32,15 +31,16 @@ import ( mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink-testing-framework/logging" reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" - "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" ) @@ -114,7 +114,7 @@ func NewOCRSoakTest(t *testing.T, forwarderFlow bool) (*OCRSoakTest, error) { t: t, startTime: time.Now(), timeLeft: testInputs.TestDuration, - log: utils.GetTestLogger(t), + log: logging.GetTestLogger(t), ocrRoundStates: make([]*testreporters.OCRRoundState, 0), ocrInstanceMap: make(map[string]contracts.OffchainAggregator), } @@ -164,7 +164,7 @@ func (o *OCRSoakTest) LoadEnvironment(chainlinkURLs []string, chainURL, mockServ network = networks.SelectedNetwork err error ) - o.chainClient, err = blockchain.ConnectEVMClient(network) + o.chainClient, err = blockchain.ConnectEVMClient(network, o.log) require.NoError(o.t, err, "Error connecting to EVM client") chainlinkNodes, err := client.ConnectChainlinkNodeURLs(chainlinkURLs) require.NoError(o.t, err, "Error connecting to chainlink nodes") @@ -186,9 +186,9 @@ func (o *OCRSoakTest) Setup() { // Environment currently being used to soak test on // Make connections to soak test resources - o.chainClient, err = blockchain.NewEVMClient(network, o.testEnvironment) + o.chainClient, err = blockchain.NewEVMClient(network, o.testEnvironment, o.log) require.NoError(o.t, err, "Error creating EVM client") - contractDeployer, err := contracts.NewContractDeployer(o.chainClient) + contractDeployer, err := contracts.NewContractDeployer(o.chainClient, o.log) require.NoError(o.t, err, "Unable to create contract deployer") require.NotNil(o.t, contractDeployer, "Contract deployer shouldn't be nil") nodes, err := client.ConnectChainlinkNodes(o.testEnvironment) @@ -206,7 +206,7 @@ func (o *OCRSoakTest) Setup() { require.NoError(o.t, err, "Error funding Chainlink nodes") if o.OperatorForwarderFlow { - contractLoader, err := contracts.NewContractLoader(o.chainClient) + contractLoader, err := contracts.NewContractLoader(o.chainClient, o.log) require.NoError(o.t, err, "Loading contracts shouldn't fail") operators, authorizedForwarders, _ := actions.DeployForwarderContracts( @@ -262,9 +262,9 @@ func (o *OCRSoakTest) Run() { startingValue := 5 if o.OperatorForwarderFlow { - actions.CreateOCRJobsWithForwarder(o.t, o.ocrInstances, o.bootstrapNode, o.workerNodes, startingValue, o.mockServer) + actions.CreateOCRJobsWithForwarder(o.t, o.ocrInstances, o.bootstrapNode, o.workerNodes, startingValue, o.mockServer, o.chainClient.GetChainID().String()) } else { - err := actions.CreateOCRJobs(o.ocrInstances, o.bootstrapNode, o.workerNodes, startingValue, o.mockServer) + err := actions.CreateOCRJobs(o.ocrInstances, o.bootstrapNode, o.workerNodes, startingValue, o.mockServer, o.chainClient.GetChainID().String()) require.NoError(o.t, err, "Error creating OCR jobs") } @@ -384,11 +384,11 @@ func (o *OCRSoakTest) LoadState() error { o.startingBlockNum = testState.StartingBlockNum network := networks.SelectedNetwork - o.chainClient, err = blockchain.ConnectEVMClient(network) + o.chainClient, err = blockchain.ConnectEVMClient(network, o.log) if err != nil { return err } - contractDeployer, err := contracts.NewContractDeployer(o.chainClient) + contractDeployer, err := contracts.NewContractDeployer(o.chainClient, o.log) if err != nil { return err } @@ -423,7 +423,7 @@ func (o *OCRSoakTest) Resume() { StartTime: time.Now(), Message: "Test Resumed", }) - log.Info(). + o.log.Info(). Str("Total Duration", o.Inputs.TestDuration.String()). Str("Time Left", o.timeLeft.String()). Msg("Resuming OCR Soak Test") @@ -446,7 +446,7 @@ func (o *OCRSoakTest) Resume() { o.log.Info().Msg("Test Complete, collecting on-chain events") err = o.collectEvents() - log.Error().Err(err).Interface("Query", o.filterQuery).Msg("Error collecting on-chain events, expect malformed report") + o.log.Error().Err(err).Interface("Query", o.filterQuery).Msg("Error collecting on-chain events, expect malformed report") o.TestReporter.RecordEvents(o.ocrRoundStates, o.testIssues) } @@ -484,7 +484,7 @@ func (o *OCRSoakTest) testLoop(testDuration time.Duration, newValue int) { if err := o.SaveState(); err != nil { o.log.Error().Err(err).Msg("Error saving state") } - log.Warn().Str("Time Taken", time.Since(saveStart).String()).Msg("Saved state") + o.log.Warn().Str("Time Taken", time.Since(saveStart).String()).Msg("Saved state") os.Exit(2) // Exit with code 2 to indicate test was interrupted, not just a normal failure case <-endTest: return @@ -525,7 +525,7 @@ func (o *OCRSoakTest) complete() { err := o.collectEvents() if err != nil { - log.Error().Err(err).Interface("Query", o.filterQuery).Msg("Error collecting on-chain events, expect malformed report") + o.log.Error().Err(err).Interface("Query", o.filterQuery).Msg("Error collecting on-chain events, expect malformed report") } o.TestReporter.RecordEvents(o.ocrRoundStates, o.testIssues) } @@ -543,7 +543,7 @@ func (o *OCRSoakTest) setFilterQuery() { Topics: [][]common.Hash{{contractABI.Events["AnswerUpdated"].ID}}, FromBlock: big.NewInt(0).SetUint64(o.startingBlockNum), } - log.Debug(). + o.log.Debug(). Interface("Addresses", ocrAddresses). Str("Topic", contractABI.Events["AnswerUpdated"].ID.Hex()). Uint64("Starting Block", o.startingBlockNum). @@ -568,7 +568,7 @@ func (o *OCRSoakTest) observeOCREvents() error { case event := <-eventLogs: answerUpdated, err := o.ocrInstances[0].ParseEventAnswerUpdated(event) if err != nil { - log.Warn(). + o.log.Warn(). Err(err). Str("Address", event.Address.Hex()). Uint64("Block Number", event.BlockNumber). @@ -633,18 +633,18 @@ func (o *OCRSoakTest) collectEvents() error { // We must retrieve the events, use exponential backoff for timeout to retry timeout := time.Second * 15 - log.Info().Interface("Filter Query", o.filterQuery).Str("Timeout", timeout.String()).Msg("Retrieving on-chain events") + o.log.Info().Interface("Filter Query", o.filterQuery).Str("Timeout", timeout.String()).Msg("Retrieving on-chain events") ctx, cancel := context.WithTimeout(context.Background(), timeout) contractEvents, err := o.chainClient.FilterLogs(ctx, o.filterQuery) cancel() for err != nil { - log.Info().Interface("Filter Query", o.filterQuery).Str("Timeout", timeout.String()).Msg("Retrieving on-chain events") + o.log.Info().Interface("Filter Query", o.filterQuery).Str("Timeout", timeout.String()).Msg("Retrieving on-chain events") ctx, cancel := context.WithTimeout(context.Background(), timeout) contractEvents, err = o.chainClient.FilterLogs(ctx, o.filterQuery) cancel() if err != nil { - log.Warn().Interface("Filter Query", o.filterQuery).Str("Timeout", timeout.String()).Msg("Error collecting on-chain events, trying again") + o.log.Warn().Interface("Filter Query", o.filterQuery).Str("Timeout", timeout.String()).Msg("Error collecting on-chain events, trying again") timeout *= 2 } } diff --git a/integration-tests/testsetups/vrfv2.go b/integration-tests/testsetups/vrfv2.go index 7afe9cf2cca..cfa26e8f279 100644 --- a/integration-tests/testsetups/vrfv2.go +++ b/integration-tests/testsetups/vrfv2.go @@ -16,8 +16,8 @@ import ( "github.com/smartcontractkit/chainlink-env/environment" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/logging" reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" - "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" @@ -80,7 +80,7 @@ func (v *VRFV2SoakTest) Setup(t *testing.T, env *environment.Environment) { // Run starts the VRFV2 soak test func (v *VRFV2SoakTest) Run(t *testing.T) { - l := utils.GetTestLogger(t) + l := logging.GetTestLogger(t) l.Info(). Str("Test Duration", v.Inputs.TestDuration.Truncate(time.Second).String()). Int("Max number of requests per minute wanted", v.Inputs.RequestsPerMinute). diff --git a/integration-tests/types/config/node/core.go b/integration-tests/types/config/node/core.go index 0d433daa1b4..3702d11745f 100644 --- a/integration-tests/types/config/node/core.go +++ b/integration-tests/types/config/node/core.go @@ -23,8 +23,8 @@ import ( utils2 "github.com/smartcontractkit/chainlink/integration-tests/utils" ) -var ( - BaseConf = &chainlink.Config{ +func NewBaseConfig() *chainlink.Config { + return &chainlink.Config{ Core: toml.Core{ RootDir: utils2.Ptr("/home/chainlink"), Database: toml.Database{ @@ -60,7 +60,7 @@ var ( P2P: toml.P2P{}, }, } -) +} type NodeConfigOpt = func(c *chainlink.Config) diff --git a/plugins/cmd/chainlink-solana/main.go b/plugins/cmd/chainlink-solana/main.go index 9f470355297..df2824fb338 100644 --- a/plugins/cmd/chainlink-solana/main.go +++ b/plugins/cmd/chainlink-solana/main.go @@ -63,13 +63,9 @@ func (c *pluginRelayer) NewRelayer(ctx context.Context, config string, keystore return nil, fmt.Errorf("failed to decode config toml: %w:\n\t%s", err, config) } - // TODO BCF-2605 clean this up when the internal details of Solana Chain construction - // doesn't need `Configs` - cfgAdapter := solana.SolanaConfigs{&cfg.Solana} opts := solana.ChainOpts{ Logger: c.Logger, KeyStore: keystore, - Configs: solana.NewConfigs(cfgAdapter), } chain, err := solana.NewChain(&cfg.Solana, opts) if err != nil { diff --git a/plugins/cmd/chainlink-starknet/main.go b/plugins/cmd/chainlink-starknet/main.go index 433d4408e31..5015f70be2e 100644 --- a/plugins/cmd/chainlink-starknet/main.go +++ b/plugins/cmd/chainlink-starknet/main.go @@ -66,13 +66,9 @@ func (c *pluginRelayer) NewRelayer(ctx context.Context, config string, loopKs lo return nil, fmt.Errorf("failed to decode config toml: %w:\n\t%s", err, config) } - // TODO BCF-2605 clean this up when the internal details of Chain construction - // doesn't need `Configs` - cfgAdapter := starknet.StarknetConfigs{&cfg.Starknet} opts := starknet.ChainOpts{ Logger: c.Logger, KeyStore: loopKs, - Configs: starknet.NewConfigs(cfgAdapter), } chain, err := starknet.NewChain(&cfg.Starknet, opts) diff --git a/testdata/scripts/node/validate/default.txtar b/testdata/scripts/node/validate/default.txtar index 8a678e96cb9..85b16edaa27 100644 --- a/testdata/scripts/node/validate/default.txtar +++ b/testdata/scripts/node/validate/default.txtar @@ -10,7 +10,6 @@ AllowSimplePasswords = false # Input Configuration: # Effective Configuration, with defaults applied: -ExplorerURL = '' InsecureFastScrypt = false RootDir = '~/.chainlink' ShutdownGracePeriod = '5s' diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index 1692480a698..5f02793ff57 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -54,7 +54,6 @@ WSURL = 'wss://foo.bar/ws' HTTPURL = 'https://foo.bar' # Effective Configuration, with defaults applied: -ExplorerURL = '' InsecureFastScrypt = false RootDir = '~/.chainlink' ShutdownGracePeriod = '5s' 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 7f6104afeca..527a739f7ca 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -54,7 +54,6 @@ WSURL = 'wss://foo.bar/ws' HTTPURL = 'https://foo.bar' # Effective Configuration, with defaults applied: -ExplorerURL = '' InsecureFastScrypt = false RootDir = '~/.chainlink' ShutdownGracePeriod = '5s' diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar index e5d5151376e..791a8aad076 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -54,7 +54,6 @@ WSURL = 'wss://foo.bar/ws' HTTPURL = 'https://foo.bar' # Effective Configuration, with defaults applied: -ExplorerURL = '' InsecureFastScrypt = false RootDir = '~/.chainlink' ShutdownGracePeriod = '5s' diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index 974bb507f9a..e9db92fb8f7 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -44,7 +44,6 @@ WSURL = 'wss://foo.bar/ws' HTTPURL = 'https://foo.bar' # Effective Configuration, with defaults applied: -ExplorerURL = '' InsecureFastScrypt = false RootDir = '~/.chainlink' ShutdownGracePeriod = '5s' diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index 0fc036a899c..f48fa1926d8 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -51,7 +51,6 @@ WSURL = 'wss://foo.bar/ws' HTTPURL = 'https://foo.bar' # Effective Configuration, with defaults applied: -ExplorerURL = '' InsecureFastScrypt = false RootDir = '~/.chainlink' ShutdownGracePeriod = '5s' diff --git a/tools/docker/config.toml b/tools/docker/config.toml index 2c21ce008c8..23108ae295c 100644 --- a/tools/docker/config.toml +++ b/tools/docker/config.toml @@ -1,5 +1,3 @@ -ExplorerURL = 'ws://explorer:3001' - [Log] Level = 'info' diff --git a/tools/flakeytests/runner.go b/tools/flakeytests/runner.go index 592b673a23b..28522b2aa70 100644 --- a/tools/flakeytests/runner.go +++ b/tools/flakeytests/runner.go @@ -3,6 +3,8 @@ package flakeytests import ( "bufio" "bytes" + "encoding/json" + "errors" "fmt" "io" "log" @@ -10,13 +12,11 @@ import ( "os/exec" "regexp" "strings" + "time" ) var ( - failedTestRe = regexp.MustCompile(`^--- FAIL: (Test\w+)`) - logPanicRe = regexp.MustCompile(`^panic: Log in goroutine after (Test\w+)`) - - failedPkgRe = regexp.MustCompile(`^FAIL\s+github\.com\/smartcontractkit\/chainlink\/v2\/(\S+)`) + panicRe = regexp.MustCompile(`^panic:`) ) type Runner struct { @@ -53,29 +53,67 @@ func runGoTest(pkg string, tests []string, numReruns int, w io.Writer) error { return cmd.Run() } +type TestEvent struct { + Time time.Time + Action string + Package string + Test string + Elapsed float64 // seconds + Output string +} + +func newEvent(b []byte) (*TestEvent, error) { + e := &TestEvent{} + err := json.Unmarshal(b, e) + if err != nil { + return nil, err + } + + e.Package = strings.Replace(e.Package, "github.com/smartcontractkit/chainlink/v2/", "", -1) + return e, nil + +} + func parseOutput(readers ...io.Reader) (map[string]map[string]int, error) { - testsWithoutPackage := []string{} tests := map[string]map[string]int{} for _, r := range readers { s := bufio.NewScanner(r) for s.Scan() { - t := s.Text() - switch { - case failedTestRe.MatchString(t): - m := failedTestRe.FindStringSubmatch(t) - testsWithoutPackage = append(testsWithoutPackage, m[1]) - case logPanicRe.MatchString(t): - m := logPanicRe.FindStringSubmatch(t) - testsWithoutPackage = append(testsWithoutPackage, m[1]) - case failedPkgRe.MatchString(t): - p := failedPkgRe.FindStringSubmatch(t) - for _, t := range testsWithoutPackage { - if tests[p[1]] == nil { - tests[p[1]] = map[string]int{} + t := s.Bytes() + if len(t) == 0 { + continue + } + + // Skip the line if doesn't start with a "{" -- + // this mean it isn't JSON output. + if !strings.HasPrefix(string(t), "{") { + continue + } + + e, err := newEvent(t) + if err != nil { + return nil, err + } + + // We're only interested in test failures, for which + // both Package and Test would be present. + if e.Package == "" || e.Test == "" { + continue + } + + switch e.Action { + case "fail": + if tests[e.Package] == nil { + tests[e.Package] = map[string]int{} + } + tests[e.Package][e.Test]++ + case "output": + if panicRe.MatchString(e.Output) { + if tests[e.Package] == nil { + tests[e.Package] = map[string]int{} } - tests[p[1]][t]++ + tests[e.Package][e.Test]++ } - testsWithoutPackage = []string{} } } @@ -86,6 +124,10 @@ func parseOutput(readers ...io.Reader) (map[string]map[string]int, error) { return tests, nil } +type exitCoder interface { + ExitCode() int +} + func (r *Runner) runTests(failedTests map[string]map[string]int) (io.Reader, error) { var out bytes.Buffer for pkg, tests := range failedTests { @@ -98,6 +140,13 @@ func (r *Runner) runTests(failedTests map[string]map[string]int) (io.Reader, err err := r.runTestFn(pkg, ts, r.numReruns, &out) if err != nil { log.Printf("Test command errored: %s\n", err) + // There was an error because the command failed with a non-zero + // exit code. This could just mean that the test failed again, so let's + // keep going. + var exErr exitCoder + if errors.As(err, &exErr) && exErr.ExitCode() > 0 { + continue + } return &out, err } } diff --git a/tools/flakeytests/runner_test.go b/tools/flakeytests/runner_test.go index 6560d43e2f9..6c1d1068765 100644 --- a/tools/flakeytests/runner_test.go +++ b/tools/flakeytests/runner_test.go @@ -23,25 +23,7 @@ func newMockReporter() *mockReporter { } func TestParser(t *testing.T) { - output := ` ---- FAIL: TestLink (0.00s) - --- FAIL: TestLink/1.1_link#01 (0.00s) - currencies_test.go:325: - Error Trace: /Users/ccordenier/Development/chainlink/core/assets/currencies_test.go:325 - Error: Not equal: - expected: "1.2 link" - actual : "1.1 link" - - Diff: - --- Expected - +++ Actual - @@ -1 +1 @@ - -1.2 link - +1.1 link - Test: TestLink/1.1_link#01 -FAIL -FAIL github.com/smartcontractkit/chainlink/v2/core/assets 0.338s -FAIL + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} ` r := strings.NewReader(output) @@ -53,65 +35,24 @@ FAIL assert.Equal(t, ts["core/assets"]["TestLink"], 1) } -func TestParser_PanicInTest(t *testing.T) { - output := ` -? github.com/smartcontractkit/chainlink/v2/tools/flakeytests/cmd/runner [no test files] ---- FAIL: TestParser (0.00s) -panic: foo [recovered] - panic: foo - -goroutine 21 [running]: -testing.tRunner.func1.2({0x1009953c0, 0x1009d1e40}) - /opt/homebrew/Cellar/go/1.20.3/libexec/src/testing/testing.go:1526 +0x1c8 -testing.tRunner.func1() - /opt/homebrew/Cellar/go/1.20.3/libexec/src/testing/testing.go:1529 +0x384 -panic({0x1009953c0, 0x1009d1e40}) - /opt/homebrew/Cellar/go/1.20.3/libexec/src/runtime/panic.go:884 +0x204 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests.TestParser(0x0?) - /Users/ccordenier/Development/chainlink/tools/flakeytests/runner_test.go:50 +0xa4 -testing.tRunner(0x14000083520, 0x1009d1588) - /opt/homebrew/Cellar/go/1.20.3/libexec/src/testing/testing.go:1576 +0x10c -created by testing.(*T).Run - /opt/homebrew/Cellar/go/1.20.3/libexec/src/testing/testing.go:1629 +0x368 -FAIL github.com/smartcontractkit/chainlink/v2/tools/flakeytests 0.197s -FAIL` +func TestParser_SkipsNonJSON(t *testing.T) { + output := `Failed tests and panics: +------- +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} +` r := strings.NewReader(output) ts, err := parseOutput(r) require.NoError(t, err) assert.Len(t, ts, 1) - assert.Len(t, ts["tools/flakeytests"], 1) - assert.Equal(t, ts["tools/flakeytests"]["TestParser"], 1) + assert.Len(t, ts["core/assets"], 1) + assert.Equal(t, ts["core/assets"]["TestLink"], 1) } func TestParser_PanicDueToLogging(t *testing.T) { output := ` -panic: Log in goroutine after TestIntegration_LogEventProvider_Backfill has completed: 2023-07-19T10:10:45.925Z WARN KeepersRegistry.LogEventProvider logprovider/provider.go:218 failed to read logs {"version": "2.3.0@d898528", "where": "reader", "err": "fetched logs with errors: context canceled"} - -goroutine 4999 [running]: -testing.(*common).logDepth(0xc0051f6000, {0xc003011960, 0xd3}, 0x3) - /opt/hostedtoolcache/go/1.20.5/x64/src/testing/testing.go:1003 +0x4e7 -testing.(*common).log(...) - /opt/hostedtoolcache/go/1.20.5/x64/src/testing/testing.go:985 -testing.(*common).Logf(0xc0051f6000, {0x21ba777?, 0x41ac8a?}, {0xc00217c330?, 0x1e530c0?, 0x1?}) - /opt/hostedtoolcache/go/1.20.5/x64/src/testing/testing.go:1036 +0x5a -go.uber.org/zap/zaptest.testingWriter.Write({{0x7f4c5c94f018?, 0xc0051f6000?}, 0xa8?}, {0xc003017000?, 0xd4, 0xc00217c320?}) - /home/runner/go/pkg/mod/go.uber.org/zap@v1.24.0/zaptest/logger.go:130 +0xe6 -go.uber.org/zap/zapcore.(*ioCore).Write(0xc0022f60f0, {0x1, {0xc1260b897723e1ca, 0x4bdc75e54, 0x3d56e40}, {0x22e96a1, 0x20}, {0x22c3204, 0x13}, {0x1, ...}, ...}, ...) - /home/runner/go/pkg/mod/go.uber.org/zap@v1.24.0/zapcore/core.go:99 +0xb5 -go.uber.org/zap/zapcore.(*CheckedEntry).Write(0xc001265ba0, {0xc0023ca100, 0x1, 0x2}) - /home/runner/go/pkg/mod/go.uber.org/zap@v1.24.0/zapcore/entry.go:255 +0x1d9 -go.uber.org/zap.(*SugaredLogger).log(0xc00363a008, 0x1, {0x22c3204?, 0x13?}, {0x0?, 0x0?, 0x0?}, {0xc004ea3f80, 0x2, 0x2}) - /home/runner/go/pkg/mod/go.uber.org/zap@v1.24.0/sugar.go:295 +0xee -go.uber.org/zap.(*SugaredLogger).Warnw(...) - /home/runner/go/pkg/mod/go.uber.org/zap@v1.24.0/sugar.go:216 -github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider.(*logEventProvider).startReader(0xc00076d730, {0x2917018?, 0xc0043c4000?}, 0xc003b2a000) - /home/runner/work/chainlink/chainlink/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go:218 +0x29f -created by github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider.(*logEventProvider).Start - /home/runner/work/chainlink/chainlink/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go:108 +0x133 -FAIL github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider 20.380s -FAIL +{"Time":"2023-09-07T16:01:40.649849+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_LinkScanValue","Output":"panic: foo\n"} ` r := strings.NewReader(output) @@ -119,14 +60,24 @@ FAIL require.NoError(t, err) assert.Len(t, ts, 1) - assert.Len(t, ts["core/services/ocr2/plugins/ocr2keeper/evm21/logprovider"], 1) - assert.Equal(t, ts["core/services/ocr2/plugins/ocr2keeper/evm21/logprovider"]["TestIntegration_LogEventProvider_Backfill"], 1) + assert.Len(t, ts["core/assets"], 1) + assert.Equal(t, ts["core/assets"]["TestAssets_LinkScanValue"], 1) } func TestParser_SuccessfulOutput(t *testing.T) { output := ` -? github.com/smartcontractkit/chainlink/v2/tools/flakeytests/cmd/runner [no test files] -ok github.com/smartcontractkit/chainlink/v2/tools/flakeytests 0.320s +{"Time":"2023-09-07T16:22:52.556853+01:00","Action":"start","Package":"github.com/smartcontractkit/chainlink/v2/core/assets"} +{"Time":"2023-09-07T16:22:52.762353+01:00","Action":"run","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString"} +{"Time":"2023-09-07T16:22:52.762456+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString","Output":"=== RUN TestAssets_NewLinkAndString\n"} +{"Time":"2023-09-07T16:22:52.76249+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString","Output":"=== PAUSE TestAssets_NewLinkAndString\n"} +{"Time":"2023-09-07T16:22:52.7625+01:00","Action":"pause","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString"} +{"Time":"2023-09-07T16:22:52.762511+01:00","Action":"cont","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString"} +{"Time":"2023-09-07T16:22:52.762528+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString","Output":"=== CONT TestAssets_NewLinkAndString\n"} +{"Time":"2023-09-07T16:22:52.762546+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString","Output":"--- PASS: TestAssets_NewLinkAndString (0.00s)\n"} +{"Time":"2023-09-07T16:22:52.762557+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString","Elapsed":0} +{"Time":"2023-09-07T16:22:52.762566+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Output":"PASS\n"} +{"Time":"2023-09-07T16:22:52.762955+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Output":"ok \tgithub.com/smartcontractkit/chainlink/v2/core/assets\t0.206s\n"} +{"Time":"2023-09-07T16:22:52.765598+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Elapsed":0.209} ` r := strings.NewReader(output) @@ -136,25 +87,31 @@ ok github.com/smartcontractkit/chainlink/v2/tools/flakeytests 0.320s } func TestRunner_WithFlake(t *testing.T) { + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}` + m := newMockReporter() + r := &Runner{ + numReruns: 2, + readers: []io.Reader{strings.NewReader(output)}, + runTestFn: func(pkg string, testNames []string, numReruns int, w io.Writer) error { + _, err := w.Write([]byte(output)) + return err + }, + parse: parseOutput, + reporter: m, + } + + // This will report a flake since we've mocked the rerun + // to only report one failure (not two as expected). + err := r.Run() + require.NoError(t, err) + assert.Len(t, m.entries, 1) + assert.Equal(t, m.entries["core/assets"], []string{"TestLink"}) +} + +func TestRunner_WithFailedPackage(t *testing.T) { output := ` ---- FAIL: TestLink (0.00s) - --- FAIL: TestLink/1.1_link#01 (0.00s) - currencies_test.go:325: - Error Trace: /Users/ccordenier/Development/chainlink/core/assets/currencies_test.go:325 - Error: Not equal: - expected: "1.2 link" - actual : "1.1 link" - - Diff: - --- Expected - +++ Actual - @@ -1 +1 @@ - -1.2 link - +1.1 link - Test: TestLink/1.1_link#01 -FAIL -FAIL github.com/smartcontractkit/chainlink/v2/core/assets 0.338s -FAIL +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Elapsed":0} ` m := newMockReporter() r := &Runner{ @@ -177,61 +134,11 @@ FAIL } func TestRunner_AllFailures(t *testing.T) { - output := ` ---- FAIL: TestLink (0.00s) - --- FAIL: TestLink/1.1_link#01 (0.00s) - currencies_test.go:325: - Error Trace: /Users/ccordenier/Development/chainlink/core/assets/currencies_test.go:325 - Error: Not equal: - expected: "1.2 link" - actual : "1.1 link" - - Diff: - --- Expected - +++ Actual - @@ -1 +1 @@ - -1.2 link - +1.1 link - Test: TestLink/1.1_link#01 -FAIL -FAIL github.com/smartcontractkit/chainlink/v2/core/assets 0.338s -FAIL -` + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}` rerunOutput := ` ---- FAIL: TestLink (0.00s) - --- FAIL: TestLink/1.1_link#01 (0.00s) - currencies_test.go:325: - Error Trace: /Users/ccordenier/Development/chainlink/core/assets/currencies_test.go:325 - Error: Not equal: - expected: "1.2 link" - actual : "1.1 link" - - Diff: - --- Expected - +++ Actual - @@ -1 +1 @@ - -1.2 link - +1.1 link - Test: TestLink/1.1_link#01 ---- FAIL: TestLink (0.00s) - --- FAIL: TestLink/1.1_link#01 (0.00s) - currencies_test.go:325: - Error Trace: /Users/ccordenier/Development/chainlink/core/assets/currencies_test.go:325 - Error: Not equal: - expected: "1.2 link" - actual : "1.1 link" - - Diff: - --- Expected - +++ Actual - @@ -1 +1 @@ - -1.2 link - +1.1 link - Test: TestLink/1.1_link#01 -FAIL -FAIL github.com/smartcontractkit/chainlink/v2/core/assets 0.315s -FAIL +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} ` m := newMockReporter() r := &Runner{ @@ -251,29 +158,11 @@ FAIL } func TestRunner_RerunSuccessful(t *testing.T) { - output := ` ---- FAIL: TestLink (0.00s) - --- FAIL: TestLink/1.1_link#01 (0.00s) - currencies_test.go:325: - Error Trace: /Users/ccordenier/Development/chainlink/core/assets/currencies_test.go:325 - Error: Not equal: - expected: "1.2 link" - actual : "1.1 link" - - Diff: - --- Expected - +++ Actual - @@ -1 +1 @@ - -1.2 link - +1.1 link - Test: TestLink/1.1_link#01 -FAIL -FAIL github.com/smartcontractkit/chainlink/v2/core/assets 0.338s -FAIL -` + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}` rerunOutput := ` -ok github.com/smartcontractkit/chainlink/v2/core/assets 0.320s +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} ` m := newMockReporter() r := &Runner{ @@ -291,3 +180,76 @@ ok github.com/smartcontractkit/chainlink/v2/core/assets 0.320s require.NoError(t, err) assert.Equal(t, m.entries["core/assets"], []string{"TestLink"}) } + +type exitError struct{} + +func (e *exitError) ExitCode() int { return 1 } + +func (e *exitError) Error() string { return "exit code: 1" } + +func TestRunner_RerunFailsWithNonzeroExitCode(t *testing.T) { + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}` + + rerunOutput := ` +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} +` + m := newMockReporter() + r := &Runner{ + numReruns: 2, + readers: []io.Reader{strings.NewReader(output)}, + runTestFn: func(pkg string, testNames []string, numReruns int, w io.Writer) error { + _, _ = w.Write([]byte(rerunOutput)) + return &exitError{} + }, + parse: parseOutput, + reporter: m, + } + + err := r.Run() + require.NoError(t, err) + assert.Equal(t, m.entries["core/assets"], []string{"TestLink"}) +} + +func TestRunner_RerunWithNonZeroExitCodeDoesntStopCommand(t *testing.T) { + outputs := []io.Reader{ + strings.NewReader(` +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} +`), + strings.NewReader(` +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2","Test":"TestMaybeReservedLinkV2","Elapsed":0} +`), + } + + rerunOutputs := []string{ + ` +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} +`, + ` +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2","Test":"TestMaybeReservedLinkV2","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2","Test":"TestMaybeReservedLinkV2","Elapsed":0} +`, + } + + index := 0 + m := newMockReporter() + r := &Runner{ + numReruns: 2, + readers: outputs, + runTestFn: func(pkg string, testNames []string, numReruns int, w io.Writer) error { + + _, _ = w.Write([]byte(rerunOutputs[index])) + index++ + return &exitError{} + }, + parse: parseOutput, + reporter: m, + } + + err := r.Run() + require.NoError(t, err) + calls := index + assert.Equal(t, 2, calls) + assert.Equal(t, m.entries["core/assets"], []string{"TestLink"}) +}