diff --git a/.github/tracing/README.md b/.github/tracing/README.md index feba31feb65..04f0216e25f 100644 --- a/.github/tracing/README.md +++ b/.github/tracing/README.md @@ -48,4 +48,55 @@ This folder contains the following config files: These config files are for an OTEL collector, grafana Tempo, and a grafana UI instance to run as containers on the same network. `otel-collector-dev.yaml` is the configuration for dev (i.e. your local machine) environments, and forwards traces from the otel collector to the grafana tempo instance on the same network. -`otel-collector-ci.yaml` is the configuration for the CI runs, and exports the trace data to the artifact from the github run. \ No newline at end of file +`otel-collector-ci.yaml` is the configuration for the CI runs, and exports the trace data to the artifact from the github run. + +## Adding Traces to Plugins and to core + +Adding traces requires identifying an observability gap in a related group of code executions or a critical path in your application. This is intuitive for the developer: + +- "What's the flow of component interaction in this distributed system?" +- "What's the behavior of the JobProcessorOne component when jobs with [x, y, z] attributes are processed?" +- "Is this critical path workflow behaving the way we expect?" + +The developer will measure a flow of execution from end to end in one trace. Each logically separate measure of this flow is called a span. Spans have either one or no parent span and multiple children span. The relationship between parent and child spans in agreggate will form a directed acyclic graph. The trace begins at the root of this graph. + +The most trivial application of a span is measuring top level performance in one critical path. There is much more you can do, including creating human readable and timestamped events within a span (useful for monitoring concurrent access to resources), recording errors, linking parent and children spans through large parts of an application, and even extending a span beyond a single process. + +Spans are created by `tracers` and passed through go applications by `Context`s. A tracer must be initialized first. Both core and plugin developers will initialize a tracer from the globally registered trace provider: + +``` +tracer := otel.GetTracerProvider().Tracer("example.com/foo") +``` + +The globally registered tracer provider is available for plugins after they are initialized, and available in core after configuration is processed (`initGlobals`). + +Add spans by: +``` + func interestingFunc() { + // Assuming there is an appropriate parentContext + ctx, span := tracer.Start(parentContext, "hello-span") + defer span.End() + + // do some work to track with hello-span + } +``` +As implied by the example, `span` is a child of its parent span captured by `parentContext`. + + +Note that in certain situations, there are 3rd party libraries that will setup spans. For instance: + +``` +import ( + "github.com/gin-gonic/gin" + "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" +) + +router := gin.Default() +router.Use(otelgin.Middleware("service-name")) +``` + +The developer aligns with best practices when they: +- Start with critical paths +- Measure paths from end to end (Context is wired all the way through) +- Emphasize broadness of measurement over depth +- Use automatic instrumentation if possible \ No newline at end of file diff --git a/.github/workflows/bash-scripts.yml b/.github/workflows/bash-scripts.yml new file mode 100644 index 00000000000..52ce17f1f28 --- /dev/null +++ b/.github/workflows/bash-scripts.yml @@ -0,0 +1,35 @@ +name: Bash Scripts + +on: + pull_request: + +jobs: + changes: + name: detect changes + runs-on: ubuntu-latest + outputs: + bash-scripts-src: ${{ steps.bash-scripts.outputs.src }} + steps: + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 + id: bash-scripts + with: + filters: | + src: + - 'tools/bin/**' + - '.github/workflows/bash-scripts.yml' + shellcheck: + name: ShellCheck Lint + runs-on: ubuntu-latest + needs: [changes] + steps: + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Run ShellCheck + if: needs.changes.outputs.bash-scripts-src == 'true' + uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0 + with: + scandir: "./tools/bin" + # Consider changing this to check for warnings once all warnings are fixed. + severity: error diff --git a/.github/workflows/build-publish-pr.yml b/.github/workflows/build-publish-pr.yml index cdc9cf3f11c..fd5533c1b5b 100644 --- a/.github/workflows/build-publish-pr.yml +++ b/.github/workflows/build-publish-pr.yml @@ -2,8 +2,8 @@ name: "Build and Publish from PR" ## # This workflow builds and publishes a Docker image for Chainlink from a PR. -# It doesn't use an environment, has its own special IAM role, does not sign -# the image, and publishes to a special ECR repo. +# It has its own special IAM role, does not sign the image, and publishes to +# a special ECR repo. ## on: @@ -13,6 +13,7 @@ jobs: build-publish-untrusted: if: ${{ ! startsWith(github.ref_name, 'release/') }} runs-on: ubuntu-20.04 + environment: sdlc permissions: id-token: write contents: read @@ -53,6 +54,51 @@ jobs: dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + - name: Get PR labels + id: pr-labels + env: + GH_TOKEN: ${{ github.token }} + PR_NUMBER: ${{ github.event.number }} + run: | + RESPONSE=$(gh pr view ${PR_NUMBER} --json labels) + # Check if the labels command was successful + if [[ $? -ne 0 ]]; then + echo "Error fetching labels" + exit 1 + fi + echo "RESPONSE=${RESPONSE}" + LABELS=$(echo "$RESPONSE" | jq -r '.labels | map(.name) | join(", ")') + # Check if any labels were found + if [[ -z "${LABELS:-}" ]]; then + echo "No labels found" + else + echo "labels=${LABELS}" | tee -a "${GITHUB_OUTPUT}" + fi + + - name: Setup GAP + if: contains(steps.pr-labels.outputs.labels, 'crib') + uses: smartcontractkit/.github/actions/setup-gap@main + with: + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_PUBLISH_PR_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_ARGO_SAND }} + use-argocd: "true" + argocd-user: ${{ secrets.ARGOCD_USER_SAND }} + argocd-pass: ${{ secrets.ARGOCD_PASS_SAND }} + + # Run an Argo CD sync after the image is built. + - name: Argo CD App Sync + if: contains(steps.pr-labels.outputs.labels, 'crib') + shell: bash + env: + PR_NUMBER: ${{ github.event.number }} + run: | + argocd app sync \ + --plaintext \ + --grpc-web \ + --async \ + "crib-chainlink-${PR_NUMBER}" + - name: Collect Metrics if: always() id: collect-gha-metrics diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index bac6f763892..0d9d2912718 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -50,7 +50,7 @@ jobs: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup node - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 - name: Setup NodeJS uses: ./.github/actions/setup-nodejs with: @@ -97,7 +97,7 @@ jobs: working-directory: ./.github/actions/setup-postgres - name: Store logs artifacts if: always() - uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 + uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 with: name: ${{ matrix.cmd }}_logs path: | @@ -136,7 +136,7 @@ jobs: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup node - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 - name: Setup NodeJS uses: ./.github/actions/setup-nodejs with: @@ -154,7 +154,7 @@ jobs: - name: Setup DB run: ./chainlink.test local db preparetest - name: Load test outputs - uses: actions/download-artifact@v3 + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: path: ./artifacts - name: Build flakey test runner diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8bc066f408c..5b846d8708d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -26,7 +26,7 @@ jobs: - name: Set up Go if: ${{ matrix.language == 'go' }} - uses: actions/setup-go@v4 + uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version-file: 'go.mod' diff --git a/.github/workflows/dependency-check.yml b/.github/workflows/dependency-check.yml index dbf08895757..0143042abd9 100644 --- a/.github/workflows/dependency-check.yml +++ b/.github/workflows/dependency-check.yml @@ -29,7 +29,7 @@ jobs: - name: Set up Go if: needs.changes.outputs.src == 'true' - uses: actions/setup-go@v4 + uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version-file: 'go.mod' id: go diff --git a/.github/workflows/helm-chart-publish.yml b/.github/workflows/helm-chart-publish.yml index 6ea46e6a52d..156268d66b0 100644 --- a/.github/workflows/helm-chart-publish.yml +++ b/.github/workflows/helm-chart-publish.yml @@ -31,7 +31,7 @@ jobs: uses: azure/setup-helm@5119fcb9089d432beecbf79bb2c7915207344b78 # v3.5 - name: Run chart-releaser - uses: helm/chart-releaser-action@be16258da8010256c6e82849661221415f031968 # v1.5.0 + uses: helm/chart-releaser-action@a917fd15b20e8b64b94d9158ad54cd6345335584 # v1.6.0 with: charts_dir: charts config: .github/cr.yaml diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index d505dc26224..0cb5bbc8c3b 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -249,6 +249,16 @@ jobs: runs-on: ${{ matrix.product.os }} name: ETH Smoke Tests ${{ matrix.product.name }} steps: + - name: Collect Metrics + if: needs.changes.outputs.src == 'true' + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: ETH Smoke Tests ${{ matrix.product.name }} + test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' + continue-on-error: true - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: @@ -285,16 +295,6 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: "" - - name: Collect Metrics - if: always() - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 - with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: ETH Smoke Tests ${{ matrix.product.name }} - 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') || github.event_name == 'workflow_dispatch') }} @@ -365,6 +365,16 @@ jobs: runs-on: ${{ matrix.product.os }} name: ETH Smoke Tests ${{ matrix.product.name }}${{ matrix.product.tag_suffix }} steps: + - name: Collect Metrics + if: needs.changes.outputs.src == 'true' + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: ETH Smoke Tests ${{ matrix.product.name }}${{ matrix.product.tag_suffix }} + test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' + continue-on-error: true - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: @@ -477,23 +487,13 @@ jobs: if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' run: | docker logs otel-collector - - name: Collect Metrics - if: always() - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 - with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: ETH Smoke Tests ${{ matrix.product.name }}${{ matrix.product.tag_suffix }} - test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' - continue-on-error: true - name: Permissions on traces if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' run: | ls -l ./integration-tests/smoke/traces - name: Upload Trace Data if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 with: name: trace-data path: ./integration-tests/smoke/traces/trace-data.json diff --git a/.github/workflows/on-demand-log-poller.yml b/.github/workflows/on-demand-log-poller.yml index 42f901ec304..4658e188bac 100644 --- a/.github/workflows/on-demand-log-poller.yml +++ b/.github/workflows/on-demand-log-poller.yml @@ -76,7 +76,7 @@ jobs: with: ref: ${{ env.REF_NAME }} - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version-file: "integration-tests/go.mod" cache: true diff --git a/.github/workflows/on-demand-ocr-soak-test.yml b/.github/workflows/on-demand-ocr-soak-test.yml index a4289dd0129..32e080aafca 100644 --- a/.github/workflows/on-demand-ocr-soak-test.yml +++ b/.github/workflows/on-demand-ocr-soak-test.yml @@ -15,6 +15,7 @@ on: - "CELO_ALFAJORES" - "CELO_MAINNET" - "BASE_GOERLI" + - "BASE_SEPOLIA" - "BASE_MAINNET" - "BSC_MAINNET" - "BSC_TESTNET" diff --git a/.github/workflows/performance-tests.yml b/.github/workflows/performance-tests.yml index 4b6dd1a2280..7b9eef7fccc 100644 --- a/.github/workflows/performance-tests.yml +++ b/.github/workflows/performance-tests.yml @@ -31,7 +31,7 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 - name: Build and Push - uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 + uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 with: context: . file: core/chainlink.Dockerfile @@ -72,7 +72,7 @@ jobs: QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Publish pprof artifacts if: ${{ success() }} - uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 + uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 with: name: pprof_results path: ./integration-tests/performance/logs diff --git a/.github/workflows/solidity-hardhat.yml b/.github/workflows/solidity-hardhat.yml index 129f37c0de6..9301c6f3967 100644 --- a/.github/workflows/solidity-hardhat.yml +++ b/.github/workflows/solidity-hardhat.yml @@ -84,7 +84,7 @@ jobs: - name: Rename coverage run: mv ./contracts/coverage.json ./contracts/coverage-${{ matrix.split.idx }}.json - name: Upload coverage - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 with: name: solidity-coverage-${{ matrix.split.idx }} path: ./contracts/coverage-${{ matrix.split.idx }}.json @@ -110,7 +110,7 @@ jobs: - name: Make coverage directory run: mkdir ./contracts/coverage-reports - name: Download coverage - uses: actions/download-artifact@v3 + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: path: ./contracts/coverage-reports - name: Display structure of downloaded files diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 6c5207e0f05..8eb95f4147c 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -18,7 +18,7 @@ jobs: pull-requests: write steps: - - uses: actions/stale@1160a2240286f5da8ec72b1c0816ce2481aabf84 # v8.0.0 + - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} exempt-all-pr-assignees: true diff --git a/.golangci.yml b/.golangci.yml index f9d06ad471c..3672692f599 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -10,6 +10,9 @@ linters: - misspell - rowserrcheck - errorlint + - unconvert + - sqlclosecheck + - noctx linters-settings: exhaustive: default-signifies-exhaustive: true diff --git a/GNUmakefile b/GNUmakefile index 09b1dfe87a3..a6e886b7f6c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -6,7 +6,7 @@ GO_LDFLAGS := $(shell tools/bin/ldflags) GOFLAGS = -ldflags "$(GO_LDFLAGS)" .PHONY: install -install: operator-ui-autoinstall install-chainlink-autoinstall ## Install chainlink and all its dependencies. +install: install-chainlink-autoinstall ## Install chainlink and all its dependencies. .PHONY: install-git-hooks install-git-hooks: ## Install git hooks. @@ -14,8 +14,6 @@ install-git-hooks: ## Install git hooks. .PHONY: install-chainlink-autoinstall install-chainlink-autoinstall: | pnpmdep gomod install-chainlink ## Autoinstall chainlink. -.PHONY: operator-ui-autoinstall -operator-ui-autoinstall: | operator-ui ## Autoinstall frontend UI. .PHONY: pnpmdep pnpmdep: ## Install solidity contract dependencies through pnpm @@ -44,13 +42,13 @@ godoc: ## Install and run godoc install-chainlink: operator-ui ## Install the chainlink binary. go install $(GOFLAGS) . -chainlink: operator-ui ## Build the chainlink binary. +chainlink: ## Build the chainlink binary. go build $(GOFLAGS) . -chainlink-dev: operator-ui ## Build a dev build of chainlink binary. +chainlink-dev: ## Build a dev build of chainlink binary. go build -tags dev $(GOFLAGS) . -chainlink-test: operator-ui ## Build a test build of chainlink binary. +chainlink-test: ## Build a test build of chainlink binary. go build $(GOFLAGS) . .PHONY: chainlink-local-start diff --git a/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml b/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml index a08c31c2c42..16156ef4ffc 100644 --- a/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml +++ b/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml @@ -4,6 +4,9 @@ kind: Deployment metadata: name: {{ $.Release.Name }}-{{ $cfg.name }} spec: + strategy: + # Need to recreate the pod to deal with lease lock held by old pod. + type: Recreate selector: matchLabels: app: {{ $.Release.Name }} diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index 36a6a1304ae..25c3b9beb35 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -240,7 +240,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Reset(addr // - marks all pending and inflight transactions fatally errored (note: at this point all transactions are either confirmed or fatally errored) // this must not be run while Broadcaster or Confirmer are running func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) abandon(addr ADDR) (err error) { - ctx, cancel := services.StopChan(b.chStop).NewCtx() + ctx, cancel := b.chStop.NewCtx() defer cancel() if err = b.txStore.Abandon(ctx, b.chainID, addr); err != nil { return fmt.Errorf("abandon failed to update txes for key %s: %w", addr.String(), err) diff --git a/contracts/scripts/native_solc_compile_all_vrf b/contracts/scripts/native_solc_compile_all_vrf index 4eed35cf5bc..828ba790510 100755 --- a/contracts/scripts/native_solc_compile_all_vrf +++ b/contracts/scripts/native_solc_compile_all_vrf @@ -90,6 +90,7 @@ compileContract vrf/VRFV2Wrapper.sol compileContract vrf/interfaces/VRFV2WrapperInterface.sol compileContract vrf/VRFV2WrapperConsumerBase.sol compileContract vrf/testhelpers/VRFV2WrapperConsumerExample.sol +compileContract vrf/testhelpers/VRFV2WrapperLoadTestConsumer.sol compileContract vrf/testhelpers/VRFv2Consumer.sol # VRF Consumers and Mocks diff --git a/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol index 9b9dc2d6b7d..b858800d73a 100644 --- a/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol +++ b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol @@ -3,7 +3,9 @@ pragma solidity 0.8.19; import {AutomationCompatibleInterface} from "../interfaces/AutomationCompatibleInterface.sol"; -import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {AccessControl} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/access/AccessControl.sol"; +import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableMap.sol"; +import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol"; import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; import {Pausable} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/security/Pausable.sol"; @@ -33,7 +35,10 @@ interface ILinkAvailable { /// this is a "trusless" upkeep, meaning it does not trust the caller of performUpkeep; /// we could save a fair amount of gas and re-write this upkeep for use with Automation v2.0+, /// which has significantly different trust assumptions -contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationCompatibleInterface { +contract LinkAvailableBalanceMonitor is AccessControl, AutomationCompatibleInterface, Pausable { + using EnumerableMap for EnumerableMap.UintToAddressMap; + using EnumerableSet for EnumerableSet.AddressSet; + event BalanceUpdated(address indexed addr, uint256 oldBalance, uint256 newBalance); event FundsWithdrawn(uint256 amountWithdrawn, address payee); event UpkeepIntervalSet(uint256 oldUpkeepInterval, uint256 newUpkeepInterval); @@ -54,6 +59,7 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp error InvalidUpkeepInterval(uint8 upkeepInterval); error InvalidLinkTokenAddress(address lt); error InvalidWatchList(); + error InvalidChainSelector(); error DuplicateAddress(address duplicate); struct MonitoredAddress { @@ -63,24 +69,49 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp bool isActive; } - IERC20 private immutable LINK_TOKEN; + bytes32 private constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); + bytes32 private constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE"); + uint96 private constant DEFAULT_TOP_UP_AMOUNT_JULES = 9000000000000000000; + uint96 private constant DEFAULT_MIN_BALANCE_JULES = 1000000000000000000; + IERC20 private immutable i_linkToken; + uint256 private s_minWaitPeriodSeconds; uint16 private s_maxPerform; uint16 private s_maxCheck; uint8 private s_upkeepInterval; - address[] private s_watchList; - mapping(address targetAddress => MonitoredAddress targetProperties) internal s_targets; - /// @param linkTokenAddress the LINK token address + /// @notice s_watchList contains all the addresses watched by this monitor + /// @dev It mainly provides the length() function + EnumerableSet.AddressSet private s_watchList; + + /// @notice s_targets contains all the addresses watched by this monitor + /// Each key points to a MonitoredAddress with all the needed metadata + mapping(address targetAddress => MonitoredAddress targetProperties) private s_targets; + + /// @notice s_onRampAddresses represents a list of CCIP onRamp addresses watched on this contract + /// There has to be only one onRamp per dstChainSelector. + /// dstChainSelector is needed as we have to track the live onRamp, and delete the onRamp + /// whenever a new one is deployed with the same dstChainSelector. + EnumerableMap.UintToAddressMap private s_onRampAddresses; + + /// @param admin is the administrator address of this contract + /// @param linkToken the LINK token address + /// @param minWaitPeriodSeconds represents the amount of time that has to wait a contract to be funded + /// @param maxPerform maximum amount of contracts to fund + /// @param maxCheck maximum amount of contracts to check + /// @param upkeepInterval randomizes the check for underfunded contracts constructor( - address linkTokenAddress, + address admin, + IERC20 linkToken, uint256 minWaitPeriodSeconds, uint16 maxPerform, uint16 maxCheck, uint8 upkeepInterval - ) ConfirmedOwner(msg.sender) { - if (linkTokenAddress == address(0)) revert InvalidLinkTokenAddress(linkTokenAddress); - LINK_TOKEN = IERC20(linkTokenAddress); + ) { + _setRoleAdmin(ADMIN_ROLE, ADMIN_ROLE); + _setRoleAdmin(EXECUTOR_ROLE, ADMIN_ROLE); + _grantRole(ADMIN_ROLE, admin); + i_linkToken = linkToken; setMinWaitPeriodSeconds(minWaitPeriodSeconds); setMaxPerform(maxPerform); setMaxCheck(maxCheck); @@ -94,18 +125,31 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp function setWatchList( address[] calldata addresses, uint96[] calldata minBalances, - uint96[] calldata topUpAmounts - ) external onlyOwner { - if (addresses.length != minBalances.length || addresses.length != topUpAmounts.length) { + uint96[] calldata topUpAmounts, + uint64[] calldata dstChainSelectors + ) external onlyAdminOrExecutor { + if ( + addresses.length != minBalances.length || + addresses.length != topUpAmounts.length || + addresses.length != dstChainSelectors.length + ) { revert InvalidWatchList(); } - for (uint256 idx = 0; idx < s_watchList.length; idx++) { - delete s_targets[s_watchList[idx]]; + for (uint256 idx = s_watchList.length(); idx > 0; idx--) { + address member = s_watchList.at(idx - 1); + s_watchList.remove(member); + delete s_targets[member]; + } + // s_onRampAddresses is not the same length as s_watchList, so it has + // to be clean in a separate loop + for (uint256 idx = 0; idx < s_onRampAddresses.length(); idx++) { + (uint256 key, ) = s_onRampAddresses.at(idx); + s_onRampAddresses.remove(key); } for (uint256 idx = 0; idx < addresses.length; idx++) { address targetAddress = addresses[idx]; - if (s_targets[targetAddress].isActive) revert DuplicateAddress(addresses[idx]); - if (addresses[idx] == address(0)) revert InvalidWatchList(); + if (s_targets[targetAddress].isActive) revert DuplicateAddress(targetAddress); + if (targetAddress == address(0)) revert InvalidWatchList(); if (topUpAmounts[idx] == 0) revert InvalidWatchList(); s_targets[targetAddress] = MonitoredAddress({ isActive: true, @@ -113,11 +157,55 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp topUpAmount: topUpAmounts[idx], lastTopUpTimestamp: 0 }); + if (dstChainSelectors[idx] > 0) { + s_onRampAddresses.set(dstChainSelectors[idx], targetAddress); + } + s_watchList.add(targetAddress); } - s_watchList = addresses; emit WatchlistUpdated(); } + /// @notice Adds a new address to the watchlist + /// @param targetAddress the address to be added to the watchlist + /// @param dstChainSelector carries a non-zero value in case the targetAddress is an onRamp, otherwise it carries a 0 + /// @dev this function has to be compatible with the event onRampSet(address, dstChainSelector) emitted by + /// the CCIP router. Important detail to know is this event is also emitted when an onRamp is decomissioned, + /// in which case it will carry the proper dstChainSelector along with the 0x0 address + function addToWatchListOrDecomission(address targetAddress, uint64 dstChainSelector) public onlyAdminOrExecutor { + if (s_targets[targetAddress].isActive) revert DuplicateAddress(targetAddress); + bool onRampExists = s_onRampAddresses.contains(dstChainSelector); + // if targetAddress is an existing onRamp, there's a need of cleaning the previous onRamp associated to this dstChainSelector + // there's no need to remove any other address that's not an onRamp + if (dstChainSelector > 0 && onRampExists) { + address oldAddress = s_onRampAddresses.get(dstChainSelector); + removeFromWatchList(oldAddress); + } + // only add the new address if it's not 0x0 + if (targetAddress != address(0)) { + s_onRampAddresses.set(dstChainSelector, targetAddress); + s_targets[targetAddress] = MonitoredAddress({ + isActive: true, + minBalance: DEFAULT_MIN_BALANCE_JULES, + topUpAmount: DEFAULT_TOP_UP_AMOUNT_JULES, + lastTopUpTimestamp: 0 + }); + s_watchList.add(targetAddress); + } else { + // if the address is 0x0, it means the onRamp has ben decomissioned and has to be cleaned + s_onRampAddresses.remove(dstChainSelector); + } + } + + /// @notice Delete an address from the watchlist and sets the target to inactive + /// @param targetAddress the address to be deleted + function removeFromWatchList(address targetAddress) public onlyAdminOrExecutor returns (bool) { + if (s_watchList.remove(targetAddress)) { + delete s_targets[targetAddress]; + return true; + } + return false; + } + /// @notice Gets a list of proxies that are underfunded, up to the s_maxPerform size /// @dev the function starts at a random index in the list to avoid biasing the first /// addresses in the list over latter ones. @@ -127,7 +215,7 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp function sampleUnderfundedAddresses() public view returns (address[] memory) { uint16 maxPerform = s_maxPerform; uint16 maxCheck = s_maxCheck; - uint256 numTargets = s_watchList.length; + uint256 numTargets = s_watchList.length(); uint256 idx = uint256(blockhash(block.number - (block.number % s_upkeepInterval) - 1)) % numTargets; uint256 numToCheck = numTargets < maxCheck ? numTargets : maxCheck; uint256 numFound = 0; @@ -138,7 +226,7 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp numChecked < numToCheck; (idx, numChecked) = ((idx + 1) % numTargets, numChecked + 1) ) { - address targetAddress = s_watchList[idx]; + address targetAddress = s_watchList.at(idx); target = s_targets[targetAddress]; if (_needsFunding(targetAddress, target.minBalance)) { targetsToFund[numFound] = targetAddress; @@ -156,17 +244,19 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp return targetsToFund; } + /// @notice tries to fund an array of target addresses, checking if they're underfunded in the process + /// @param targetAddresses is an array of contract addresses to be funded in case they're underfunded function topUp(address[] memory targetAddresses) public whenNotPaused { MonitoredAddress memory target; - uint256 localBalance = LINK_TOKEN.balanceOf(address(this)); + uint256 localBalance = i_linkToken.balanceOf(address(this)); for (uint256 idx = 0; idx < targetAddresses.length; idx++) { address targetAddress = targetAddresses[idx]; target = s_targets[targetAddress]; if (localBalance >= target.topUpAmount && _needsFunding(targetAddress, target.minBalance)) { - bool success = LINK_TOKEN.transfer(targetAddress, target.topUpAmount); + bool success = i_linkToken.transfer(targetAddress, target.topUpAmount); if (success) { localBalance -= target.topUpAmount; - target.lastTopUpTimestamp = uint56(block.timestamp); + s_targets[targetAddress].lastTopUpTimestamp = uint56(block.timestamp); emit TopUpSucceeded(targetAddress); } else { emit TopUpFailed(targetAddress); @@ -201,7 +291,9 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp } try target.linkAvailableForPayment() returns (int256 balance) { if ( - balance < int256(minBalance) && addressToCheck.lastTopUpTimestamp + s_minWaitPeriodSeconds <= block.timestamp + balance < int256(minBalance) && + addressToCheck.lastTopUpTimestamp + s_minWaitPeriodSeconds <= block.timestamp && + addressToCheck.isActive ) { return true; } @@ -231,14 +323,14 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp /// @notice Withdraws the contract balance in the LINK token. /// @param amount the amount of the LINK to withdraw /// @param payee the address to pay - function withdraw(uint256 amount, address payable payee) external onlyOwner { + function withdraw(uint256 amount, address payable payee) external onlyAdminOrExecutor { if (payee == address(0)) revert InvalidAddress(payee); - LINK_TOKEN.transfer(payee, amount); + i_linkToken.transfer(payee, amount); emit FundsWithdrawn(amount, payee); } /// @notice Sets the minimum balance for the given target address - function setMinBalance(address target, uint96 minBalance) external onlyOwner { + function setMinBalance(address target, uint96 minBalance) external onlyRole(ADMIN_ROLE) { if (target == address(0)) revert InvalidAddress(target); if (minBalance == 0) revert InvalidMinBalance(minBalance); if (!s_targets[target].isActive) revert InvalidWatchList(); @@ -248,7 +340,7 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp } /// @notice Sets the minimum balance for the given target address - function setTopUpAmount(address target, uint96 topUpAmount) external onlyOwner { + function setTopUpAmount(address target, uint96 topUpAmount) external onlyRole(ADMIN_ROLE) { if (target == address(0)) revert InvalidAddress(target); if (topUpAmount == 0) revert InvalidTopUpAmount(topUpAmount); if (!s_targets[target].isActive) revert InvalidWatchList(); @@ -258,28 +350,28 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp } /// @notice Update s_maxPerform - function setMaxPerform(uint16 maxPerform) public onlyOwner { - s_maxPerform = maxPerform; + function setMaxPerform(uint16 maxPerform) public onlyRole(ADMIN_ROLE) { emit MaxPerformSet(s_maxPerform, maxPerform); + s_maxPerform = maxPerform; } /// @notice Update s_maxCheck - function setMaxCheck(uint16 maxCheck) public onlyOwner { - s_maxCheck = maxCheck; + function setMaxCheck(uint16 maxCheck) public onlyRole(ADMIN_ROLE) { emit MaxCheckSet(s_maxCheck, maxCheck); + s_maxCheck = maxCheck; } /// @notice Sets the minimum wait period (in seconds) for addresses between funding - function setMinWaitPeriodSeconds(uint256 minWaitPeriodSeconds) public onlyOwner { - s_minWaitPeriodSeconds = minWaitPeriodSeconds; + function setMinWaitPeriodSeconds(uint256 minWaitPeriodSeconds) public onlyRole(ADMIN_ROLE) { emit MinWaitPeriodSet(s_minWaitPeriodSeconds, minWaitPeriodSeconds); + s_minWaitPeriodSeconds = minWaitPeriodSeconds; } /// @notice Update s_upkeepInterval - function setUpkeepInterval(uint8 upkeepInterval) public onlyOwner { + function setUpkeepInterval(uint8 upkeepInterval) public onlyRole(ADMIN_ROLE) { if (upkeepInterval > 255) revert InvalidUpkeepInterval(upkeepInterval); - s_upkeepInterval = upkeepInterval; emit UpkeepIntervalSet(s_upkeepInterval, upkeepInterval); + s_upkeepInterval = upkeepInterval; } /// @notice Gets maxPerform @@ -304,7 +396,13 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp /// @notice Gets the list of subscription ids being watched function getWatchList() external view returns (address[] memory) { - return s_watchList; + return s_watchList.values(); + } + + /// @notice Gets the onRamp address with the specified dstChainSelector + function getOnRampAddressAtChainSelector(uint64 dstChainSelector) external view returns (address) { + if (dstChainSelector == 0) revert InvalidChainSelector(); + return s_onRampAddresses.get(dstChainSelector); } /// @notice Gets configuration information for an address on the watchlist @@ -315,13 +413,23 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp return (target.isActive, target.minBalance, target.topUpAmount); } + /// @dev Modifier to make a function callable only by executor role or the + /// admin role. + modifier onlyAdminOrExecutor() { + address sender = _msgSender(); + if (!hasRole(ADMIN_ROLE, sender)) { + _checkRole(EXECUTOR_ROLE, sender); + } + _; + } + /// @notice Pause the contract, which prevents executing performUpkeep - function pause() external onlyOwner { + function pause() external onlyRole(ADMIN_ROLE) { _pause(); } /// @notice Unpause the contract - function unpause() external onlyOwner { + function unpause() external onlyRole(ADMIN_ROLE) { _unpause(); } } diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/access/AccessControl.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/access/AccessControl.sol new file mode 100644 index 00000000000..4e388f9d83d --- /dev/null +++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/access/AccessControl.sol @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol) + +pragma solidity ^0.8.0; + +import "./IAccessControl.sol"; +import "../utils/Context.sol"; +import "../utils/Strings.sol"; +import "../utils/introspection/ERC165.sol"; + +/** + * @dev Contract module that allows children to implement role-based access + * control mechanisms. This is a lightweight version that doesn't allow enumerating role + * members except through off-chain means by accessing the contract event logs. Some + * applications may benefit from on-chain enumerability, for those cases see + * {AccessControlEnumerable}. + * + * Roles are referred to by their `bytes32` identifier. These should be exposed + * in the external API and be unique. The best way to achieve this is by + * using `public constant` hash digests: + * + * ``` + * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); + * ``` + * + * Roles can be used to represent a set of permissions. To restrict access to a + * function call, use {hasRole}: + * + * ``` + * function foo() public { + * require(hasRole(MY_ROLE, msg.sender)); + * ... + * } + * ``` + * + * Roles can be granted and revoked dynamically via the {grantRole} and + * {revokeRole} functions. Each role has an associated admin role, and only + * accounts that have a role's admin role can call {grantRole} and {revokeRole}. + * + * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means + * that only accounts with this role will be able to grant or revoke other + * roles. More complex role relationships can be created by using + * {_setRoleAdmin}. + * + * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to + * grant and revoke this role. Extra precautions should be taken to secure + * accounts that have been granted it. + */ +abstract contract AccessControl is Context, IAccessControl, ERC165 { + struct RoleData { + mapping(address => bool) members; + bytes32 adminRole; + } + + mapping(bytes32 => RoleData) private _roles; + + bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; + + /** + * @dev Modifier that checks that an account has a specific role. Reverts + * with a standardized message including the required role. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + * + * _Available since v4.1._ + */ + modifier onlyRole(bytes32 role) { + _checkRole(role); + _; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) public view virtual override returns (bool) { + return _roles[role].members[account]; + } + + /** + * @dev Revert with a standard message if `_msgSender()` is missing `role`. + * Overriding this function changes the behavior of the {onlyRole} modifier. + * + * Format of the revert message is described in {_checkRole}. + * + * _Available since v4.6._ + */ + function _checkRole(bytes32 role) internal view virtual { + _checkRole(role, _msgSender()); + } + + /** + * @dev Revert with a standard message if `account` is missing `role`. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + */ + function _checkRole(bytes32 role, address account) internal view virtual { + if (!hasRole(role, account)) { + revert( + string( + abi.encodePacked( + "AccessControl: account ", + Strings.toHexString(account), + " is missing role ", + Strings.toHexString(uint256(role), 32) + ) + ) + ); + } + } + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { + return _roles[role].adminRole; + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleGranted} event. + */ + function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _grantRole(role, account); + } + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleRevoked} event. + */ + function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _revokeRole(role, account); + } + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been revoked `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + * + * May emit a {RoleRevoked} event. + */ + function renounceRole(bytes32 role, address account) public virtual override { + require(account == _msgSender(), "AccessControl: can only renounce roles for self"); + + _revokeRole(role, account); + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. Note that unlike {grantRole}, this function doesn't perform any + * checks on the calling account. + * + * May emit a {RoleGranted} event. + * + * [WARNING] + * ==== + * This function should only be called from the constructor when setting + * up the initial roles for the system. + * + * Using this function in any other way is effectively circumventing the admin + * system imposed by {AccessControl}. + * ==== + * + * NOTE: This function is deprecated in favor of {_grantRole}. + */ + function _setupRole(bytes32 role, address account) internal virtual { + _grantRole(role, account); + } + + /** + * @dev Sets `adminRole` as ``role``'s admin role. + * + * Emits a {RoleAdminChanged} event. + */ + function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { + bytes32 previousAdminRole = getRoleAdmin(role); + _roles[role].adminRole = adminRole; + emit RoleAdminChanged(role, previousAdminRole, adminRole); + } + + /** + * @dev Grants `role` to `account`. + * + * Internal function without access restriction. + * + * May emit a {RoleGranted} event. + */ + function _grantRole(bytes32 role, address account) internal virtual { + if (!hasRole(role, account)) { + _roles[role].members[account] = true; + emit RoleGranted(role, account, _msgSender()); + } + } + + /** + * @dev Revokes `role` from `account`. + * + * Internal function without access restriction. + * + * May emit a {RoleRevoked} event. + */ + function _revokeRole(bytes32 role, address account) internal virtual { + if (hasRole(role, account)) { + _roles[role].members[account] = false; + emit RoleRevoked(role, account, _msgSender()); + } + } +} \ No newline at end of file diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/access/IAccessControl.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/access/IAccessControl.sol new file mode 100644 index 00000000000..efb82a3cb5e --- /dev/null +++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/access/IAccessControl.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + +pragma solidity ^0.8.0; + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} \ No newline at end of file diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165.sol new file mode 100644 index 00000000000..c682b07a65b --- /dev/null +++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} \ No newline at end of file diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperLoadTestConsumer.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperLoadTestConsumer.sol new file mode 100644 index 00000000000..5a82d4b0b9d --- /dev/null +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperLoadTestConsumer.sol @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.6; + +import {VRFV2WrapperConsumerBase} from "../VRFV2WrapperConsumerBase.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; +import {VRFV2WrapperInterface} from "../interfaces/VRFV2WrapperInterface.sol"; + +contract VRFV2WrapperLoadTestConsumer is VRFV2WrapperConsumerBase, ConfirmedOwner { + VRFV2WrapperInterface public immutable i_vrfV2Wrapper; + uint256 public s_responseCount; + uint256 public s_requestCount; + uint256 public s_averageFulfillmentInMillions = 0; // in millions for better precision + uint256 public s_slowestFulfillment = 0; + uint256 public s_fastestFulfillment = 999; + uint256 public s_lastRequestId; + // solhint-disable-next-line chainlink-solidity/prefix-storage-variables-with-s-underscore + mapping(uint256 => uint256) internal requestHeights; // requestIds to block number when rand request was made + mapping(uint256 => RequestStatus) /* requestId */ /* requestStatus */ public s_requests; + + event WrappedRequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment); + event WrapperRequestMade(uint256 indexed requestId, uint256 paid); + + struct RequestStatus { + uint256 paid; + bool fulfilled; + uint256[] randomWords; + uint256 requestTimestamp; + uint256 fulfilmentTimestamp; + uint256 requestBlockNumber; + uint256 fulfilmentBlockNumber; + } + + constructor( + address _link, + address _vrfV2Wrapper + ) ConfirmedOwner(msg.sender) VRFV2WrapperConsumerBase(_link, _vrfV2Wrapper) { + i_vrfV2Wrapper = VRFV2WrapperInterface(_vrfV2Wrapper); + } + + function makeRequests( + uint32 _callbackGasLimit, + uint16 _requestConfirmations, + uint32 _numWords, + uint16 _requestCount + ) external onlyOwner { + for (uint16 i = 0; i < _requestCount; i++) { + uint256 requestId = requestRandomness(_callbackGasLimit, _requestConfirmations, _numWords); + s_lastRequestId = requestId; + uint256 requestBlockNumber = ChainSpecificUtil._getBlockNumber(); + uint256 paid = VRF_V2_WRAPPER.calculateRequestPrice(_callbackGasLimit); + s_requests[requestId] = RequestStatus({ + paid: paid, + fulfilled: false, + randomWords: new uint256[](0), + requestTimestamp: block.timestamp, + fulfilmentTimestamp: 0, + requestBlockNumber: requestBlockNumber, + fulfilmentBlockNumber: 0 + }); + s_requestCount++; + requestHeights[requestId] = requestBlockNumber; + emit WrapperRequestMade(requestId, paid); + } + } + + function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { + // solhint-disable-next-line custom-errors + require(s_requests[_requestId].paid > 0, "request not found"); + uint256 fulfilmentBlockNumber = ChainSpecificUtil._getBlockNumber(); + uint256 requestDelay = fulfilmentBlockNumber - requestHeights[_requestId]; + uint256 requestDelayInMillions = requestDelay * 1_000_000; + + if (requestDelay > s_slowestFulfillment) { + s_slowestFulfillment = requestDelay; + } + if (requestDelay < s_fastestFulfillment) { + s_fastestFulfillment = requestDelay; + } + s_averageFulfillmentInMillions = s_responseCount > 0 + ? (s_averageFulfillmentInMillions * s_responseCount + requestDelayInMillions) / (s_responseCount + 1) + : requestDelayInMillions; + + s_responseCount++; + s_requests[_requestId].fulfilled = true; + s_requests[_requestId].randomWords = _randomWords; + s_requests[_requestId].fulfilmentTimestamp = block.timestamp; + s_requests[_requestId].fulfilmentBlockNumber = fulfilmentBlockNumber; + + emit WrappedRequestFulfilled(_requestId, _randomWords, s_requests[_requestId].paid); + } + + function getRequestStatus( + uint256 _requestId + ) + external + view + returns ( + uint256 paid, + bool fulfilled, + uint256[] memory randomWords, + uint256 requestTimestamp, + uint256 fulfilmentTimestamp, + uint256 requestBlockNumber, + uint256 fulfilmentBlockNumber + ) + { + // solhint-disable-next-line custom-errors + require(s_requests[_requestId].paid > 0, "request not found"); + RequestStatus memory request = s_requests[_requestId]; + return ( + request.paid, + request.fulfilled, + request.randomWords, + request.requestTimestamp, + request.fulfilmentTimestamp, + request.requestBlockNumber, + request.fulfilmentBlockNumber + ); + } + + /// @notice withdrawLink withdraws the amount specified in amount to the owner + /// @param amount the amount to withdraw, in juels + function withdrawLink(uint256 amount) external onlyOwner { + LINK.transfer(owner(), amount); + } + + function reset() external { + s_averageFulfillmentInMillions = 0; + s_slowestFulfillment = 0; + s_fastestFulfillment = 999; + s_requestCount = 0; + s_responseCount = 0; + } + + receive() external payable {} +} diff --git a/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts b/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts index 76a3dcfff1b..2627bee34a3 100644 --- a/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts +++ b/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts @@ -26,8 +26,6 @@ const TARGET_PERFORM_GAS_LIMIT = 2_000_000 const TARGET_CHECK_GAS_LIMIT = 3_500_000 // // ////////////////////////////////////////////////////////////////////////////////////////////////// - -const OWNABLE_ERR = 'Only callable by owner' const INVALID_WATCHLIST_ERR = `InvalidWatchList()` const PAUSED_ERR = 'Pausable: paused' @@ -35,7 +33,6 @@ const zeroLINK = ethers.utils.parseEther('0') const oneLINK = ethers.utils.parseEther('1') const twoLINK = ethers.utils.parseEther('2') const fourLINK = ethers.utils.parseEther('4') -const fiveLINK = ethers.utils.parseEther('5') const tenLINK = ethers.utils.parseEther('10') const oneHundredLINK = ethers.utils.parseEther('100') @@ -61,6 +58,7 @@ let directTarget2: MockContract let watchListAddresses: string[] let watchListMinBalances: BigNumber[] let watchListTopUpAmounts: BigNumber[] +let watchListDstChainSelectors: number[] async function assertContractLinkBalances( balance1: BigNumber, @@ -123,6 +121,7 @@ const setup = async () => { ] watchListMinBalances = [oneLINK, oneLINK, oneLINK, twoLINK, twoLINK] watchListTopUpAmounts = [twoLINK, twoLINK, twoLINK, twoLINK, twoLINK] + watchListDstChainSelectors = [1, 2, 3, 4, 5] await proxy1.mock.aggregator.returns(aggregator1.address) await proxy2.mock.aggregator.returns(aggregator2.address) @@ -152,6 +151,7 @@ const setup = async () => { lt = (await ltFactory.deploy()) as LinkToken labm = await labmFactory.deploy( + owner.address, lt.address, minWaitPeriodSeconds, maxPerform, @@ -171,6 +171,7 @@ const setup = async () => { watchListAddresses, watchListMinBalances, watchListTopUpAmounts, + watchListDstChainSelectors, ) await setTx.wait() } @@ -223,6 +224,42 @@ describe('LinkAvailableBalanceMonitor', () => { }) }) + describe('setMaxPerform()', () => { + it('configures the MaxPerform', async () => { + await labm.connect(owner).setMaxPerform(BigNumber.from(100)) + const report = await labm.getMaxPerform() + assert.equal(report.toString(), '100') + }) + + it('is only callable by the owner', async () => { + await expect(labm.connect(stranger).setMaxPerform(100)).to.be.reverted + }) + }) + + describe('setMaxCheck()', () => { + it('configures the MaxCheck', async () => { + await labm.connect(owner).setMaxCheck(BigNumber.from(100)) + const report = await labm.getMaxCheck() + assert.equal(report.toString(), '100') + }) + + it('is only callable by the owner', async () => { + await expect(labm.connect(stranger).setMaxCheck(100)).to.be.reverted + }) + }) + + describe('setUpkeepInterval()', () => { + it('configures the UpkeepInterval', async () => { + await labm.connect(owner).setUpkeepInterval(BigNumber.from(100)) + const report = await labm.getUpkeepInterval() + assert.equal(report.toString(), '100') + }) + + it('is only callable by the owner', async () => { + await expect(labm.connect(stranger).setUpkeepInterval(100)).to.be.reverted + }) + }) + describe('withdraw()', () => { beforeEach(async () => { const tx = await lt.connect(owner).transfer(labm.address, oneLINK) @@ -260,7 +297,7 @@ describe('LinkAvailableBalanceMonitor', () => { it('Should not allow strangers to withdraw', async () => { const tx = labm.connect(stranger).withdraw(oneLINK, owner.address) - await expect(tx).to.be.revertedWith(OWNABLE_ERR) + await expect(tx).to.be.reverted }) }) @@ -274,22 +311,22 @@ describe('LinkAvailableBalanceMonitor', () => { it('Should not allow strangers to pause / unpause', async () => { const pauseTxStranger = labm.connect(stranger).pause() - await expect(pauseTxStranger).to.be.revertedWith(OWNABLE_ERR) + await expect(pauseTxStranger).to.be.reverted const pauseTxOwner = await labm.connect(owner).pause() await pauseTxOwner.wait() const unpauseTxStranger = labm.connect(stranger).unpause() - await expect(unpauseTxStranger).to.be.revertedWith(OWNABLE_ERR) + await expect(unpauseTxStranger).to.be.reverted }) }) - describe('setWatchList() / addToWatchList() / removeFromWatchlist() / getWatchList()', () => { + describe('setWatchList() / addToWatchListOrDecomissionOrDecomission() / removeFromWatchlist() / getWatchList()', () => { const watchAddress1 = randAddr() const watchAddress2 = randAddr() const watchAddress3 = randAddr() beforeEach(async () => { // reset watchlist to empty before running these tests - await labm.connect(owner).setWatchList([], [], []) + await labm.connect(owner).setWatchList([], [], [], []) const watchList = await labm.getWatchList() assert.deepEqual(watchList, []) }) @@ -298,7 +335,7 @@ describe('LinkAvailableBalanceMonitor', () => { // add first watchlist let tx = await labm .connect(owner) - .setWatchList([watchAddress1], [oneLINK], [oneLINK]) + .setWatchList([watchAddress1], [oneLINK], [oneLINK], [0]) let watchList = await labm.getWatchList() assert.deepEqual(watchList[0], watchAddress1) // add more to watchlist @@ -308,6 +345,7 @@ describe('LinkAvailableBalanceMonitor', () => { [watchAddress1, watchAddress2, watchAddress3], [oneLINK, oneLINK, oneLINK], [oneLINK, oneLINK, oneLINK], + [1, 2, 3], ) await tx.wait() watchList = await labm.getWatchList() @@ -322,6 +360,7 @@ describe('LinkAvailableBalanceMonitor', () => { [watchAddress1, watchAddress2, watchAddress1], [oneLINK, oneLINK], [oneLINK, oneLINK], + [1, 2], ) await expect(tx).to.be.revertedWith(errMsg) }) @@ -334,6 +373,7 @@ describe('LinkAvailableBalanceMonitor', () => { [watchAddress1, watchAddress2, watchAddress1], [oneLINK, oneLINK, oneLINK], [oneLINK, oneLINK, oneLINK], + [1, 2, 3], ) await expect(tx).to.be.revertedWith(errMsg) }) @@ -341,8 +381,8 @@ describe('LinkAvailableBalanceMonitor', () => { it('Should not allow strangers to set the watchlist', async () => { const setTxStranger = labm .connect(stranger) - .setWatchList([watchAddress1], [oneLINK], [oneLINK]) - await expect(setTxStranger).to.be.revertedWith(OWNABLE_ERR) + .setWatchList([watchAddress1], [oneLINK], [oneLINK], [0]) + await expect(setTxStranger).to.be.reverted }) it('Should revert if any of the addresses are empty', async () => { @@ -352,9 +392,143 @@ describe('LinkAvailableBalanceMonitor', () => { [watchAddress1, ethers.constants.AddressZero], [oneLINK, oneLINK], [oneLINK, oneLINK], + [1, 2], ) await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) }) + + it('Should allow owner to add multiple addresses with dstChainSelector 0 to the watchlist', async () => { + let tx = await labm + .connect(owner) + .addToWatchListOrDecomission(watchAddress1, 0) + await tx.wait + let watchList = await labm.getWatchList() + assert.deepEqual(watchList[0], watchAddress1) + + tx = await labm + .connect(owner) + .addToWatchListOrDecomission(watchAddress2, 0) + await tx.wait + watchList = await labm.getWatchList() + assert.deepEqual(watchList[0], watchAddress1) + assert.deepEqual(watchList[1], watchAddress2) + + tx = await labm + .connect(owner) + .addToWatchListOrDecomission(watchAddress3, 0) + await tx.wait + watchList = await labm.getWatchList() + assert.deepEqual(watchList[0], watchAddress1) + assert.deepEqual(watchList[1], watchAddress2) + assert.deepEqual(watchList[2], watchAddress3) + }) + + it('Should allow owner to add only one address with an unique non-zero dstChainSelector 0 to the watchlist', async () => { + let tx = await labm + .connect(owner) + .addToWatchListOrDecomission(watchAddress1, 1) + await tx.wait + let watchList = await labm.getWatchList() + assert.deepEqual(watchList[0], watchAddress1) + + // 1 is active + let report = await labm.getAccountInfo(watchAddress1) + assert.isTrue(report.isActive) + + tx = await labm + .connect(owner) + .addToWatchListOrDecomission(watchAddress2, 1) + await tx.wait + watchList = await labm.getWatchList() + assert.deepEqual(watchList[0], watchAddress2) + + // 2 is active, 1 should be false + report = await labm.getAccountInfo(watchAddress2) + assert.isTrue(report.isActive) + report = await labm.getAccountInfo(watchAddress1) + assert.isFalse(report.isActive) + + tx = await labm + .connect(owner) + .addToWatchListOrDecomission(watchAddress3, 1) + await tx.wait + watchList = await labm.getWatchList() + assert.deepEqual(watchList[0], watchAddress3) + + // 3 is active, 1 and 2 should be false + report = await labm.getAccountInfo(watchAddress3) + assert.isTrue(report.isActive) + report = await labm.getAccountInfo(watchAddress2) + assert.isFalse(report.isActive) + report = await labm.getAccountInfo(watchAddress1) + assert.isFalse(report.isActive) + }) + + it('Should not add address 0 to the watchlist', async () => { + await labm + .connect(owner) + .addToWatchListOrDecomission(ethers.constants.AddressZero, 1) + expect(await labm.getWatchList()).to.not.contain( + ethers.constants.AddressZero, + ) + }) + + it('Should not allow stangers to add addresses to the watchlist', async () => { + await expect( + labm.connect(stranger).addToWatchListOrDecomission(watchAddress1, 1), + ).to.be.reverted + }) + + it('Should allow owner to remove addresses from the watchlist', async () => { + let tx = await labm + .connect(owner) + .addToWatchListOrDecomission(watchAddress1, 1) + await tx.wait + let watchList = await labm.getWatchList() + assert.deepEqual(watchList[0], watchAddress1) + let report = await labm.getAccountInfo(watchAddress1) + assert.isTrue(report.isActive) + + // remove address + tx = await labm.connect(owner).removeFromWatchList(watchAddress1) + + // address should be false + report = await labm.getAccountInfo(watchAddress1) + assert.isFalse(report.isActive) + + watchList = await labm.getWatchList() + assert.deepEqual(watchList, []) + }) + + it('Should allow only one address per dstChainSelector', async () => { + // add address1 + await labm.connect(owner).addToWatchListOrDecomission(watchAddress1, 1) + expect(await labm.getWatchList()).to.contain(watchAddress1) + + // add address2 + await labm.connect(owner).addToWatchListOrDecomission(watchAddress2, 1) + + // only address2 has to be in the watchlist + const watchlist = await labm.getWatchList() + expect(watchlist).to.not.contain(watchAddress1) + expect(watchlist).to.contain(watchAddress2) + }) + + it('Should delete the onRamp address on a zero-address with same dstChainSelector', async () => { + // add address1 + await labm.connect(owner).addToWatchListOrDecomission(watchAddress1, 1) + expect(await labm.getWatchList()).to.contain(watchAddress1) + + // simulates an onRampSet(zeroAddress, same dstChainSelector) + await labm + .connect(owner) + .addToWatchListOrDecomission(ethers.constants.AddressZero, 1) + + // address1 should be cleaned + const watchlist = await labm.getWatchList() + expect(watchlist).to.not.contain(watchAddress1) + assert.deepEqual(watchlist, []) + }) }) describe('checkUpkeep() / sampleUnderfundedAddresses() [ @skip-coverage ]', () => { @@ -368,6 +542,7 @@ describe('LinkAvailableBalanceMonitor', () => { watchListAddresses, watchListMinBalances, watchListTopUpAmounts, + watchListDstChainSelectors, ) const [should, payload] = await labm.checkUpkeep('0x') @@ -393,6 +568,7 @@ describe('LinkAvailableBalanceMonitor', () => { [aggregator2.address, directTarget1.address, directTarget2.address], [oneLINK, twoLINK, twoLINK], [oneLINK, oneLINK, oneLINK], + [1, 2, 3], ) // all of them are underfunded, return 3 @@ -441,6 +617,7 @@ describe('LinkAvailableBalanceMonitor', () => { let minBalances: BigNumber[] let topUpAmount: BigNumber[] let aggregators: MockContract[] + let dstChainSelectors: number[] beforeEach(async () => { MAX_PERFORM = await labm.getMaxPerform() @@ -449,6 +626,7 @@ describe('LinkAvailableBalanceMonitor', () => { minBalances = [] topUpAmount = [] aggregators = [] + dstChainSelectors = [] const numAggregators = MAX_CHECK + 50 for (let idx = 0; idx < numAggregators; idx++) { const proxy = await deployMockContract( @@ -465,8 +643,14 @@ describe('LinkAvailableBalanceMonitor', () => { minBalances.push(oneLINK) topUpAmount.push(oneLINK) aggregators.push(aggregator) + dstChainSelectors.push(0) } - await labm.setWatchList(proxyAddresses, minBalances, topUpAmount) + await labm.setWatchList( + proxyAddresses, + minBalances, + topUpAmount, + dstChainSelectors, + ) let watchlist = await labm.getWatchList() expect(watchlist).to.deep.equalInAnyOrder(proxyAddresses) assert.equal(watchlist.length, minBalances.length) @@ -521,6 +705,7 @@ describe('LinkAvailableBalanceMonitor', () => { watchListAddresses, watchListMinBalances, watchListTopUpAmounts, + watchListDstChainSelectors, ) }) @@ -563,6 +748,7 @@ describe('LinkAvailableBalanceMonitor', () => { const proxyAddresses = [] const minBalances = [] const topUpAmount = [] + const dstChainSelectors = [] for (let idx = 0; idx < MAX_PERFORM; idx++) { const proxy = await deployMockContract( owner, @@ -577,8 +763,14 @@ describe('LinkAvailableBalanceMonitor', () => { proxyAddresses.push(proxy.address) minBalances.push(oneLINK) topUpAmount.push(oneLINK) + dstChainSelectors.push(0) } - await labm.setWatchList(proxyAddresses, minBalances, topUpAmount) + await labm.setWatchList( + proxyAddresses, + minBalances, + topUpAmount, + dstChainSelectors, + ) let watchlist = await labm.getWatchList() expect(watchlist).to.deep.equalInAnyOrder(proxyAddresses) assert.equal(watchlist.length, minBalances.length) @@ -691,6 +883,7 @@ describe('LinkAvailableBalanceMonitor', () => { [proxy1.address, directTarget1.address], [oneLINK, oneLINK], [oneLINK, oneLINK], + [1, 2], ) const tx = await labm .connect(keeperRegistry) @@ -728,6 +921,7 @@ describe('LinkAvailableBalanceMonitor', () => { [proxy1.address, proxy4.address], [oneLINK, oneLINK], [oneLINK, oneLINK], + [1, 2], ) const tx = await labm .connect(keeperRegistry) @@ -746,6 +940,7 @@ describe('LinkAvailableBalanceMonitor', () => { [proxy1.address, proxy4.address], [oneLINK, oneLINK], [oneLINK, oneLINK], + [1, 2], ) const tx = await labm .connect(keeperRegistry) @@ -765,6 +960,7 @@ describe('LinkAvailableBalanceMonitor', () => { [proxy1.address, proxy4.address], [oneLINK, oneLINK], [oneLINK, oneLINK], + [1, 2], ) const tx = await labm .connect(keeperRegistry) @@ -783,6 +979,7 @@ describe('LinkAvailableBalanceMonitor', () => { [proxy1.address, directTarget1.address], [oneLINK, oneLINK], [oneLINK, oneLINK], + [1, 2], ) const tx = await labm .connect(keeperRegistry) diff --git a/core/bridges/orm.go b/core/bridges/orm.go index cfad1da836e..8ae6b855c88 100644 --- a/core/bridges/orm.go +++ b/core/bridges/orm.go @@ -150,6 +150,7 @@ func (o *orm) CreateBridgeType(bt *BridgeType) error { if err != nil { return err } + defer stmt.Close() return stmt.Get(bt, bt) }) if err == nil { @@ -222,6 +223,7 @@ func (o *orm) CreateExternalInitiator(externalInitiator *ExternalInitiator) (err if err != nil { return errors.Wrap(err, "failed to prepare named stmt") } + defer stmt.Close() return errors.Wrap(stmt.Get(externalInitiator, externalInitiator), "failed to load external_initiator") }) return errors.Wrap(err, "CreateExternalInitiator failed") diff --git a/core/chains/evm/client/node_lifecycle_test.go b/core/chains/evm/client/node_lifecycle_test.go index f097c2bc078..0fcaf54ae3d 100644 --- a/core/chains/evm/client/node_lifecycle_test.go +++ b/core/chains/evm/client/node_lifecycle_test.go @@ -556,7 +556,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { return }) - iN := NewNode(cfg, time.Duration(time.Second), logger.Test(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) + iN := NewNode(cfg, time.Second, logger.Test(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) n := iN.(*node) dial(t, n) diff --git a/core/chains/evm/config/config_test.go b/core/chains/evm/config/config_test.go index 0127328239a..cd1967b9582 100644 --- a/core/chains/evm/config/config_test.go +++ b/core/chains/evm/config/config_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + configurl "github.com/smartcontractkit/chainlink-common/pkg/config" commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" @@ -21,7 +22,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func TestChainScopedConfig(t *testing.T) { @@ -70,7 +70,7 @@ func TestChainScopedConfig(t *testing.T) { ChainID: id, Chain: toml.Defaults(id, &toml.Chain{ GasEstimator: toml.GasEstimator{ - BumpTxDepth: ptr(uint32(override)), + BumpTxDepth: ptr(override), }, }), } @@ -383,8 +383,8 @@ func Test_chainScopedConfig_Validate(t *testing.T) { c.EVM[0] = &toml.EVMConfig{ChainID: chainID, Enabled: ptr(true), Chain: toml.Defaults(chainID, chains...), Nodes: toml.EVMNodes{{ Name: ptr("fake"), - WSURL: models.MustParseURL("wss://foo.test/ws"), - HTTPURL: models.MustParseURL("http://foo.test"), + WSURL: configurl.MustParseURL("wss://foo.test/ws"), + HTTPURL: configurl.MustParseURL("http://foo.test"), }}} }) } diff --git a/core/chains/evm/config/toml/config.go b/core/chains/evm/config/toml/config.go index 292db56f817..2348e648696 100644 --- a/core/chains/evm/config/toml/config.go +++ b/core/chains/evm/config/toml/config.go @@ -22,7 +22,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) type HasEVMConfigs interface { @@ -351,12 +350,12 @@ type Chain struct { FlagsContractAddress *ethkey.EIP55Address LinkContractAddress *ethkey.EIP55Address LogBackfillBatchSize *uint32 - LogPollInterval *models.Duration + LogPollInterval *commonconfig.Duration LogKeepBlocksDepth *uint32 MinIncomingConfirmations *uint32 MinContractPayment *commonassets.Link NonceAutoSync *bool - NoNewHeadsThreshold *models.Duration + NoNewHeadsThreshold *commonconfig.Duration OperatorFactoryAddress *ethkey.EIP55Address RPCDefaultBatchSize *uint32 RPCBlockQueryDelay *uint16 @@ -381,7 +380,7 @@ func (c *Chain) ValidateConfig() (err error) { Msg: config.ErrInvalidChainType.Error()}) } - if c.GasEstimator.BumpTxDepth != nil && uint32(*c.GasEstimator.BumpTxDepth) > *c.Transactions.MaxInFlight { + if c.GasEstimator.BumpTxDepth != nil && *c.GasEstimator.BumpTxDepth > *c.Transactions.MaxInFlight { err = multierr.Append(err, commonconfig.ErrInvalid{Name: "GasEstimator.BumpTxDepth", Value: *c.GasEstimator.BumpTxDepth, Msg: "must be less than or equal to Transactions.MaxInFlight"}) } @@ -404,9 +403,9 @@ type Transactions struct { ForwardersEnabled *bool MaxInFlight *uint32 MaxQueued *uint32 - ReaperInterval *models.Duration - ReaperThreshold *models.Duration - ResendAfterThreshold *models.Duration + ReaperInterval *commonconfig.Duration + ReaperThreshold *commonconfig.Duration + ResendAfterThreshold *commonconfig.Duration } func (t *Transactions) setFrom(f *Transactions) { @@ -669,7 +668,7 @@ func (e *KeySpecificGasEstimator) setFrom(f *KeySpecificGasEstimator) { type HeadTracker struct { HistoryDepth *uint32 MaxBufferSize *uint32 - SamplingInterval *models.Duration + SamplingInterval *commonconfig.Duration } func (t *HeadTracker) setFrom(f *HeadTracker) { @@ -686,10 +685,10 @@ func (t *HeadTracker) setFrom(f *HeadTracker) { type NodePool struct { PollFailureThreshold *uint32 - PollInterval *models.Duration + PollInterval *commonconfig.Duration SelectionMode *string SyncThreshold *uint32 - LeaseDuration *models.Duration + LeaseDuration *commonconfig.Duration } func (p *NodePool) setFrom(f *NodePool) { @@ -712,11 +711,11 @@ func (p *NodePool) setFrom(f *NodePool) { type OCR struct { ContractConfirmations *uint16 - ContractTransmitterTransmitTimeout *models.Duration - DatabaseTimeout *models.Duration - DeltaCOverride *models.Duration - DeltaCJitterOverride *models.Duration - ObservationGracePeriod *models.Duration + ContractTransmitterTransmitTimeout *commonconfig.Duration + DatabaseTimeout *commonconfig.Duration + DeltaCOverride *commonconfig.Duration + DeltaCJitterOverride *commonconfig.Duration + ObservationGracePeriod *commonconfig.Duration } func (o *OCR) setFrom(f *OCR) { @@ -742,8 +741,8 @@ func (o *OCR) setFrom(f *OCR) { type Node struct { Name *string - WSURL *models.URL - HTTPURL *models.URL + WSURL *commonconfig.URL + HTTPURL *commonconfig.URL SendOnly *bool Order *int32 } diff --git a/core/chains/evm/forwarders/forwarder_manager.go b/core/chains/evm/forwarders/forwarder_manager.go index 03792966fef..cabedf79aee 100644 --- a/core/chains/evm/forwarders/forwarder_manager.go +++ b/core/chains/evm/forwarders/forwarder_manager.go @@ -236,7 +236,7 @@ func (f *FwdMgr) runLoop() { defer f.wg.Done() tick := time.After(0) - for ; ; tick = time.After(utils.WithJitter(time.Duration(time.Minute))) { + for ; ; tick = time.After(utils.WithJitter(time.Minute)) { select { case <-tick: if err := f.logpoller.Ready(); err != nil { diff --git a/core/chains/evm/headtracker/head_broadcaster_test.go b/core/chains/evm/headtracker/head_broadcaster_test.go index eb4daa6fde4..dcbb9bd0396 100644 --- a/core/chains/evm/headtracker/head_broadcaster_test.go +++ b/core/chains/evm/headtracker/head_broadcaster_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" @@ -26,7 +27,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func waitHeadBroadcasterToStart(t *testing.T, hb types.HeadBroadcaster) { @@ -46,7 +46,7 @@ func TestHeadBroadcaster_Subscribe(t *testing.T) { g := gomega.NewWithT(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].HeadTracker.SamplingInterval = &models.Duration{} + c.EVM[0].HeadTracker.SamplingInterval = &commonconfig.Duration{} }) evmCfg := evmtest.NewChainScopedConfig(t, cfg) db := pgtest.NewSqlxDB(t) diff --git a/core/chains/evm/headtracker/head_listener_test.go b/core/chains/evm/headtracker/head_listener_test.go index 8bb761bdfaa..3ba9c0863da 100644 --- a/core/chains/evm/headtracker/head_listener_test.go +++ b/core/chains/evm/headtracker/head_listener_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" @@ -21,7 +22,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func Test_HeadListener_HappyPath(t *testing.T) { @@ -39,7 +39,7 @@ func Test_HeadListener_HappyPath(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { // no need to test head timeouts here - c.EVM[0].NoNewHeadsThreshold = &models.Duration{} + c.EVM[0].NoNewHeadsThreshold = &commonconfig.Duration{} }) evmcfg := evmtest.NewChainScopedConfig(t, cfg) chStop := make(chan struct{}) @@ -100,7 +100,7 @@ func Test_HeadListener_NotReceivingHeads(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].NoNewHeadsThreshold = models.MustNewDuration(time.Second) + c.EVM[0].NoNewHeadsThreshold = commonconfig.MustNewDuration(time.Second) }) evmcfg := evmtest.NewChainScopedConfig(t, cfg) chStop := make(chan struct{}) diff --git a/core/chains/evm/headtracker/head_tracker_test.go b/core/chains/evm/headtracker/head_tracker_test.go index 38cbe1fbfe4..22e931d6d0f 100644 --- a/core/chains/evm/headtracker/head_tracker_test.go +++ b/core/chains/evm/headtracker/head_tracker_test.go @@ -20,6 +20,7 @@ import ( "github.com/jmoiron/sqlx" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" @@ -38,7 +39,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func firstHead(t *testing.T, db *sqlx.DB) (h evmtypes.Head) { @@ -426,7 +426,7 @@ func TestHeadTracker_SwitchesToLongestChainWithHeadSamplingEnabled(t *testing.T) c.EVM[0].FinalityDepth = ptr[uint32](50) // Need to set the buffer to something large since we inject a lot of heads at once and otherwise they will be dropped c.EVM[0].HeadTracker.MaxBufferSize = ptr[uint32](100) - c.EVM[0].HeadTracker.SamplingInterval = models.MustNewDuration(2500 * time.Millisecond) + c.EVM[0].HeadTracker.SamplingInterval = commonconfig.MustNewDuration(2500 * time.Millisecond) }) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -554,7 +554,7 @@ func TestHeadTracker_SwitchesToLongestChainWithHeadSamplingDisabled(t *testing.T c.EVM[0].FinalityDepth = ptr[uint32](50) // Need to set the buffer to something large since we inject a lot of heads at once and otherwise they will be dropped c.EVM[0].HeadTracker.MaxBufferSize = ptr[uint32](100) - c.EVM[0].HeadTracker.SamplingInterval = models.MustNewDuration(0) + c.EVM[0].HeadTracker.SamplingInterval = commonconfig.MustNewDuration(0) }) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) diff --git a/core/chains/evm/log/broadcaster.go b/core/chains/evm/log/broadcaster.go index 55a53211fc9..8321dd30bfe 100644 --- a/core/chains/evm/log/broadcaster.go +++ b/core/chains/evm/log/broadcaster.go @@ -564,7 +564,7 @@ func (b *broadcaster) onNewHeads() { b.lastSeenHeadNumber.Store(latestHead.Number) - keptLogsDepth := uint32(b.config.FinalityDepth()) + keptLogsDepth := b.config.FinalityDepth() if b.registrations.highestNumConfirmations > keptLogsDepth { keptLogsDepth = b.registrations.highestNumConfirmations } diff --git a/core/chains/evm/log/eth_subscriber.go b/core/chains/evm/log/eth_subscriber.go index 2f9cbb07cb3..ff20a6e74e8 100644 --- a/core/chains/evm/log/eth_subscriber.go +++ b/core/chains/evm/log/eth_subscriber.go @@ -131,7 +131,7 @@ func (sub *ethSubscriber) backfillLogs(fromBlockOverride null.Int64, addresses [ return true } - sub.logger.Infow(fmt.Sprintf("LogBroadcaster: Fetched a batch of %v logs from %v to %v%s", len(batchLogs), from, to, elapsedMessage), "len", len(batchLogs), "fromBlock", from, "toBlock", to, "remaining", int64(latestHeight)-to) + sub.logger.Infow(fmt.Sprintf("LogBroadcaster: Fetched a batch of %v logs from %v to %v%s", len(batchLogs), from, to, elapsedMessage), "len", len(batchLogs), "fromBlock", from, "toBlock", to, "remaining", latestHeight-to) select { case <-sub.chStop: diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index f82cec62b74..7006c1762ef 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -1060,7 +1060,7 @@ func (lp *logPoller) GetBlocksRange(ctx context.Context, numbers []uint64, qopts qopts = append(qopts, pg.WithParentCtx(ctx)) minRequestedBlock := int64(mathutil.Min(numbers[0], numbers[1:]...)) maxRequestedBlock := int64(mathutil.Max(numbers[0], numbers[1:]...)) - lpBlocks, err := lp.orm.GetBlocksRange(int64(minRequestedBlock), int64(maxRequestedBlock), qopts...) + lpBlocks, err := lp.orm.GetBlocksRange(minRequestedBlock, maxRequestedBlock, qopts...) if err != nil { lp.lggr.Warnw("Error while retrieving blocks from log pollers blocks table. Falling back to RPC...", "requestedBlocks", numbers, "err", err) } else { diff --git a/core/chains/evm/logpoller/log_poller_test.go b/core/chains/evm/logpoller/log_poller_test.go index 81d1b74e42d..4bfc403e341 100644 --- a/core/chains/evm/logpoller/log_poller_test.go +++ b/core/chains/evm/logpoller/log_poller_test.go @@ -20,7 +20,6 @@ import ( "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" - "github.com/lib/pq" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -39,7 +38,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) @@ -1325,61 +1323,6 @@ func TestLogPoller_DBErrorHandling(t *testing.T) { assert.Contains(t, logMsgs, "Backup log poller ran before filters loaded, skipping") } -func TestNotifyAfterInsert(t *testing.T) { - t.Parallel() - - // Use a non-transactional db for this test because notify events - // are not delivered until the transaction is committed. - var dbURL string - _, sqlxDB := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { - dbURL = s.Database.URL.URL().String() - }) - - lggr, _ := logger.TestObserved(t, zapcore.WarnLevel) - chainID := big.NewInt(1337) - o := logpoller.NewORM(chainID, sqlxDB, lggr, pgtest.NewQConfig(true)) - - listener := pq.NewListener(dbURL, time.Second, time.Second, nil) - err := listener.Listen(pg.ChannelInsertOnEVMLogs) - require.NoError(t, err) - - log := logpoller.Log{ - EvmChainId: ubig.New(chainID), - LogIndex: 10, - BlockHash: testutils.Random32Byte(), - BlockNumber: 100, - BlockTimestamp: time.Now(), - Topics: pq.ByteaArray{ - testutils.NewAddress().Bytes(), - testutils.NewAddress().Bytes(), - }, - EventSig: testutils.Random32Byte(), - Address: testutils.NewAddress(), - TxHash: testutils.Random32Byte(), - Data: []byte("test_data"), - CreatedAt: time.Now(), - } - - err = o.InsertLogs([]logpoller.Log{log}) - require.NoError(t, err) - - testutils.AssertEventually(t, func() bool { - select { - case event := <-listener.Notify: - expectedPayload := fmt.Sprintf( - "%s:%s,%s", - hexutil.Encode(log.Address.Bytes())[2:], // strip the leading 0x - hexutil.Encode(log.Topics[0])[2:], - hexutil.Encode(log.Topics[1])[2:], - ) - require.Equal(t, event.Extra, expectedPayload) - return true - default: - return false - } - }) -} - type getLogErrData struct { From string To string diff --git a/core/chains/evm/txmgr/attempts.go b/core/chains/evm/txmgr/attempts.go index ab143a0c963..91645bae6f6 100644 --- a/core/chains/evm/txmgr/attempts.go +++ b/core/chains/evm/txmgr/attempts.go @@ -124,7 +124,7 @@ func (c *evmTxAttemptBuilder) NewEmptyTxAttempt(nonce evmtypes.Nonce, feeLimit u uint64(nonce), fromAddress, value, - uint32(feeLimit), + feeLimit, fee.Legacy, payload, ) diff --git a/core/chains/evm/txmgr/attempts_test.go b/core/chains/evm/txmgr/attempts_test.go index 5635972d7ae..c7373e2c4f6 100644 --- a/core/chains/evm/txmgr/attempts_test.go +++ b/core/chains/evm/txmgr/attempts_test.go @@ -164,13 +164,13 @@ func TestTxm_NewDynamicFeeTx(t *testing.T) { {"gas tip < fee cap", assets.GWei(4), assets.GWei(5), nil, ""}, {"gas tip > fee cap", assets.GWei(6), assets.GWei(5), nil, "gas fee cap must be greater than or equal to gas tip cap (fee cap: 5 gwei, tip cap: 6 gwei)"}, {"fee cap exceeds max allowed", assets.GWei(5), assets.GWei(5), func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.PriceMax = (*assets.Wei)(assets.GWei(4)) + c.EVM[0].GasEstimator.PriceMax = assets.GWei(4) }, "specified gas fee cap of 5 gwei would exceed max configured gas price of 4 gwei"}, {"ignores global min gas price", assets.GWei(5), assets.GWei(5), func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.PriceMin = (*assets.Wei)(assets.GWei(6)) + c.EVM[0].GasEstimator.PriceMin = assets.GWei(6) }, ""}, {"tip cap below min allowed", assets.GWei(5), assets.GWei(5), func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.TipCapMin = (*assets.Wei)(assets.GWei(6)) + c.EVM[0].GasEstimator.TipCapMin = assets.GWei(6) }, "specified gas tip cap of 5 gwei is below min configured gas tip of 6 gwei"}, } diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index a0711a55a56..67e9b0d8f04 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -1142,7 +1142,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) localNextNonce = getLocalNextNonce(t, eb, fromAddress) - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() eb2 := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), evmcfg.Database().Listener(), ethKeyStore, txBuilder, nil, lggr, &testCheckerFactory{}, false) retryable, err := eb2.ProcessUnstartedTxs(ctx, fromAddress) assert.NoError(t, err) @@ -1193,7 +1193,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { require.Equal(t, int64(localNextNonce), int64(nonce)) // On the second try, the tx has been accepted into the mempool - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce+1), nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce+1, nil).Once() retryable, err = eb.ProcessUnstartedTxs(ctx, fromAddress) assert.NoError(t, err) @@ -1217,10 +1217,10 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { localNextNonce := getLocalNextNonce(t, eb, fromAddress) etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { - return tx.Nonce() == uint64(localNextNonce) + return tx.Nonce() == localNextNonce }), fromAddress).Return(commonclient.Unknown, errors.New(retryableErrorExample)).Once() // Nonce is the same as localNextNonce, implying that this sent transaction has not been accepted - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() // Do the thing retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) @@ -1269,7 +1269,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { localNextNonce := getLocalNextNonce(t, eb, fromAddress) etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { - return tx.Nonce() == uint64(localNextNonce) + return tx.Nonce() == localNextNonce }), fromAddress).Return(commonclient.Unknown, errors.New(retryableErrorExample)).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), errors.New("pending nonce fetch failed")).Once() @@ -1324,7 +1324,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { return tx.Nonce() == localNextNonce }), fromAddress).Return(commonclient.Unknown, errors.New(retryableErrorExample)).Once() // Nonce is one higher than localNextNonce, implying that despite the error, this sent transaction has been accepted into the mempool - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce+1), nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce+1, nil).Once() // Do the thing retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) @@ -1466,7 +1466,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.BumpMin = assets.NewWeiI(0) c.EVM[0].GasEstimator.BumpPercent = ptr[uint16](0) })) - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) @@ -1558,7 +1558,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.BumpPercent = ptr[uint16](0) })) localNextNonce := getLocalNextNonce(t, eb, fromAddress) - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) underpricedError := "transaction underpriced" @@ -1799,7 +1799,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, txBuilder, txNonceSyncer, lggr, checkerFactory, true) - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(ethNodeNonce), nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(ethNodeNonce, nil).Once() servicetest.Run(t, eb) testutils.WaitForLogMessage(t, observed, "Fast-forward sequence") diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index 8fa791a141e..9f267a8ea67 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -1724,7 +1724,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.PriceMax = (*assets.Wei)(assets.GWei(500)) + c.EVM[0].GasEstimator.PriceMax = assets.GWei(500) }) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) @@ -2373,7 +2373,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.PriceMax = (*assets.Wei)(assets.GWei(500)) + c.EVM[0].GasEstimator.PriceMax = assets.GWei(500) }) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index da206c46c7d..add4d915809 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -150,7 +150,7 @@ func fromDBReceiptsPlus(rs []dbReceiptPlus) []ReceiptPlus { func toOnchainReceipt(rs []*evmtypes.Receipt) []rawOnchainReceipt { receipts := make([]rawOnchainReceipt, len(rs)) for i := 0; i < len(rs); i++ { - receipts[i] = rawOnchainReceipt(*rs[i]) + receipts[i] = *rs[i] } return receipts } diff --git a/core/chains/evm/txmgr/evm_tx_store_test.go b/core/chains/evm/txmgr/evm_tx_store_test.go index 1a1ee1bcd3a..b5da5527448 100644 --- a/core/chains/evm/txmgr/evm_tx_store_test.go +++ b/core/chains/evm/txmgr/evm_tx_store_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -23,7 +24,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/google/uuid" "github.com/stretchr/testify/assert" @@ -1379,7 +1379,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { etx := mustInsertInProgressEthTxWithAttempt(t, txStore, nonce, fromAddress) require.Len(t, etx.TxAttempts, 1) - zero := models.MustNewDuration(time.Duration(0)) + zero := commonconfig.MustNewDuration(time.Duration(0)) evmCfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Chain.Transactions.ReaperInterval = zero c.EVM[0].Chain.Transactions.ReaperThreshold = zero diff --git a/core/chains/evm/txmgr/resender_test.go b/core/chains/evm/txmgr/resender_test.go index f6b0e3e29c7..fd3d1745010 100644 --- a/core/chains/evm/txmgr/resender_test.go +++ b/core/chains/evm/txmgr/resender_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" @@ -23,7 +24,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func Test_EthResender_resendUnconfirmed(t *testing.T) { @@ -106,7 +106,7 @@ func Test_EthResender_alertUnconfirmed(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, logCfg).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) // Set this to the smallest non-zero value possible for the attempt to be eligible for resend - delay := models.MustNewDuration(1 * time.Nanosecond) + delay := commonconfig.MustNewDuration(1 * time.Nanosecond) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0] = &toml.EVMConfig{ Chain: toml.Defaults(ubig.New(big.NewInt(0)), &toml.Chain{ @@ -144,7 +144,7 @@ func Test_EthResender_Start(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { // This can be anything as long as it isn't zero - c.EVM[0].Transactions.ResendAfterThreshold = models.MustNewDuration(42 * time.Hour) + c.EVM[0].Transactions.ResendAfterThreshold = commonconfig.MustNewDuration(42 * time.Hour) // Set batch size low to test batching c.EVM[0].RPCDefaultBatchSize = ptr[uint32](1) }) diff --git a/core/chains/evm/types/models.go b/core/chains/evm/types/models.go index 93b300aa532..44e150b6541 100644 --- a/core/chains/evm/types/models.go +++ b/core/chains/evm/types/models.go @@ -316,7 +316,7 @@ func (h *Head) MarshalJSON() ([]byte, error) { if h.StateRoot != (common.Hash{}) { jsonHead.StateRoot = &h.StateRoot } - jsonHead.Number = (*hexutil.Big)(big.NewInt(int64(h.Number))) + jsonHead.Number = (*hexutil.Big)(big.NewInt(h.Number)) if h.ParentHash != (common.Hash{}) { jsonHead.ParentHash = &h.ParentHash } diff --git a/core/chains/evm/types/nonce.go b/core/chains/evm/types/nonce.go index e9caf98c763..be295bdd2a9 100644 --- a/core/chains/evm/types/nonce.go +++ b/core/chains/evm/types/nonce.go @@ -19,5 +19,5 @@ func (n Nonce) String() string { } func GenerateNextNonce(prev Nonce) Nonce { - return Nonce(prev + 1) + return prev + 1 } diff --git a/core/chains/legacyevm/chain.go b/core/chains/legacyevm/chain.go index ef84573cd09..0e0e1e65aca 100644 --- a/core/chains/legacyevm/chain.go +++ b/core/chains/legacyevm/chain.go @@ -37,7 +37,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) //go:generate mockery --quiet --name Chain --output ./mocks/ --case=underscore @@ -164,9 +163,8 @@ func (c ChainRelayExtenderConfig) Validate() error { type ChainOpts struct { AppConfig AppConfig - EventBroadcaster pg.EventBroadcaster - MailMon *mailbox.Monitor - GasEstimator gas.EvmFeeEstimator + MailMon *mailbox.Monitor + GasEstimator gas.EvmFeeEstimator *sqlx.DB @@ -185,9 +183,7 @@ func (o ChainOpts) Validate() error { if o.AppConfig == nil { err = errors.Join(err, errors.New("nil AppConfig")) } - if o.EventBroadcaster == nil { - err = errors.Join(err, errors.New("nil EventBroadcaster")) - } + if o.MailMon == nil { err = errors.Join(err, errors.New("nil MailMon")) } diff --git a/core/chains/legacyevm/chain_test.go b/core/chains/legacyevm/chain_test.go index 93332348aa0..e639db6e7cc 100644 --- a/core/chains/legacyevm/chain_test.go +++ b/core/chains/legacyevm/chain_test.go @@ -14,7 +14,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) func TestLegacyChains(t *testing.T) { @@ -34,10 +33,9 @@ func TestLegacyChains(t *testing.T) { func TestChainOpts_Validate(t *testing.T) { type fields struct { - AppConfig legacyevm.AppConfig - EventBroadcaster pg.EventBroadcaster - MailMon *mailbox.Monitor - DB *sqlx.DB + AppConfig legacyevm.AppConfig + MailMon *mailbox.Monitor + DB *sqlx.DB } tests := []struct { name string @@ -47,19 +45,17 @@ func TestChainOpts_Validate(t *testing.T) { { name: "valid", fields: fields{ - AppConfig: configtest.NewTestGeneralConfig(t), - EventBroadcaster: pg.NewNullEventBroadcaster(), - MailMon: &mailbox.Monitor{}, - DB: pgtest.NewSqlxDB(t), + AppConfig: configtest.NewTestGeneralConfig(t), + MailMon: &mailbox.Monitor{}, + DB: pgtest.NewSqlxDB(t), }, }, { name: "invalid", fields: fields{ - AppConfig: nil, - EventBroadcaster: nil, - MailMon: nil, - DB: nil, + AppConfig: nil, + MailMon: nil, + DB: nil, }, wantErr: true, }, @@ -67,10 +63,9 @@ func TestChainOpts_Validate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { o := legacyevm.ChainOpts{ - AppConfig: tt.fields.AppConfig, - EventBroadcaster: tt.fields.EventBroadcaster, - MailMon: tt.fields.MailMon, - DB: tt.fields.DB, + AppConfig: tt.fields.AppConfig, + MailMon: tt.fields.MailMon, + DB: tt.fields.DB, } if err := o.Validate(); (err != nil) != tt.wantErr { t.Errorf("ChainOpts.Validate() error = %v, wantErr %v", err, tt.wantErr) diff --git a/core/cmd/admin_commands.go b/core/cmd/admin_commands.go index a0e69867e71..799709ad205 100644 --- a/core/cmd/admin_commands.go +++ b/core/cmd/admin_commands.go @@ -180,7 +180,7 @@ func (ps AdminUsersPresenters) RenderTable(rt RendererTable) error { // ListUsers renders all API users and their roles func (s *Shell) ListUsers(_ *cli.Context) (err error) { - resp, err := s.HTTP.Get("/v2/users/", nil) + resp, err := s.HTTP.Get(s.ctx(), "/v2/users/", nil) if err != nil { return s.errorOut(err) } @@ -195,7 +195,7 @@ func (s *Shell) ListUsers(_ *cli.Context) (err error) { // CreateUser creates a new user by prompting for email, password, and role func (s *Shell) CreateUser(c *cli.Context) (err error) { - resp, err := s.HTTP.Get("/v2/users/", nil) + resp, err := s.HTTP.Get(s.ctx(), "/v2/users/", nil) if err != nil { return s.errorOut(err) } @@ -234,7 +234,7 @@ func (s *Shell) CreateUser(c *cli.Context) (err error) { } buf := bytes.NewBuffer(requestData) - response, err := s.HTTP.Post("/v2/users", buf) + response, err := s.HTTP.Post(s.ctx(), "/v2/users", buf) if err != nil { return s.errorOut(err) } @@ -263,7 +263,7 @@ func (s *Shell) ChangeRole(c *cli.Context) (err error) { } buf := bytes.NewBuffer(requestData) - response, err := s.HTTP.Patch("/v2/users", buf) + response, err := s.HTTP.Patch(s.ctx(), "/v2/users", buf) if err != nil { return s.errorOut(err) } @@ -283,7 +283,7 @@ func (s *Shell) DeleteUser(c *cli.Context) (err error) { return s.errorOut(errors.New("email flag is empty, must specify an email")) } - response, err := s.HTTP.Delete(fmt.Sprintf("/v2/users/%s", email)) + response, err := s.HTTP.Delete(s.ctx(), fmt.Sprintf("/v2/users/%s", email)) if err != nil { return s.errorOut(err) } @@ -297,8 +297,8 @@ func (s *Shell) DeleteUser(c *cli.Context) (err error) { } // Status will display the health of various services -func (s *Shell) Status(_ *cli.Context) error { - resp, err := s.HTTP.Get("/health?full=1", nil) +func (s *Shell) Status(c *cli.Context) error { + resp, err := s.HTTP.Get(s.ctx(), "/health?full=1", nil) if err != nil { return s.errorOut(err) } @@ -313,6 +313,7 @@ func (s *Shell) Status(_ *cli.Context) error { // Profile will collect pprof metrics and store them in a folder. func (s *Shell) Profile(c *cli.Context) error { + ctx := s.ctx() seconds := c.Uint("seconds") baseDir := c.String("output_dir") @@ -342,7 +343,7 @@ func (s *Shell) Profile(c *cli.Context) error { go func(vt string) { defer wgPprof.Done() uri := fmt.Sprintf("/v2/debug/pprof/%s?seconds=%d", vt, seconds) - resp, err := s.HTTP.Get(uri) + resp, err := s.HTTP.Get(ctx, uri) if err != nil { errs <- fmt.Errorf("error collecting %s: %w", vt, err) return diff --git a/core/cmd/blocks_commands.go b/core/cmd/blocks_commands.go index 29c9e7642a5..72b0523e18d 100644 --- a/core/cmd/blocks_commands.go +++ b/core/cmd/blocks_commands.go @@ -52,7 +52,7 @@ func (s *Shell) ReplayFromBlock(c *cli.Context) (err error) { } buf := bytes.NewBufferString("{}") - resp, err := s.HTTP.Post( + resp, err := s.HTTP.Post(s.ctx(), fmt.Sprintf( "/v2/replay_from_block/%v?%s", blockNumber, diff --git a/core/cmd/bridge_commands.go b/core/cmd/bridge_commands.go index 8389d548c79..398d466c43a 100644 --- a/core/cmd/bridge_commands.go +++ b/core/cmd/bridge_commands.go @@ -91,7 +91,7 @@ func (s *Shell) ShowBridge(c *cli.Context) (err error) { return s.errorOut(errors.New("must pass the name of the bridge to be shown")) } bridgeName := c.Args().First() - resp, err := s.HTTP.Get("/v2/bridge_types/" + bridgeName) + resp, err := s.HTTP.Get(s.ctx(), "/v2/bridge_types/"+bridgeName) if err != nil { return s.errorOut(err) } @@ -115,7 +115,7 @@ func (s *Shell) CreateBridge(c *cli.Context) (err error) { return s.errorOut(err) } - resp, err := s.HTTP.Post("/v2/bridge_types", buf) + resp, err := s.HTTP.Post(s.ctx(), "/v2/bridge_types", buf) if err != nil { return s.errorOut(err) } @@ -134,7 +134,7 @@ func (s *Shell) RemoveBridge(c *cli.Context) (err error) { return s.errorOut(errors.New("must pass the name of the bridge to be removed")) } bridgeName := c.Args().First() - resp, err := s.HTTP.Delete("/v2/bridge_types/" + bridgeName) + resp, err := s.HTTP.Delete(s.ctx(), "/v2/bridge_types/"+bridgeName) if err != nil { return s.errorOut(err) } diff --git a/core/cmd/cosmos_transaction_commands.go b/core/cmd/cosmos_transaction_commands.go index 7c53d1ff1da..576a64adfb0 100644 --- a/core/cmd/cosmos_transaction_commands.go +++ b/core/cmd/cosmos_transaction_commands.go @@ -115,7 +115,7 @@ func (s *Shell) CosmosSendNativeToken(c *cli.Context) (err error) { buf := bytes.NewBuffer(requestData) - resp, err := s.HTTP.Post("/v2/transfers/cosmos", buf) + resp, err := s.HTTP.Post(s.ctx(), "/v2/transfers/cosmos", buf) if err != nil { return s.errorOut(err) } diff --git a/core/cmd/csa_keys_commands.go b/core/cmd/csa_keys_commands.go index c2ab3697b18..1c0fe54ab09 100644 --- a/core/cmd/csa_keys_commands.go +++ b/core/cmd/csa_keys_commands.go @@ -108,7 +108,7 @@ func (ps CSAKeyPresenters) RenderTable(rt RendererTable) error { // ListCSAKeys retrieves a list of all CSA keys func (s *Shell) ListCSAKeys(_ *cli.Context) (err error) { - resp, err := s.HTTP.Get("/v2/keys/csa", nil) + resp, err := s.HTTP.Get(s.ctx(), "/v2/keys/csa", nil) if err != nil { return s.errorOut(err) } @@ -123,7 +123,7 @@ func (s *Shell) ListCSAKeys(_ *cli.Context) (err error) { // CreateCSAKey creates a new CSA key func (s *Shell) CreateCSAKey(_ *cli.Context) (err error) { - resp, err := s.HTTP.Post("/v2/keys/csa", nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/csa", nil) if err != nil { return s.errorOut(err) } @@ -165,7 +165,7 @@ func (s *Shell) ImportCSAKey(c *cli.Context) (err error) { query.Set("oldpassword", normalizePassword(string(oldPassword))) exportUrl.RawQuery = query.Encode() - resp, err := s.HTTP.Post(exportUrl.String(), bytes.NewReader(keyJSON)) + resp, err := s.HTTP.Post(s.ctx(), exportUrl.String(), bytes.NewReader(keyJSON)) if err != nil { return s.errorOut(err) } @@ -208,7 +208,7 @@ func (s *Shell) ExportCSAKey(c *cli.Context) (err error) { query.Set("newpassword", normalizePassword(string(newPassword))) exportUrl.RawQuery = query.Encode() - resp, err := s.HTTP.Post(exportUrl.String(), nil) + resp, err := s.HTTP.Post(s.ctx(), exportUrl.String(), nil) if err != nil { return s.errorOut(errors.Wrap(err, "Could not make HTTP request")) } diff --git a/core/cmd/eth_keys_commands.go b/core/cmd/eth_keys_commands.go index ad76a7655ef..5adac3b382b 100644 --- a/core/cmd/eth_keys_commands.go +++ b/core/cmd/eth_keys_commands.go @@ -124,15 +124,27 @@ type EthKeyPresenter struct { } func (p *EthKeyPresenter) ToRow() []string { + eth := "Unknown" + if p.EthBalance != nil { + eth = p.EthBalance.String() + } + link := "Unknown" + if p.LinkBalance != nil { + link = p.LinkBalance.String() + } + gas := "None" + if p.MaxGasPriceWei != nil { + gas = p.MaxGasPriceWei.String() + } return []string{ p.Address, p.EVMChainID.String(), - p.EthBalance.String(), - p.LinkBalance.String(), + eth, + link, fmt.Sprintf("%v", p.Disabled), p.CreatedAt.String(), p.UpdatedAt.String(), - p.MaxGasPriceWei.String(), + gas, } } @@ -164,7 +176,7 @@ func (ps EthKeyPresenters) RenderTable(rt RendererTable) error { // ListETHKeys renders the active account address with its ETH & LINK balance func (s *Shell) ListETHKeys(_ *cli.Context) (err error) { - resp, err := s.HTTP.Get("/v2/keys/evm") + resp, err := s.HTTP.Get(s.ctx(), "/v2/keys/evm") if err != nil { return s.errorOut(err) @@ -194,7 +206,7 @@ func (s *Shell) CreateETHKey(c *cli.Context) (err error) { } createUrl.RawQuery = query.Encode() - resp, err := s.HTTP.Post(createUrl.String(), nil) + resp, err := s.HTTP.Post(s.ctx(), createUrl.String(), nil) if err != nil { return s.errorOut(err) } @@ -219,7 +231,7 @@ func (s *Shell) DeleteETHKey(c *cli.Context) (err error) { return nil } - resp, err := s.HTTP.Delete("/v2/keys/evm/" + address) + resp, err := s.HTTP.Delete(s.ctx(), "/v2/keys/evm/"+address) if err != nil { return s.errorOut(err) } @@ -278,7 +290,7 @@ func (s *Shell) ImportETHKey(c *cli.Context) (err error) { } importUrl.RawQuery = query.Encode() - resp, err := s.HTTP.Post(importUrl.String(), bytes.NewReader(keyJSON)) + resp, err := s.HTTP.Post(s.ctx(), importUrl.String(), bytes.NewReader(keyJSON)) if err != nil { return s.errorOut(err) } @@ -320,7 +332,7 @@ func (s *Shell) ExportETHKey(c *cli.Context) (err error) { query.Set("newpassword", strings.TrimSpace(string(newPassword))) exportUrl.RawQuery = query.Encode() - resp, err := s.HTTP.Post(exportUrl.String(), nil) + resp, err := s.HTTP.Post(s.ctx(), exportUrl.String(), nil) if err != nil { return s.errorOut(errors.Wrap(err, "Could not make HTTP request")) } @@ -373,7 +385,7 @@ func (s *Shell) UpdateChainEVMKey(c *cli.Context) (err error) { } chainURL.RawQuery = query.Encode() - resp, err := s.HTTP.Post(chainURL.String(), nil) + resp, err := s.HTTP.Post(s.ctx(), chainURL.String(), nil) if err != nil { return s.errorOut(errors.Wrap(err, "Could not make HTTP request")) } diff --git a/core/cmd/eth_keys_commands_test.go b/core/cmd/eth_keys_commands_test.go index e9121270191..de40a5bf873 100644 --- a/core/cmd/eth_keys_commands_test.go +++ b/core/cmd/eth_keys_commands_test.go @@ -161,8 +161,8 @@ func TestShell_ListETHKeys_Disabled(t *testing.T) { assert.Nil(t, balances[0].LinkBalance) assert.Nil(t, balances[0].MaxGasPriceWei) assert.Equal(t, []string{ - k.Address.String(), "0", "", "0", "false", - balances[0].UpdatedAt.String(), balances[0].CreatedAt.String(), "", + k.Address.String(), "0", "Unknown", "Unknown", "false", + balances[0].UpdatedAt.String(), balances[0].CreatedAt.String(), "None", }, balances[0].ToRow()) } diff --git a/core/cmd/evm_node_commands_test.go b/core/cmd/evm_node_commands_test.go index 869ef1b9b3e..dae950fce01 100644 --- a/core/cmd/evm_node_commands_test.go +++ b/core/cmd/evm_node_commands_test.go @@ -9,11 +9,11 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func assertTableRenders(t *testing.T, r *cltest.RendererMock) { @@ -31,15 +31,15 @@ func TestShell_IndexEVMNodes(t *testing.T) { chainID := newRandChainID() node1 := evmcfg.Node{ Name: ptr("Test node 1"), - WSURL: models.MustParseURL("ws://localhost:8546"), - HTTPURL: models.MustParseURL("http://localhost:8546"), + WSURL: commonconfig.MustParseURL("ws://localhost:8546"), + HTTPURL: commonconfig.MustParseURL("http://localhost:8546"), SendOnly: ptr(false), Order: ptr(int32(15)), } node2 := evmcfg.Node{ Name: ptr("Test node 2"), - WSURL: models.MustParseURL("ws://localhost:8547"), - HTTPURL: models.MustParseURL("http://localhost:8547"), + WSURL: commonconfig.MustParseURL("ws://localhost:8547"), + HTTPURL: commonconfig.MustParseURL("http://localhost:8547"), SendOnly: ptr(false), Order: ptr(int32(36)), } diff --git a/core/cmd/evm_transaction_commands.go b/core/cmd/evm_transaction_commands.go index 76628944a6c..28a4fa23a3b 100644 --- a/core/cmd/evm_transaction_commands.go +++ b/core/cmd/evm_transaction_commands.go @@ -117,7 +117,7 @@ func (s *Shell) ShowTransaction(c *cli.Context) (err error) { return s.errorOut(errors.New("must pass the hash of the transaction")) } hash := c.Args().First() - resp, err := s.HTTP.Get("/v2/transactions/evm/" + hash) + resp, err := s.HTTP.Get(s.ctx(), "/v2/transactions/evm/"+hash) if err != nil { return s.errorOut(err) } @@ -198,7 +198,7 @@ func (s *Shell) SendEther(c *cli.Context) (err error) { buf := bytes.NewBuffer(requestData) - resp, err := s.HTTP.Post("/v2/transfers/evm", buf) + resp, err := s.HTTP.Post(s.ctx(), "/v2/transfers/evm", buf) if err != nil { return s.errorOut(err) } diff --git a/core/cmd/evm_transaction_commands_test.go b/core/cmd/evm_transaction_commands_test.go index 5c80a7d74a0..588e65027f2 100644 --- a/core/cmd/evm_transaction_commands_test.go +++ b/core/cmd/evm_transaction_commands_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -22,7 +23,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func TestShell_IndexTransactions(t *testing.T) { @@ -151,7 +151,7 @@ func TestShell_SendEther_From_Txm(t *testing.T) { // NOTE: FallbackPollInterval is used in this test to quickly create TxAttempts // Testing triggers requires committing transactions and does not work with transactional tests - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(time.Second) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(time.Second) }, withKey(), withMocks(ethMock, key), @@ -217,7 +217,7 @@ func TestShell_SendEther_From_Txm_WEI(t *testing.T) { // NOTE: FallbackPollInterval is used in this test to quickly create TxAttempts // Testing triggers requires committing transactions and does not work with transactional tests - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(time.Second) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(time.Second) }, withKey(), withMocks(ethMock, key), diff --git a/core/cmd/forwarders_commands.go b/core/cmd/forwarders_commands.go index a870d4714c7..2445be5bfec 100644 --- a/core/cmd/forwarders_commands.go +++ b/core/cmd/forwarders_commands.go @@ -102,7 +102,7 @@ func (s *Shell) DeleteForwarder(c *cli.Context) (err error) { if !c.Args().Present() { return s.errorOut(errors.New("must pass the forwarder id to be archived")) } - resp, err := s.HTTP.Delete("/v2/nodes/evm/forwarders/" + c.Args().First()) + resp, err := s.HTTP.Delete(s.ctx(), "/v2/nodes/evm/forwarders/"+c.Args().First()) if err != nil { return s.errorOut(err) } @@ -143,7 +143,7 @@ func (s *Shell) TrackForwarder(c *cli.Context) (err error) { return s.errorOut(err) } - resp, err := s.HTTP.Post("/v2/nodes/evm/forwarders/track", bytes.NewReader(request)) + resp, err := s.HTTP.Post(s.ctx(), "/v2/nodes/evm/forwarders/track", bytes.NewReader(request)) if err != nil { return s.errorOut(err) } diff --git a/core/cmd/jobs_commands.go b/core/cmd/jobs_commands.go index d6e752e1a10..1f9ca33c78e 100644 --- a/core/cmd/jobs_commands.go +++ b/core/cmd/jobs_commands.go @@ -212,7 +212,7 @@ func (s *Shell) ShowJob(c *cli.Context) (err error) { return s.errorOut(errors.New("must provide the id of the job")) } id := c.Args().First() - resp, err := s.HTTP.Get("/v2/jobs/" + id) + resp, err := s.HTTP.Get(s.ctx(), "/v2/jobs/"+id) if err != nil { return s.errorOut(err) } @@ -244,7 +244,7 @@ func (s *Shell) CreateJob(c *cli.Context) (err error) { return s.errorOut(err) } - resp, err := s.HTTP.Post("/v2/jobs", bytes.NewReader(request)) + resp, err := s.HTTP.Post(s.ctx(), "/v2/jobs", bytes.NewReader(request)) if err != nil { return s.errorOut(err) } @@ -273,7 +273,7 @@ func (s *Shell) DeleteJob(c *cli.Context) error { if !c.Args().Present() { return s.errorOut(errors.New("must pass the job id to be archived")) } - resp, err := s.HTTP.Delete("/v2/jobs/" + c.Args().First()) + resp, err := s.HTTP.Delete(s.ctx(), "/v2/jobs/"+c.Args().First()) if err != nil { return s.errorOut(err) } @@ -291,7 +291,7 @@ func (s *Shell) TriggerPipelineRun(c *cli.Context) error { if !c.Args().Present() { return s.errorOut(errors.New("Must pass the job id to trigger a run")) } - resp, err := s.HTTP.Post("/v2/jobs/"+c.Args().First()+"/runs", nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/jobs/"+c.Args().First()+"/runs", nil) if err != nil { return s.errorOut(err) } diff --git a/core/cmd/jobs_commands_test.go b/core/cmd/jobs_commands_test.go index 5d9b3cb3f1a..75e95db84ca 100644 --- a/core/cmd/jobs_commands_test.go +++ b/core/cmd/jobs_commands_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" @@ -367,7 +368,7 @@ func TestShell_CreateJobV2(t *testing.T) { t.Parallel() app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(100 * time.Millisecond) c.OCR.Enabled = ptr(true) c.P2P.V2.Enabled = ptr(true) c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} @@ -405,7 +406,7 @@ func TestShell_DeleteJob(t *testing.T) { t.Parallel() app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(100 * time.Millisecond) c.EVM[0].Enabled = ptr(true) c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) diff --git a/core/cmd/keys_commands.go b/core/cmd/keys_commands.go index 07340c9cf08..7408d168887 100644 --- a/core/cmd/keys_commands.go +++ b/core/cmd/keys_commands.go @@ -105,7 +105,7 @@ func newKeysClient[K keystore.Key, P TableRenderer, P2 ~[]P](typ string, s *Shel // ListKeys retrieves a list of all keys func (cli *keysClient[K, P, P2]) ListKeys(_ *cli.Context) (err error) { - resp, err := cli.HTTP.Get(cli.path, nil) + resp, err := cli.HTTP.Get(cli.ctx(), cli.path, nil) if err != nil { return cli.errorOut(err) } @@ -121,7 +121,7 @@ func (cli *keysClient[K, P, P2]) ListKeys(_ *cli.Context) (err error) { // CreateKey creates a new key func (cli *keysClient[K, P, P2]) CreateKey(_ *cli.Context) (err error) { - resp, err := cli.HTTP.Post(cli.path, nil) + resp, err := cli.HTTP.Post(cli.ctx(), cli.path, nil) if err != nil { return cli.errorOut(err) } @@ -152,7 +152,7 @@ func (cli *keysClient[K, P, P2]) DeleteKey(c *cli.Context) (err error) { queryStr = "?hard=true" } - resp, err := cli.HTTP.Delete(fmt.Sprintf(cli.path+"/%s%s", id, queryStr)) + resp, err := cli.HTTP.Delete(cli.ctx(), fmt.Sprintf(cli.path+"/%s%s", id, queryStr)) if err != nil { return cli.errorOut(err) } @@ -189,7 +189,7 @@ func (cli *keysClient[K, P, P2]) ImportKey(c *cli.Context) (err error) { } normalizedPassword := normalizePassword(string(oldPassword)) - resp, err := cli.HTTP.Post(cli.path+"/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) + resp, err := cli.HTTP.Post(cli.ctx(), cli.path+"/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) if err != nil { return cli.errorOut(err) } @@ -227,7 +227,7 @@ func (cli *keysClient[K, P, P2]) ExportKey(c *cli.Context) (err error) { ID := c.Args().Get(0) normalizedPassword := normalizePassword(string(newPassword)) - resp, err := cli.HTTP.Post(cli.path+"/export/"+ID+"?newpassword="+normalizedPassword, nil) + resp, err := cli.HTTP.Post(cli.ctx(), cli.path+"/export/"+ID+"?newpassword="+normalizedPassword, nil) if err != nil { return cli.errorOut(errors.Wrap(err, "Could not make HTTP request")) } diff --git a/core/cmd/ocr2_keys_commands.go b/core/cmd/ocr2_keys_commands.go index ad4b30df4c2..1d469024878 100644 --- a/core/cmd/ocr2_keys_commands.go +++ b/core/cmd/ocr2_keys_commands.go @@ -127,7 +127,7 @@ func (ps OCR2KeyBundlePresenters) RenderTable(rt RendererTable) error { // ListOCR2KeyBundles lists the available OCR2 Key Bundles func (s *Shell) ListOCR2KeyBundles(_ *cli.Context) error { - resp, err := s.HTTP.Get("/v2/keys/ocr2", nil) + resp, err := s.HTTP.Get(s.ctx(), "/v2/keys/ocr2", nil) if err != nil { return s.errorOut(err) } @@ -149,7 +149,7 @@ func (s *Shell) CreateOCR2KeyBundle(c *cli.Context) error { ) } chainType := c.Args().Get(0) - resp, err := s.HTTP.Post(fmt.Sprintf("/v2/keys/ocr2/%s", chainType), nil) + resp, err := s.HTTP.Post(s.ctx(), fmt.Sprintf("/v2/keys/ocr2/%s", chainType), nil) if err != nil { return s.errorOut(err) } @@ -182,7 +182,7 @@ func (s *Shell) DeleteOCR2KeyBundle(c *cli.Context) error { queryStr = "?hard=true" } - resp, err := s.HTTP.Delete(fmt.Sprintf("/v2/keys/ocr2/%s%s", id, queryStr)) + resp, err := s.HTTP.Delete(s.ctx(), fmt.Sprintf("/v2/keys/ocr2/%s%s", id, queryStr)) if err != nil { return s.errorOut(err) } @@ -218,7 +218,7 @@ func (s *Shell) ImportOCR2Key(c *cli.Context) (err error) { } normalizedPassword := normalizePassword(string(oldPassword)) - resp, err := s.HTTP.Post("/v2/keys/ocr2/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/ocr2/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) if err != nil { return s.errorOut(err) } @@ -255,7 +255,7 @@ func (s *Shell) ExportOCR2Key(c *cli.Context) (err error) { ID := c.Args().Get(0) normalizedPassword := normalizePassword(string(newPassword)) - resp, err := s.HTTP.Post("/v2/keys/ocr2/export/"+ID+"?newpassword="+normalizedPassword, nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/ocr2/export/"+ID+"?newpassword="+normalizedPassword, nil) if err != nil { return s.errorOut(errors.Wrap(err, "Could not make HTTP request")) } diff --git a/core/cmd/ocr_keys_commands.go b/core/cmd/ocr_keys_commands.go index 2628cd9b270..399333bba93 100644 --- a/core/cmd/ocr_keys_commands.go +++ b/core/cmd/ocr_keys_commands.go @@ -108,7 +108,7 @@ type OCRKeyBundlePresenters []OCRKeyBundlePresenter // ListOCRKeyBundles lists the available OCR Key Bundles func (s *Shell) ListOCRKeyBundles(_ *cli.Context) error { - resp, err := s.HTTP.Get("/v2/keys/ocr", nil) + resp, err := s.HTTP.Get(s.ctx(), "/v2/keys/ocr", nil) if err != nil { return s.errorOut(err) } @@ -141,7 +141,7 @@ func (ps OCRKeyBundlePresenters) RenderTable(rt RendererTable) error { // CreateOCR2KeyBundle creates an OCR key bundle and saves it to the keystore func (s *Shell) CreateOCRKeyBundle(_ *cli.Context) error { - resp, err := s.HTTP.Post("/v2/keys/ocr", nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/ocr", nil) if err != nil { return s.errorOut(err) } @@ -174,7 +174,7 @@ func (s *Shell) DeleteOCRKeyBundle(c *cli.Context) error { queryStr = "?hard=true" } - resp, err := s.HTTP.Delete(fmt.Sprintf("/v2/keys/ocr/%s%s", id, queryStr)) + resp, err := s.HTTP.Delete(s.ctx(), fmt.Sprintf("/v2/keys/ocr/%s%s", id, queryStr)) if err != nil { return s.errorOut(err) } @@ -210,7 +210,7 @@ func (s *Shell) ImportOCRKey(c *cli.Context) (err error) { } normalizedPassword := normalizePassword(string(oldPassword)) - resp, err := s.HTTP.Post("/v2/keys/ocr/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/ocr/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) if err != nil { return s.errorOut(err) } @@ -247,7 +247,7 @@ func (s *Shell) ExportOCRKey(c *cli.Context) (err error) { ID := c.Args().Get(0) normalizedPassword := normalizePassword(string(newPassword)) - resp, err := s.HTTP.Post("/v2/keys/ocr/export/"+ID+"?newpassword="+normalizedPassword, nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/ocr/export/"+ID+"?newpassword="+normalizedPassword, nil) if err != nil { return s.errorOut(errors.Wrap(err, "Could not make HTTP request")) } diff --git a/core/cmd/p2p_keys_commands.go b/core/cmd/p2p_keys_commands.go index 4ec03da96ca..da3bf412a04 100644 --- a/core/cmd/p2p_keys_commands.go +++ b/core/cmd/p2p_keys_commands.go @@ -125,7 +125,7 @@ func (ps P2PKeyPresenters) RenderTable(rt RendererTable) error { // ListP2PKeys retrieves a list of all P2P keys func (s *Shell) ListP2PKeys(_ *cli.Context) (err error) { - resp, err := s.HTTP.Get("/v2/keys/p2p", nil) + resp, err := s.HTTP.Get(s.ctx(), "/v2/keys/p2p", nil) if err != nil { return s.errorOut(err) } @@ -140,7 +140,7 @@ func (s *Shell) ListP2PKeys(_ *cli.Context) (err error) { // CreateP2PKey creates a new P2P key func (s *Shell) CreateP2PKey(_ *cli.Context) (err error) { - resp, err := s.HTTP.Post("/v2/keys/p2p", nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/p2p", nil) if err != nil { return s.errorOut(err) } @@ -170,7 +170,7 @@ func (s *Shell) DeleteP2PKey(c *cli.Context) (err error) { queryStr = "?hard=true" } - resp, err := s.HTTP.Delete(fmt.Sprintf("/v2/keys/p2p/%s%s", id, queryStr)) + resp, err := s.HTTP.Delete(s.ctx(), fmt.Sprintf("/v2/keys/p2p/%s%s", id, queryStr)) if err != nil { return s.errorOut(err) } @@ -206,7 +206,7 @@ func (s *Shell) ImportP2PKey(c *cli.Context) (err error) { } normalizedPassword := normalizePassword(string(oldPassword)) - resp, err := s.HTTP.Post("/v2/keys/p2p/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/p2p/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) if err != nil { return s.errorOut(err) } @@ -243,7 +243,7 @@ func (s *Shell) ExportP2PKey(c *cli.Context) (err error) { ID := c.Args().Get(0) normalizedPassword := normalizePassword(string(newPassword)) - resp, err := s.HTTP.Post("/v2/keys/p2p/export/"+ID+"?newpassword="+normalizedPassword, nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/p2p/export/"+ID+"?newpassword="+normalizedPassword, nil) if err != nil { return s.errorOut(errors.Wrap(err, "Could not make HTTP request")) } diff --git a/core/cmd/shell.go b/core/cmd/shell.go index e4711646cb4..b2298ab399d 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -43,7 +43,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/periodicbackup" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/cache" "github.com/smartcontractkit/chainlink/v2/core/services/versioning" @@ -156,8 +155,6 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G keyStore := keystore.New(db, utils.GetScryptParams(cfg), appLggr, cfg.Database()) mailMon := mailbox.NewMonitor(cfg.AppID().String(), appLggr.Named("Mailbox")) - dbListener := cfg.Database().Listener() - eventBroadcaster := pg.NewEventBroadcaster(cfg.Database().URL(), dbListener.MinReconnectInterval(), dbListener.MaxReconnectDuration(), appLggr, cfg.AppID()) loopRegistry := plugins.NewLoopRegistry(appLggr, cfg.Tracing()) mercuryPool := wsrpc.NewPool(appLggr, cache.Config{ @@ -176,7 +173,7 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G evmFactoryCfg := chainlink.EVMFactoryConfig{ CSAETHKeystore: keyStore, - ChainOpts: legacyevm.ChainOpts{AppConfig: cfg, EventBroadcaster: eventBroadcaster, MailMon: mailMon, DB: db}, + ChainOpts: legacyevm.ChainOpts{AppConfig: cfg, MailMon: mailMon, DB: db}, } // evm always enabled for backward compatibility // TODO BCF-2510 this needs to change in order to clear the path for EVM extraction @@ -226,7 +223,6 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G SqlxDB: db, KeyStore: keyStore, RelayerChainInteroperators: relayChainInterops, - EventBroadcaster: eventBroadcaster, MailMon: mailMon, Logger: appLggr, AuditLogger: auditLogger, @@ -477,11 +473,11 @@ func createServer(handler *gin.Engine, addr string, requestTimeout time.Duration // HTTPClient encapsulates all methods used to interact with a chainlink node API. type HTTPClient interface { - Get(string, ...map[string]string) (*http.Response, error) - Post(string, io.Reader) (*http.Response, error) - Put(string, io.Reader) (*http.Response, error) - Patch(string, io.Reader, ...map[string]string) (*http.Response, error) - Delete(string) (*http.Response, error) + Get(context.Context, string, ...map[string]string) (*http.Response, error) + Post(context.Context, string, io.Reader) (*http.Response, error) + Put(context.Context, string, io.Reader) (*http.Response, error) + Patch(context.Context, string, io.Reader, ...map[string]string) (*http.Response, error) + Delete(context.Context, string) (*http.Response, error) } type authenticatedHTTPClient struct { @@ -515,31 +511,31 @@ func newHttpClient(lggr logger.Logger, insecureSkipVerify bool) *http.Client { } // Get performs an HTTP Get using the authenticated HTTP client's cookie. -func (h *authenticatedHTTPClient) Get(path string, headers ...map[string]string) (*http.Response, error) { - return h.doRequest("GET", path, nil, headers...) +func (h *authenticatedHTTPClient) Get(ctx context.Context, path string, headers ...map[string]string) (*http.Response, error) { + return h.doRequest(ctx, "GET", path, nil, headers...) } // Post performs an HTTP Post using the authenticated HTTP client's cookie. -func (h *authenticatedHTTPClient) Post(path string, body io.Reader) (*http.Response, error) { - return h.doRequest("POST", path, body) +func (h *authenticatedHTTPClient) Post(ctx context.Context, path string, body io.Reader) (*http.Response, error) { + return h.doRequest(ctx, "POST", path, body) } // Put performs an HTTP Put using the authenticated HTTP client's cookie. -func (h *authenticatedHTTPClient) Put(path string, body io.Reader) (*http.Response, error) { - return h.doRequest("PUT", path, body) +func (h *authenticatedHTTPClient) Put(ctx context.Context, path string, body io.Reader) (*http.Response, error) { + return h.doRequest(ctx, "PUT", path, body) } // Patch performs an HTTP Patch using the authenticated HTTP client's cookie. -func (h *authenticatedHTTPClient) Patch(path string, body io.Reader, headers ...map[string]string) (*http.Response, error) { - return h.doRequest("PATCH", path, body, headers...) +func (h *authenticatedHTTPClient) Patch(ctx context.Context, path string, body io.Reader, headers ...map[string]string) (*http.Response, error) { + return h.doRequest(ctx, "PATCH", path, body, headers...) } // Delete performs an HTTP Delete using the authenticated HTTP client's cookie. -func (h *authenticatedHTTPClient) Delete(path string) (*http.Response, error) { - return h.doRequest("DELETE", path, nil) +func (h *authenticatedHTTPClient) Delete(ctx context.Context, path string) (*http.Response, error) { + return h.doRequest(ctx, "DELETE", path, nil) } -func (h *authenticatedHTTPClient) doRequest(verb, path string, body io.Reader, headerArgs ...map[string]string) (*http.Response, error) { +func (h *authenticatedHTTPClient) doRequest(ctx context.Context, verb, path string, body io.Reader, headerArgs ...map[string]string) (*http.Response, error) { var headers map[string]string if len(headerArgs) > 0 { headers = headerArgs[0] @@ -547,7 +543,7 @@ func (h *authenticatedHTTPClient) doRequest(verb, path string, body io.Reader, h headers = map[string]string{} } - request, err := http.NewRequest(verb, h.remoteNodeURL.String()+path, body) + request, err := http.NewRequestWithContext(ctx, verb, h.remoteNodeURL.String()+path, body) if err != nil { return nil, err } @@ -569,7 +565,7 @@ func (h *authenticatedHTTPClient) doRequest(verb, path string, body io.Reader, h } if response.StatusCode == http.StatusUnauthorized && (h.sessionRequest.Email != "" || h.sessionRequest.Password != "") { var cookieerr error - cookie, cookieerr = h.cookieAuth.Authenticate(h.sessionRequest) + cookie, cookieerr = h.cookieAuth.Authenticate(ctx, h.sessionRequest) if cookieerr != nil { return response, err } @@ -587,7 +583,7 @@ func (h *authenticatedHTTPClient) doRequest(verb, path string, body io.Reader, h // future HTTP requests. type CookieAuthenticator interface { Cookie() (*http.Cookie, error) - Authenticate(sessions.SessionRequest) (*http.Cookie, error) + Authenticate(context.Context, sessions.SessionRequest) (*http.Cookie, error) Logout() error } @@ -616,14 +612,14 @@ func (t *SessionCookieAuthenticator) Cookie() (*http.Cookie, error) { } // Authenticate retrieves a session ID via a cookie and saves it to disk. -func (t *SessionCookieAuthenticator) Authenticate(sessionRequest sessions.SessionRequest) (*http.Cookie, error) { +func (t *SessionCookieAuthenticator) Authenticate(ctx context.Context, sessionRequest sessions.SessionRequest) (*http.Cookie, error) { b := new(bytes.Buffer) err := json.NewEncoder(b).Encode(sessionRequest) if err != nil { return nil, err } url := t.config.RemoteNodeURL.String() + "/sessions" - req, err := http.NewRequest("POST", url, b) + req, err := http.NewRequestWithContext(ctx, "POST", url, b) if err != nil { return nil, err } diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index 69b7373ed70..b970b516413 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -1006,9 +1006,8 @@ func (s *Shell) CleanupChainTables(c *cli.Context) error { rows, err := db.Query(tablesToDeleteFromQuery, "evm_chain_id") if err != nil { return err - } else if rows.Err() != nil { - return rows.Err() } + defer rows.Close() var tablesToDeleteFrom []string for rows.Next() { @@ -1019,6 +1018,9 @@ func (s *Shell) CleanupChainTables(c *cli.Context) error { } tablesToDeleteFrom = append(tablesToDeleteFrom, schema+"."+name) } + if rows.Err() != nil { + return rows.Err() + } for _, tableName := range tablesToDeleteFrom { query := fmt.Sprintf(`DELETE FROM %s WHERE "evm_chain_id"=$1;`, tableName) diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index 400a8e3e75a..72c2f2b5bbd 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/common/client" @@ -25,7 +26,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" chainlinkmocks "github.com/smartcontractkit/chainlink/v2/core/services/chainlink/mocks" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" evmrelayer "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/sessions/localauth" "github.com/smartcontractkit/chainlink/v2/core/store/dialects" @@ -74,8 +74,8 @@ func TestShell_RunNodeWithPasswords(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { s.Password.Keystore = models.NewSecret("dummy") c.EVM[0].Nodes[0].Name = ptr("fake") - c.EVM[0].Nodes[0].HTTPURL = models.MustParseURL("http://fake.com") - c.EVM[0].Nodes[0].WSURL = models.MustParseURL("WSS://fake.com/ws") + c.EVM[0].Nodes[0].HTTPURL = commonconfig.MustParseURL("http://fake.com") + c.EVM[0].Nodes[0].WSURL = commonconfig.MustParseURL("WSS://fake.com/ws") // seems to be needed for config validate c.Insecure.OCRDevelopmentMode = nil }) @@ -89,10 +89,9 @@ func TestShell_RunNodeWithPasswords(t *testing.T) { Logger: lggr, KeyStore: keyStore.Eth(), ChainOpts: legacyevm.ChainOpts{ - AppConfig: cfg, - EventBroadcaster: pg.NewNullEventBroadcaster(), - MailMon: &mailbox.Monitor{}, - DB: db, + AppConfig: cfg, + MailMon: &mailbox.Monitor{}, + DB: db, }, } testRelayers := genTestEVMRelayers(t, opts, keyStore) @@ -168,8 +167,8 @@ func TestShell_RunNodeWithAPICredentialsFile(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { s.Password.Keystore = models.NewSecret("16charlengthp4SsW0rD1!@#_") c.EVM[0].Nodes[0].Name = ptr("fake") - c.EVM[0].Nodes[0].WSURL = models.MustParseURL("WSS://fake.com/ws") - c.EVM[0].Nodes[0].HTTPURL = models.MustParseURL("http://fake.com") + c.EVM[0].Nodes[0].WSURL = commonconfig.MustParseURL("WSS://fake.com/ws") + c.EVM[0].Nodes[0].HTTPURL = commonconfig.MustParseURL("http://fake.com") // seems to be needed for config validate c.Insecure.OCRDevelopmentMode = nil }) @@ -194,10 +193,9 @@ func TestShell_RunNodeWithAPICredentialsFile(t *testing.T) { Logger: lggr, KeyStore: keyStore.Eth(), ChainOpts: legacyevm.ChainOpts{ - AppConfig: cfg, - EventBroadcaster: pg.NewNullEventBroadcaster(), - MailMon: &mailbox.Monitor{}, - DB: db, + AppConfig: cfg, + MailMon: &mailbox.Monitor{}, + DB: db, }, } testRelayers := genTestEVMRelayers(t, opts, keyStore) diff --git a/core/cmd/shell_remote.go b/core/cmd/shell_remote.go index bc4620d0732..aab4a94da6f 100644 --- a/core/cmd/shell_remote.go +++ b/core/cmd/shell_remote.go @@ -110,7 +110,7 @@ func (s *Shell) CreateExternalInitiator(c *cli.Context) (err error) { } buf := bytes.NewBuffer(requestData) - resp, err := s.HTTP.Post("/v2/external_initiators", buf) + resp, err := s.HTTP.Post(s.ctx(), "/v2/external_initiators", buf) if err != nil { return s.errorOut(err) } @@ -131,7 +131,7 @@ func (s *Shell) DeleteExternalInitiator(c *cli.Context) (err error) { return s.errorOut(errors.New("Must pass the name of the external initiator to delete")) } - resp, err := s.HTTP.Delete("/v2/external_initiators/" + c.Args().First()) + resp, err := s.HTTP.Delete(s.ctx(), "/v2/external_initiators/"+c.Args().First()) if err != nil { return s.errorOut(err) } @@ -155,7 +155,7 @@ func (s *Shell) getPage(requestURI string, page int, model interface{}) (err err } uri.RawQuery = q.Encode() - resp, err := s.HTTP.Get(uri.String()) + resp, err := s.HTTP.Get(s.ctx(), uri.String()) if err != nil { return s.errorOut(err) } @@ -180,7 +180,7 @@ func (s *Shell) RemoteLogin(c *cli.Context) error { if err != nil { return s.errorOut(err) } - _, err = s.CookieAuthenticator.Authenticate(sessionRequest) + _, err = s.CookieAuthenticator.Authenticate(s.ctx(), sessionRequest) if err != nil { return s.errorOut(err) } @@ -194,7 +194,7 @@ func (s *Shell) RemoteLogin(c *cli.Context) error { // Logout removes local and remote session. func (s *Shell) Logout(_ *cli.Context) (err error) { - resp, err := s.HTTP.Delete("/sessions") + resp, err := s.HTTP.Delete(s.ctx(), "/sessions") if err != nil { return s.errorOut(err) } @@ -224,7 +224,7 @@ func (s *Shell) ChangePassword(_ *cli.Context) (err error) { } buf := bytes.NewBuffer(requestData) - resp, err := s.HTTP.Patch("/v2/user/password", buf) + resp, err := s.HTTP.Patch(s.ctx(), "/v2/user/password", buf) if err != nil { return s.errorOut(err) } @@ -313,7 +313,7 @@ func (s *Shell) ConfigV2(c *cli.Context) error { } func (s *Shell) configV2Str(userOnly bool) (string, error) { - resp, err := s.HTTP.Get(fmt.Sprintf("/v2/config/v2?userOnly=%t", userOnly)) + resp, err := s.HTTP.Get(s.ctx(), fmt.Sprintf("/v2/config/v2?userOnly=%t", userOnly)) if err != nil { return "", s.errorOut(err) } @@ -351,7 +351,7 @@ func (s *Shell) SetLogLevel(c *cli.Context) (err error) { } buf := bytes.NewBuffer(requestData) - resp, err := s.HTTP.Patch("/v2/log", buf) + resp, err := s.HTTP.Patch(s.ctx(), "/v2/log", buf) if err != nil { return s.errorOut(err) } @@ -383,7 +383,7 @@ func (s *Shell) SetLogSQL(c *cli.Context) (err error) { } buf := bytes.NewBuffer(requestData) - resp, err := s.HTTP.Patch("/v2/log", buf) + resp, err := s.HTTP.Patch(s.ctx(), "/v2/log", buf) if err != nil { return s.errorOut(err) } @@ -476,7 +476,7 @@ func parseResponse(resp *http.Response) ([]byte, error) { } func (s *Shell) checkRemoteBuildCompatibility(lggr logger.Logger, onlyWarn bool, cliVersion, cliSha string) error { - resp, err := s.HTTP.Get("/v2/build_info") + resp, err := s.HTTP.Get(s.ctx(), "/v2/build_info") if err != nil { lggr.Warnw("Got error querying for version. Remote node version is unknown and CLI may behave in unexpected ways.", "err", err) return nil @@ -517,7 +517,7 @@ func (s *Shell) Health(c *cli.Context) error { if c.Bool("json") { mime = gin.MIMEJSON } - resp, err := s.HTTP.Get("/health", map[string]string{"Accept": mime}) + resp, err := s.HTTP.Get(s.ctx(), "/health", map[string]string{"Accept": mime}) if err != nil { return s.errorOut(err) } diff --git a/core/cmd/shell_remote_test.go b/core/cmd/shell_remote_test.go index 6c8b46eda4c..dbd9968daab 100644 --- a/core/cmd/shell_remote_test.go +++ b/core/cmd/shell_remote_test.go @@ -2,6 +2,7 @@ package cmd_test import ( "bytes" + "context" "errors" "flag" "fmt" @@ -20,6 +21,7 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" @@ -33,7 +35,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/sessions" "github.com/smartcontractkit/chainlink/v2/core/static" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/core/web" ) @@ -60,7 +61,7 @@ func startNewApplicationV2(t *testing.T, overrideFn func(c *chainlink.Config, s } config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(30 * time.Millisecond) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(30 * time.Millisecond) f := false c.EVM[0].Enabled = &f c.P2P.V2.Enabled = &f @@ -383,7 +384,7 @@ type mockHTTPClient struct { mockSha string } -func (h *mockHTTPClient) Get(path string, headers ...map[string]string) (*http.Response, error) { +func (h *mockHTTPClient) Get(ctx context.Context, path string, headers ...map[string]string) (*http.Response, error) { if path == "/v2/build_info" { // Return mocked response here json := fmt.Sprintf(`{"version":"%s","commitSHA":"%s"}`, h.mockVersion, h.mockSha) @@ -393,23 +394,23 @@ func (h *mockHTTPClient) Get(path string, headers ...map[string]string) (*http.R Body: r, }, nil } - return h.HTTP.Get(path, headers...) + return h.HTTP.Get(ctx, path, headers...) } -func (h *mockHTTPClient) Post(path string, body io.Reader) (*http.Response, error) { - return h.HTTP.Post(path, body) +func (h *mockHTTPClient) Post(ctx context.Context, path string, body io.Reader) (*http.Response, error) { + return h.HTTP.Post(ctx, path, body) } -func (h *mockHTTPClient) Put(path string, body io.Reader) (*http.Response, error) { - return h.HTTP.Put(path, body) +func (h *mockHTTPClient) Put(ctx context.Context, path string, body io.Reader) (*http.Response, error) { + return h.HTTP.Put(ctx, path, body) } -func (h *mockHTTPClient) Patch(path string, body io.Reader, headers ...map[string]string) (*http.Response, error) { - return h.HTTP.Patch(path, body, headers...) +func (h *mockHTTPClient) Patch(ctx context.Context, path string, body io.Reader, headers ...map[string]string) (*http.Response, error) { + return h.HTTP.Patch(ctx, path, body, headers...) } -func (h *mockHTTPClient) Delete(path string) (*http.Response, error) { - return h.HTTP.Delete(path) +func (h *mockHTTPClient) Delete(ctx context.Context, path string) (*http.Response, error) { + return h.HTTP.Delete(ctx, path) } func TestShell_ChangePassword(t *testing.T) { @@ -700,7 +701,7 @@ func (FailingAuthenticator) Cookie() (*http.Cookie, error) { } // Authenticate retrieves a session ID via a cookie and saves it to disk. -func (FailingAuthenticator) Authenticate(sessionRequest sessions.SessionRequest) (*http.Cookie, error) { +func (FailingAuthenticator) Authenticate(context.Context, sessions.SessionRequest) (*http.Cookie, error) { return nil, errors.New("no luck") } diff --git a/core/cmd/shell_test.go b/core/cmd/shell_test.go index ade14aa0d8a..ec9606e0ac6 100644 --- a/core/cmd/shell_test.go +++ b/core/cmd/shell_test.go @@ -38,6 +38,7 @@ import ( func TestTerminalCookieAuthenticator_AuthenticateWithoutSession(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) u := cltest.NewUserWithSession(t, app.AuthenticationProvider()) @@ -54,7 +55,7 @@ func TestTerminalCookieAuthenticator_AuthenticateWithoutSession(t *testing.T) { sr := sessions.SessionRequest{Email: test.email, Password: test.pwd} store := &cmd.MemoryCookieStore{} tca := cmd.NewSessionCookieAuthenticator(cmd.ClientOpts{}, store, logger.TestLogger(t)) - cookie, err := tca.Authenticate(sr) + cookie, err := tca.Authenticate(ctx, sr) assert.Error(t, err) assert.Nil(t, cookie) @@ -68,8 +69,9 @@ func TestTerminalCookieAuthenticator_AuthenticateWithoutSession(t *testing.T) { func TestTerminalCookieAuthenticator_AuthenticateWithSession(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) u := cltest.NewUserWithSession(t, app.AuthenticationProvider()) @@ -87,7 +89,7 @@ func TestTerminalCookieAuthenticator_AuthenticateWithSession(t *testing.T) { sr := sessions.SessionRequest{Email: test.email, Password: test.pwd} store := &cmd.MemoryCookieStore{} tca := cmd.NewSessionCookieAuthenticator(app.NewClientOpts(), store, logger.TestLogger(t)) - cookie, err := tca.Authenticate(sr) + cookie, err := tca.Authenticate(ctx, sr) if test.wantError { assert.Error(t, err) diff --git a/core/cmd/solana_transaction_commands.go b/core/cmd/solana_transaction_commands.go index c92cc3e29dd..23e94eee50b 100644 --- a/core/cmd/solana_transaction_commands.go +++ b/core/cmd/solana_transaction_commands.go @@ -105,7 +105,7 @@ func (s *Shell) SolanaSendSol(c *cli.Context) (err error) { buf := bytes.NewBuffer(requestData) - resp, err := s.HTTP.Post("/v2/transfers/solana", buf) + resp, err := s.HTTP.Post(s.ctx(), "/v2/transfers/solana", buf) if err != nil { return s.errorOut(err) } diff --git a/core/cmd/vrf_keys_commands.go b/core/cmd/vrf_keys_commands.go index 1a04ef37c3e..32d32334af5 100644 --- a/core/cmd/vrf_keys_commands.go +++ b/core/cmd/vrf_keys_commands.go @@ -118,7 +118,7 @@ func (ps VRFKeyPresenters) RenderTable(rt RendererTable) error { // CreateVRFKey creates a key in the VRF keystore, protected by the password in // the vrf password file provided when starting the chainlink node. func (s *Shell) CreateVRFKey(_ *cli.Context) error { - resp, err := s.HTTP.Post("/v2/keys/vrf", nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/vrf", nil) if err != nil { return s.errorOut(err) } @@ -154,7 +154,7 @@ func (s *Shell) ImportVRFKey(c *cli.Context) error { } normalizedPassword := normalizePassword(string(oldPassword)) - resp, err := s.HTTP.Post("/v2/keys/vrf/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/vrf/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) if err != nil { return s.errorOut(err) } @@ -195,7 +195,7 @@ func (s *Shell) ExportVRFKey(c *cli.Context) error { } normalizedPassword := normalizePassword(string(newPassword)) - resp, err := s.HTTP.Post("/v2/keys/vrf/export/"+pk.String()+"?newpassword="+normalizedPassword, nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/vrf/export/"+pk.String()+"?newpassword="+normalizedPassword, nil) if err != nil { return s.errorOut(errors.Wrap(err, "Could not make HTTP request")) } @@ -248,7 +248,7 @@ func (s *Shell) DeleteVRFKey(c *cli.Context) error { queryStr = "?hard=true" } - resp, err := s.HTTP.Delete(fmt.Sprintf("/v2/keys/vrf/%s%s", id, queryStr)) + resp, err := s.HTTP.Delete(s.ctx(), fmt.Sprintf("/v2/keys/vrf/%s%s", id, queryStr)) if err != nil { return s.errorOut(err) } @@ -276,7 +276,7 @@ func getPublicKey(c *cli.Context) (secp256k1.PublicKey, error) { // ListKeys Lists the keys in the db func (s *Shell) ListVRFKeys(_ *cli.Context) error { - resp, err := s.HTTP.Get("/v2/keys/vrf", nil) + resp, err := s.HTTP.Get(s.ctx(), "/v2/keys/vrf", nil) if err != nil { return s.errorOut(err) } diff --git a/core/config/audit_logger_config.go b/core/config/audit_logger_config.go index e5078897722..b83ca5b00d0 100644 --- a/core/config/audit_logger_config.go +++ b/core/config/audit_logger_config.go @@ -1,12 +1,13 @@ package config import ( + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) type AuditLogger interface { Enabled() bool - ForwardToUrl() (models.URL, error) + ForwardToUrl() (commonconfig.URL, error) Environment() string JsonWrapperKey() string Headers() (models.ServiceHeaders, error) diff --git a/core/config/auto_pprof_config.go b/core/config/auto_pprof_config.go index f87777cbbd0..c69ff2c86af 100644 --- a/core/config/auto_pprof_config.go +++ b/core/config/auto_pprof_config.go @@ -1,7 +1,7 @@ package config import ( - "github.com/smartcontractkit/chainlink/v2/core/store/models" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -9,13 +9,13 @@ type AutoPprof interface { BlockProfileRate() int CPUProfileRate() int Enabled() bool - GatherDuration() models.Duration - GatherTraceDuration() models.Duration + GatherDuration() commonconfig.Duration + GatherTraceDuration() commonconfig.Duration GoroutineThreshold() int MaxProfileSize() utils.FileSize MemProfileRate() int MemThreshold() utils.FileSize MutexProfileFraction() int - PollInterval() models.Duration + PollInterval() commonconfig.Duration ProfileRoot() string } diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml index 953f1feabd8..3cb6bb0aaa7 100644 --- a/core/config/docs/core.toml +++ b/core/config/docs/core.toml @@ -574,3 +574,8 @@ MaxStaleAge = "1h" # Default # LatestReportDeadline controls how long to wait for a response from the # mercury server before retrying. Setting this to zero will wait indefinitely. LatestReportDeadline = "5s" # Default + +# Mercury.TLS controls client settings for when the node talks to traditional web servers or load balancers. +[Mercury.TLS] +# CertFile is the path to a PEM file of trusted root certificate authority certificates +CertFile = "/path/to/client/certs.pem" # Example diff --git a/core/config/docs/docs_test.go b/core/config/docs/docs_test.go index 30688c38879..508bd62e338 100644 --- a/core/config/docs/docs_test.go +++ b/core/config/docs/docs_test.go @@ -15,13 +15,13 @@ import ( stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" "github.com/smartcontractkit/chainlink-common/pkg/config" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/config/docs" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink/cfgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func TestDoc(t *testing.T) { @@ -42,7 +42,7 @@ func TestDoc(t *testing.T) { // and its only use is to signal to NOPs that these fields are no longer allowed emptyString := "" c.TelemetryIngress.ServerPubKey = &emptyString - c.TelemetryIngress.URL = new(models.URL) + c.TelemetryIngress.URL = new(commonconfig.URL) cfgtest.AssertFieldsNotNil(t, c) diff --git a/core/config/job_pipeline_config.go b/core/config/job_pipeline_config.go index 65010fc48c7..d4a01dbed03 100644 --- a/core/config/job_pipeline_config.go +++ b/core/config/job_pipeline_config.go @@ -3,12 +3,12 @@ package config import ( "time" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" ) type JobPipeline interface { DefaultHTTPLimit() int64 - DefaultHTTPTimeout() models.Duration + DefaultHTTPTimeout() commonconfig.Duration MaxRunDuration() time.Duration MaxSuccessfulRuns() uint64 ReaperInterval() time.Duration diff --git a/core/config/mercury_config.go b/core/config/mercury_config.go index e530af6338f..6a483c593e3 100644 --- a/core/config/mercury_config.go +++ b/core/config/mercury_config.go @@ -12,7 +12,12 @@ type MercuryCache interface { LatestReportDeadline() time.Duration } +type MercuryTLS interface { + CertFile() string +} + type Mercury interface { Credentials(credName string) *ocr2models.MercuryCredentials Cache() MercuryCache + TLS() MercuryTLS } diff --git a/core/config/p2p_v2_config.go b/core/config/p2p_v2_config.go index 7b4a3c05fc4..ff640786ed2 100644 --- a/core/config/p2p_v2_config.go +++ b/core/config/p2p_v2_config.go @@ -1,16 +1,16 @@ package config import ( - ocrcommontypes "github.com/smartcontractkit/libocr/commontypes" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + ocrcommontypes "github.com/smartcontractkit/libocr/commontypes" ) type V2 interface { Enabled() bool AnnounceAddresses() []string DefaultBootstrappers() (locators []ocrcommontypes.BootstrapperLocator) - DeltaDial() models.Duration - DeltaReconcile() models.Duration + DeltaDial() commonconfig.Duration + DeltaReconcile() commonconfig.Duration ListenAddresses() []string } diff --git a/core/config/toml/types.go b/core/config/toml/types.go index e944b44853b..eae5b2f533a 100644 --- a/core/config/toml/types.go +++ b/core/config/toml/types.go @@ -14,6 +14,7 @@ import ( ocrcommontypes "github.com/smartcontractkit/libocr/commontypes" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/build" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/parse" @@ -34,7 +35,7 @@ type Core struct { AppID uuid.UUID `toml:"-"` // random or test InsecureFastScrypt *bool RootDir *string - ShutdownGracePeriod *models.Duration + ShutdownGracePeriod *commonconfig.Duration Feature Feature `toml:",omitempty"` Database Database `toml:",omitempty"` @@ -310,9 +311,9 @@ func (f *Feature) setFrom(f2 *Feature) { } type Database struct { - DefaultIdleInTxSessionTimeout *models.Duration - DefaultLockTimeout *models.Duration - DefaultQueryTimeout *models.Duration + DefaultIdleInTxSessionTimeout *commonconfig.Duration + DefaultLockTimeout *commonconfig.Duration + DefaultQueryTimeout *commonconfig.Duration Dialect dialects.DialectName `toml:"-"` LogQueries *bool MaxIdleConns *int64 @@ -353,9 +354,9 @@ func (d *Database) setFrom(f *Database) { } type DatabaseListener struct { - MaxReconnectDuration *models.Duration - MinReconnectInterval *models.Duration - FallbackPollInterval *models.Duration + MaxReconnectDuration *commonconfig.Duration + MinReconnectInterval *commonconfig.Duration + FallbackPollInterval *commonconfig.Duration } func (d *DatabaseListener) setFrom(f *DatabaseListener) { @@ -372,8 +373,8 @@ func (d *DatabaseListener) setFrom(f *DatabaseListener) { type DatabaseLock struct { Enabled *bool - LeaseDuration *models.Duration - LeaseRefreshInterval *models.Duration + LeaseDuration *commonconfig.Duration + LeaseRefreshInterval *commonconfig.Duration } func (l *DatabaseLock) Mode() string { @@ -408,7 +409,7 @@ func (l *DatabaseLock) setFrom(f *DatabaseLock) { // Note: url is stored in Secrets.DatabaseBackupURL type DatabaseBackup struct { Dir *string - Frequency *models.Duration + Frequency *commonconfig.Duration Mode *config.DatabaseBackupMode OnVersionUpgrade *bool } @@ -433,19 +434,19 @@ type TelemetryIngress struct { Logging *bool BufferSize *uint16 MaxBatchSize *uint16 - SendInterval *models.Duration - SendTimeout *models.Duration + SendInterval *commonconfig.Duration + SendTimeout *commonconfig.Duration UseBatchSend *bool Endpoints []TelemetryIngressEndpoint `toml:",omitempty"` - URL *models.URL `toml:",omitempty"` // Deprecated: Use TelemetryIngressEndpoint.URL instead, this field will be removed in future versions - ServerPubKey *string `toml:",omitempty"` // Deprecated: Use TelemetryIngressEndpoint.ServerPubKey instead, this field will be removed in future versions + URL *commonconfig.URL `toml:",omitempty"` // Deprecated: Use TelemetryIngressEndpoint.URL instead, this field will be removed in future versions + ServerPubKey *string `toml:",omitempty"` // Deprecated: Use TelemetryIngressEndpoint.ServerPubKey instead, this field will be removed in future versions } type TelemetryIngressEndpoint struct { Network *string ChainID *string - URL *models.URL + URL *commonconfig.URL ServerPubKey *string } @@ -498,7 +499,7 @@ func (t *TelemetryIngress) ValidateConfig() (err error) { type AuditLogger struct { Enabled *bool - ForwardToUrl *models.URL + ForwardToUrl *commonconfig.URL JsonWrapperKey *string Headers *[]models.ServiceHeader } @@ -597,15 +598,15 @@ func (l *LogFile) setFrom(f *LogFile) { type WebServer struct { AuthenticationMethod *string AllowOrigins *string - BridgeResponseURL *models.URL - BridgeCacheTTL *models.Duration - HTTPWriteTimeout *models.Duration + BridgeResponseURL *commonconfig.URL + BridgeCacheTTL *commonconfig.Duration + HTTPWriteTimeout *commonconfig.Duration HTTPPort *uint16 SecureCookies *bool - SessionTimeout *models.Duration - SessionReaperExpiration *models.Duration + SessionTimeout *commonconfig.Duration + SessionReaperExpiration *commonconfig.Duration HTTPMaxSize *utils.FileSize - StartTimeout *models.Duration + StartTimeout *commonconfig.Duration ListenIP *net.IP LDAP WebServerLDAP `toml:",omitempty"` @@ -708,9 +709,9 @@ func (w *WebServerMFA) setFrom(f *WebServerMFA) { type WebServerRateLimit struct { Authenticated *int64 - AuthenticatedPeriod *models.Duration + AuthenticatedPeriod *commonconfig.Duration Unauthenticated *int64 - UnauthenticatedPeriod *models.Duration + UnauthenticatedPeriod *commonconfig.Duration } func (w *WebServerRateLimit) setFrom(f *WebServerRateLimit) { @@ -760,8 +761,8 @@ func (w *WebServerTLS) setFrom(f *WebServerTLS) { type WebServerLDAP struct { ServerTLS *bool - SessionTimeout *models.Duration - QueryTimeout *models.Duration + SessionTimeout *commonconfig.Duration + QueryTimeout *commonconfig.Duration BaseUserAttr *string BaseDN *string UsersDN *string @@ -773,9 +774,9 @@ type WebServerLDAP struct { RunUserGroupCN *string ReadUserGroupCN *string UserApiTokenEnabled *bool - UserAPITokenDuration *models.Duration - UpstreamSyncInterval *models.Duration - UpstreamSyncRateLimit *models.Duration + UserAPITokenDuration *commonconfig.Duration + UpstreamSyncInterval *commonconfig.Duration + UpstreamSyncRateLimit *commonconfig.Duration } func (w *WebServerLDAP) setFrom(f *WebServerLDAP) { @@ -864,10 +865,10 @@ func (w *WebServerSecrets) SetFrom(f *WebServerSecrets) error { type JobPipeline struct { ExternalInitiatorsEnabled *bool - MaxRunDuration *models.Duration + MaxRunDuration *commonconfig.Duration MaxSuccessfulRuns *uint64 - ReaperInterval *models.Duration - ReaperThreshold *models.Duration + ReaperInterval *commonconfig.Duration + ReaperThreshold *commonconfig.Duration ResultWriteQueueDepth *uint32 HTTPRequest JobPipelineHTTPRequest `toml:",omitempty"` @@ -897,7 +898,7 @@ func (j *JobPipeline) setFrom(f *JobPipeline) { } type JobPipelineHTTPRequest struct { - DefaultTimeout *models.Duration + DefaultTimeout *commonconfig.Duration MaxSize *utils.FileSize } @@ -927,11 +928,11 @@ func (m *FluxMonitor) setFrom(f *FluxMonitor) { type OCR2 struct { Enabled *bool ContractConfirmations *uint32 - BlockchainTimeout *models.Duration - ContractPollInterval *models.Duration - ContractSubscribeInterval *models.Duration - ContractTransmitterTransmitTimeout *models.Duration - DatabaseTimeout *models.Duration + BlockchainTimeout *commonconfig.Duration + ContractPollInterval *commonconfig.Duration + ContractSubscribeInterval *commonconfig.Duration + ContractTransmitterTransmitTimeout *commonconfig.Duration + DatabaseTimeout *commonconfig.Duration KeyBundleID *models.Sha256Hash CaptureEATelemetry *bool CaptureAutomationCustomTelemetry *bool @@ -984,10 +985,10 @@ func (o *OCR2) setFrom(f *OCR2) { type OCR struct { Enabled *bool - ObservationTimeout *models.Duration - BlockchainTimeout *models.Duration - ContractPollInterval *models.Duration - ContractSubscribeInterval *models.Duration + ObservationTimeout *commonconfig.Duration + BlockchainTimeout *commonconfig.Duration + ContractPollInterval *commonconfig.Duration + ContractSubscribeInterval *commonconfig.Duration DefaultTransactionQueueDepth *uint32 // Optional KeyBundleID *models.Sha256Hash @@ -1063,8 +1064,8 @@ type P2PV2 struct { Enabled *bool AnnounceAddresses *[]string DefaultBootstrappers *[]ocrcommontypes.BootstrapperLocator - DeltaDial *models.Duration - DeltaReconcile *models.Duration + DeltaDial *commonconfig.Duration + DeltaReconcile *commonconfig.Duration ListenAddresses *[]string } @@ -1128,7 +1129,7 @@ type KeeperRegistry struct { CheckGasOverhead *uint32 PerformGasOverhead *uint32 MaxPerformDataSize *uint32 - SyncInterval *models.Duration + SyncInterval *commonconfig.Duration SyncUpkeepQueueSize *uint32 } @@ -1153,9 +1154,9 @@ func (k *KeeperRegistry) setFrom(f *KeeperRegistry) { type AutoPprof struct { Enabled *bool ProfileRoot *string - PollInterval *models.Duration - GatherDuration *models.Duration - GatherTraceDuration *models.Duration + PollInterval *commonconfig.Duration + GatherDuration *commonconfig.Duration + GatherTraceDuration *commonconfig.Duration MaxProfileSize *utils.FileSize CPUProfileRate *int64 // runtime.SetCPUProfileRate MemProfileRate *int64 // runtime.MemProfileRate @@ -1287,9 +1288,9 @@ func (ins *Insecure) setFrom(f *Insecure) { } type MercuryCache struct { - LatestReportTTL *models.Duration - MaxStaleAge *models.Duration - LatestReportDeadline *models.Duration + LatestReportTTL *commonconfig.Duration + MaxStaleAge *commonconfig.Duration + LatestReportDeadline *commonconfig.Duration } func (mc *MercuryCache) setFrom(f *MercuryCache) { @@ -1304,12 +1305,37 @@ func (mc *MercuryCache) setFrom(f *MercuryCache) { } } +type MercuryTLS struct { + CertFile *string +} + +func (m *MercuryTLS) setFrom(f *MercuryTLS) { + if v := f.CertFile; v != nil { + m.CertFile = v + } +} + +func (m *MercuryTLS) ValidateConfig() (err error) { + if *m.CertFile != "" { + if !isValidFilePath(*m.CertFile) { + err = multierr.Append(err, configutils.ErrInvalid{Name: "CertFile", Value: *m.CertFile, Msg: "must be a valid file path"}) + } + } + return +} + type Mercury struct { Cache MercuryCache `toml:",omitempty"` + TLS MercuryTLS `toml:",omitempty"` } func (m *Mercury) setFrom(f *Mercury) { m.Cache.setFrom(&f.Cache) + m.TLS.setFrom(&f.TLS) +} + +func (m *Mercury) ValidateConfig() (err error) { + return m.TLS.ValidateConfig() } type MercuryCredentials struct { diff --git a/core/config/toml/types_test.go b/core/config/toml/types_test.go index e16d3a864da..9c3fd1d02df 100644 --- a/core/config/toml/types_test.go +++ b/core/config/toml/types_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/assert" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/build" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -109,13 +110,13 @@ func Test_validateDBURL(t *testing.T) { } func TestDatabaseSecrets_ValidateConfig(t *testing.T) { - validUrl := models.URL(url.URL{Scheme: "https", Host: "localhost"}) + validUrl := commonconfig.URL(url.URL{Scheme: "https", Host: "localhost"}) validSecretURL := *models.NewSecretURL(&validUrl) - invalidEmptyUrl := models.URL(url.URL{}) + invalidEmptyUrl := commonconfig.URL(url.URL{}) invalidEmptySecretURL := *models.NewSecretURL(&invalidEmptyUrl) - invalidBackupURL := models.URL(url.URL{Scheme: "http", Host: "localhost"}) + invalidBackupURL := commonconfig.URL(url.URL{Scheme: "http", Host: "localhost"}) invalidBackupSecretURL := *models.NewSecretURL(&invalidBackupURL) tests := []struct { @@ -531,5 +532,50 @@ func TestTracing_ValidateMode(t *testing.T) { } } +func TestMercuryTLS_ValidateTLSCertPath(t *testing.T) { + tests := []struct { + name string + tlsCertPath *string + wantErr bool + errMsg string + }{ + { + name: "valid file path", + tlsCertPath: ptr("/etc/ssl/certs/cert.pem"), + wantErr: false, + }, + { + name: "relative file path", + tlsCertPath: ptr("certs/cert.pem"), + wantErr: false, + }, + { + name: "excessively long file path", + tlsCertPath: ptr(strings.Repeat("z", 4097)), + wantErr: true, + errMsg: "CertFile: invalid value (" + strings.Repeat("z", 4097) + "): must be a valid file path", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mercury := &Mercury{ + TLS: MercuryTLS{ + CertFile: tt.tlsCertPath, + }, + } + + err := mercury.ValidateConfig() + + if tt.wantErr { + assert.Error(t, err) + assert.Equal(t, tt.errMsg, err.Error()) + } else { + assert.NoError(t, err) + } + }) + } +} + // ptr is a utility function for converting a value to a pointer to the value. func ptr[T any](t T) *T { return &t } diff --git a/core/config/web_config.go b/core/config/web_config.go index 429a31e7e82..1f1adc47f5d 100644 --- a/core/config/web_config.go +++ b/core/config/web_config.go @@ -7,7 +7,7 @@ import ( "github.com/gin-contrib/sessions" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" ) type TLS interface { @@ -37,7 +37,7 @@ type LDAP interface { ReadOnlyUserLogin() string ReadOnlyUserPass() string ServerTLS() bool - SessionTimeout() models.Duration + SessionTimeout() commonconfig.Duration QueryTimeout() time.Duration BaseUserAttr() string BaseDN() string @@ -50,9 +50,9 @@ type LDAP interface { RunUserGroupCN() string ReadUserGroupCN() string UserApiTokenEnabled() bool - UserAPITokenDuration() models.Duration - UpstreamSyncInterval() models.Duration - UpstreamSyncRateLimit() models.Duration + UserAPITokenDuration() commonconfig.Duration + UpstreamSyncInterval() commonconfig.Duration + UpstreamSyncRateLimit() commonconfig.Duration } type WebServer interface { @@ -64,10 +64,10 @@ type WebServer interface { StartTimeout() time.Duration HTTPWriteTimeout() time.Duration HTTPPort() uint16 - SessionReaperExpiration() models.Duration + SessionReaperExpiration() commonconfig.Duration SecureCookies() bool SessionOptions() sessions.Options - SessionTimeout() models.Duration + SessionTimeout() commonconfig.Duration ListenIP() net.IP TLS() TLS diff --git a/core/gethwrappers/generated/vrfv2_wrapper_load_test_consumer/vrfv2_wrapper_load_test_consumer.go b/core/gethwrappers/generated/vrfv2_wrapper_load_test_consumer/vrfv2_wrapper_load_test_consumer.go new file mode 100644 index 00000000000..9f59d32f0a5 --- /dev/null +++ b/core/gethwrappers/generated/vrfv2_wrapper_load_test_consumer/vrfv2_wrapper_load_test_consumer.go @@ -0,0 +1,1142 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package vrfv2_wrapper_load_test_consumer + +import ( + "errors" + "fmt" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +var VRFV2WrapperLoadTestConsumerMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_vrfV2Wrapper\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"}],\"name\":\"WrappedRequestFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"}],\"name\":\"WrapperRequestMade\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_vrfV2Wrapper\",\"outputs\":[{\"internalType\":\"contractVRFV2WrapperInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"makeRequests\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageFulfillmentInMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_responseCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + Bin: "0x60e0604052600060045560006005556103e76006553480156200002157600080fd5b50604051620017d6380380620017d68339810160408190526200004491620001cb565b6001600160601b0319606083811b821660805282901b1660a0523380600081620000b55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000e857620000e88162000102565b50505060601b6001600160601b03191660c0525062000203565b6001600160a01b0381163314156200015d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000ac565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001c657600080fd5b919050565b60008060408385031215620001df57600080fd5b620001ea83620001ae565b9150620001fa60208401620001ae565b90509250929050565b60805160601c60a05160601c60c05160601c61157e6200025860003960006101600152600081816103ad015281816106d401528181610cea0152610e1101526000818161054e0152610cc0015261157e6000f3fe6080604052600436106100f75760003560e01c80638da5cb5b1161008a578063d826f88f11610059578063d826f88f14610300578063d8a4676f1461032c578063dc1670db1461035f578063f2fde38b1461037557600080fd5b80638da5cb5b1461021e578063a168fa8914610249578063afacbf9c146102ca578063b1e21749146102ea57600080fd5b8063737144bc116100c6578063737144bc146101bd57806374dba124146101d357806379ba5097146101e95780637a8042bd146101fe57600080fd5b80631757f11c146101035780631fe543e31461012c5780632353f2381461014e578063557d2e92146101a757600080fd5b366100fe57005b600080fd5b34801561010f57600080fd5b5061011960055481565b6040519081526020015b60405180910390f35b34801561013857600080fd5b5061014c61014736600461118b565b610395565b005b34801561015a57600080fd5b506101827f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610123565b3480156101b357600080fd5b5061011960035481565b3480156101c957600080fd5b5061011960045481565b3480156101df57600080fd5b5061011960065481565b3480156101f557600080fd5b5061014c610447565b34801561020a57600080fd5b5061014c610219366004611159565b610544565b34801561022a57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610182565b34801561025557600080fd5b5061029d610264366004611159565b600960205260009081526040902080546001820154600383015460048401546005850154600690950154939460ff909316939192909186565b604080519687529415156020870152938501929092526060840152608083015260a082015260c001610123565b3480156102d657600080fd5b5061014c6102e536600461127a565b61064c565b3480156102f657600080fd5b5061011960075481565b34801561030c57600080fd5b5061014c6000600481905560058190556103e76006556003819055600255565b34801561033857600080fd5b5061034c610347366004611159565b61089a565b60405161012397969594939291906113ca565b34801561036b57600080fd5b5061011960025481565b34801561038157600080fd5b5061014c6103903660046110fa565b610a01565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610439576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f6f6e6c792056524620563220777261707065722063616e2066756c66696c6c0060448201526064015b60405180910390fd5b6104438282610a15565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146104c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610430565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61054c610bf1565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6105a760005473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015260248101849052604401602060405180830381600087803b15801561061457600080fd5b505af1158015610628573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104439190611137565b610654610bf1565b60005b8161ffff168161ffff161015610893576000610674868686610c74565b600781905590506000610685610eb5565b6040517f4306d35400000000000000000000000000000000000000000000000000000000815263ffffffff8916600482015290915060009073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634306d3549060240160206040518083038186803b15801561071657600080fd5b505afa15801561072a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074e9190611172565b6040805160e08101825282815260006020808301828152845183815280830186528486019081524260608601526080850184905260a0850189905260c0850184905289845260098352949092208351815591516001830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905592518051949550919390926107ee92600285019291019061106f565b5060608201516003808301919091556080830151600483015560a0830151600583015560c090920151600690910155805490600061082b836114da565b9091555050600083815260086020526040908190208390555183907f5f56b4c20db9f5b294cbf6f681368de4a992a27e2de2ee702dcf2cbbfa791ec4906108759084815260200190565b60405180910390a2505050808061088b906114b8565b915050610657565b5050505050565b6000818152600960205260408120548190606090829081908190819061091c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610430565b6000888152600960209081526040808320815160e08101835281548152600182015460ff1615158185015260028201805484518187028101870186528181529295939486019383018282801561099157602002820191906000526020600020905b81548152602001906001019080831161097d575b505050505081526020016003820154815260200160048201548152602001600582015481526020016006820154815250509050806000015181602001518260400151836060015184608001518560a001518660c00151975097509750975097509750975050919395979092949650565b610a09610bf1565b610a1281610f52565b50565b600082815260096020526040902054610a8a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610430565b6000610a94610eb5565b60008481526008602052604081205491925090610ab190836114a1565b90506000610ac282620f4240611464565b9050600554821115610ad45760058290555b600654821015610ae45760068290555b600060025411610af45780610b27565b600254610b02906001611411565b81600254600454610b139190611464565b610b1d9190611411565b610b279190611429565b60045560028054906000610b3a836114da565b90915550506000858152600960209081526040909120600181810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690911790558551610b929260029092019187019061106f565b5060008581526009602052604090819020426004820155600681018590555490517f6c84e12b4c188e61f1b4727024a5cf05c025fa58467e5eedf763c0744c89da7b91610be291889188916113a1565b60405180910390a15050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610c72576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610430565b565b6040517f4306d35400000000000000000000000000000000000000000000000000000000815263ffffffff8416600482015260009073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691634000aea0917f00000000000000000000000000000000000000000000000000000000000000009190821690634306d3549060240160206040518083038186803b158015610d2f57600080fd5b505afa158015610d43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d679190611172565b6040805163ffffffff808b16602083015261ffff8a169282019290925290871660608201526080016040516020818303038152906040526040518463ffffffff1660e01b8152600401610dbc93929190611309565b602060405180830381600087803b158015610dd657600080fd5b505af1158015610dea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0e9190611137565b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663fc2a88c36040518163ffffffff1660e01b815260040160206040518083038186803b158015610e7557600080fd5b505afa158015610e89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ead9190611172565b949350505050565b600046610ec181611048565b15610f4b57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f0d57600080fd5b505afa158015610f21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f459190611172565b91505090565b4391505090565b73ffffffffffffffffffffffffffffffffffffffff8116331415610fd2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610430565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061a4b182148061105c575062066eed82145b80611069575062066eee82145b92915050565b8280548282559060005260206000209081019282156110aa579160200282015b828111156110aa57825182559160200191906001019061108f565b506110b69291506110ba565b5090565b5b808211156110b657600081556001016110bb565b803561ffff811681146110e157600080fd5b919050565b803563ffffffff811681146110e157600080fd5b60006020828403121561110c57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461113057600080fd5b9392505050565b60006020828403121561114957600080fd5b8151801515811461113057600080fd5b60006020828403121561116b57600080fd5b5035919050565b60006020828403121561118457600080fd5b5051919050565b6000806040838503121561119e57600080fd5b8235915060208084013567ffffffffffffffff808211156111be57600080fd5b818601915086601f8301126111d257600080fd5b8135818111156111e4576111e4611542565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110858211171561122757611227611542565b604052828152858101935084860182860187018b101561124657600080fd5b600095505b8386101561126957803585526001959095019493860193860161124b565b508096505050505050509250929050565b6000806000806080858703121561129057600080fd5b611299856110e6565b93506112a7602086016110cf565b92506112b5604086016110e6565b91506112c3606086016110cf565b905092959194509250565b600081518084526020808501945080840160005b838110156112fe578151875295820195908201906001016112e2565b509495945050505050565b73ffffffffffffffffffffffffffffffffffffffff8416815260006020848184015260606040840152835180606085015260005b818110156113595785810183015185820160800152820161133d565b8181111561136b576000608083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160800195945050505050565b8381526060602082015260006113ba60608301856112ce565b9050826040830152949350505050565b878152861515602082015260e0604082015260006113eb60e08301886112ce565b90508560608301528460808301528360a08301528260c083015298975050505050505050565b6000821982111561142457611424611513565b500190565b60008261145f577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561149c5761149c611513565b500290565b6000828210156114b3576114b3611513565b500390565b600061ffff808316818114156114d0576114d0611513565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561150c5761150c611513565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", +} + +var VRFV2WrapperLoadTestConsumerABI = VRFV2WrapperLoadTestConsumerMetaData.ABI + +var VRFV2WrapperLoadTestConsumerBin = VRFV2WrapperLoadTestConsumerMetaData.Bin + +func DeployVRFV2WrapperLoadTestConsumer(auth *bind.TransactOpts, backend bind.ContractBackend, _link common.Address, _vrfV2Wrapper common.Address) (common.Address, *types.Transaction, *VRFV2WrapperLoadTestConsumer, error) { + parsed, err := VRFV2WrapperLoadTestConsumerMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(VRFV2WrapperLoadTestConsumerBin), backend, _link, _vrfV2Wrapper) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &VRFV2WrapperLoadTestConsumer{address: address, abi: *parsed, VRFV2WrapperLoadTestConsumerCaller: VRFV2WrapperLoadTestConsumerCaller{contract: contract}, VRFV2WrapperLoadTestConsumerTransactor: VRFV2WrapperLoadTestConsumerTransactor{contract: contract}, VRFV2WrapperLoadTestConsumerFilterer: VRFV2WrapperLoadTestConsumerFilterer{contract: contract}}, nil +} + +type VRFV2WrapperLoadTestConsumer struct { + address common.Address + abi abi.ABI + VRFV2WrapperLoadTestConsumerCaller + VRFV2WrapperLoadTestConsumerTransactor + VRFV2WrapperLoadTestConsumerFilterer +} + +type VRFV2WrapperLoadTestConsumerCaller struct { + contract *bind.BoundContract +} + +type VRFV2WrapperLoadTestConsumerTransactor struct { + contract *bind.BoundContract +} + +type VRFV2WrapperLoadTestConsumerFilterer struct { + contract *bind.BoundContract +} + +type VRFV2WrapperLoadTestConsumerSession struct { + Contract *VRFV2WrapperLoadTestConsumer + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type VRFV2WrapperLoadTestConsumerCallerSession struct { + Contract *VRFV2WrapperLoadTestConsumerCaller + CallOpts bind.CallOpts +} + +type VRFV2WrapperLoadTestConsumerTransactorSession struct { + Contract *VRFV2WrapperLoadTestConsumerTransactor + TransactOpts bind.TransactOpts +} + +type VRFV2WrapperLoadTestConsumerRaw struct { + Contract *VRFV2WrapperLoadTestConsumer +} + +type VRFV2WrapperLoadTestConsumerCallerRaw struct { + Contract *VRFV2WrapperLoadTestConsumerCaller +} + +type VRFV2WrapperLoadTestConsumerTransactorRaw struct { + Contract *VRFV2WrapperLoadTestConsumerTransactor +} + +func NewVRFV2WrapperLoadTestConsumer(address common.Address, backend bind.ContractBackend) (*VRFV2WrapperLoadTestConsumer, error) { + abi, err := abi.JSON(strings.NewReader(VRFV2WrapperLoadTestConsumerABI)) + if err != nil { + return nil, err + } + contract, err := bindVRFV2WrapperLoadTestConsumer(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &VRFV2WrapperLoadTestConsumer{address: address, abi: abi, VRFV2WrapperLoadTestConsumerCaller: VRFV2WrapperLoadTestConsumerCaller{contract: contract}, VRFV2WrapperLoadTestConsumerTransactor: VRFV2WrapperLoadTestConsumerTransactor{contract: contract}, VRFV2WrapperLoadTestConsumerFilterer: VRFV2WrapperLoadTestConsumerFilterer{contract: contract}}, nil +} + +func NewVRFV2WrapperLoadTestConsumerCaller(address common.Address, caller bind.ContractCaller) (*VRFV2WrapperLoadTestConsumerCaller, error) { + contract, err := bindVRFV2WrapperLoadTestConsumer(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &VRFV2WrapperLoadTestConsumerCaller{contract: contract}, nil +} + +func NewVRFV2WrapperLoadTestConsumerTransactor(address common.Address, transactor bind.ContractTransactor) (*VRFV2WrapperLoadTestConsumerTransactor, error) { + contract, err := bindVRFV2WrapperLoadTestConsumer(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &VRFV2WrapperLoadTestConsumerTransactor{contract: contract}, nil +} + +func NewVRFV2WrapperLoadTestConsumerFilterer(address common.Address, filterer bind.ContractFilterer) (*VRFV2WrapperLoadTestConsumerFilterer, error) { + contract, err := bindVRFV2WrapperLoadTestConsumer(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &VRFV2WrapperLoadTestConsumerFilterer{contract: contract}, nil +} + +func bindVRFV2WrapperLoadTestConsumer(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := VRFV2WrapperLoadTestConsumerMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFV2WrapperLoadTestConsumer.Contract.VRFV2WrapperLoadTestConsumerCaller.contract.Call(opts, result, method, params...) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.VRFV2WrapperLoadTestConsumerTransactor.contract.Transfer(opts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.VRFV2WrapperLoadTestConsumerTransactor.contract.Transact(opts, method, params...) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFV2WrapperLoadTestConsumer.Contract.contract.Call(opts, result, method, params...) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.contract.Transfer(opts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.contract.Transact(opts, method, params...) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, + + error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "getRequestStatus", _requestId) + + outstruct := new(GetRequestStatus) + if err != nil { + return *outstruct, err + } + + outstruct.Paid = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.Fulfilled = *abi.ConvertType(out[1], new(bool)).(*bool) + outstruct.RandomWords = *abi.ConvertType(out[2], new([]*big.Int)).(*[]*big.Int) + outstruct.RequestTimestamp = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.FulfilmentTimestamp = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int) + outstruct.RequestBlockNumber = *abi.ConvertType(out[5], new(*big.Int)).(**big.Int) + outstruct.FulfilmentBlockNumber = *abi.ConvertType(out[6], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) GetRequestStatus(_requestId *big.Int) (GetRequestStatus, + + error) { + return _VRFV2WrapperLoadTestConsumer.Contract.GetRequestStatus(&_VRFV2WrapperLoadTestConsumer.CallOpts, _requestId) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) GetRequestStatus(_requestId *big.Int) (GetRequestStatus, + + error) { + return _VRFV2WrapperLoadTestConsumer.Contract.GetRequestStatus(&_VRFV2WrapperLoadTestConsumer.CallOpts, _requestId) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) IVrfV2Wrapper(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "i_vrfV2Wrapper") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) IVrfV2Wrapper() (common.Address, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.IVrfV2Wrapper(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) IVrfV2Wrapper() (common.Address, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.IVrfV2Wrapper(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) Owner() (common.Address, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.Owner(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) Owner() (common.Address, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.Owner(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) SAverageFulfillmentInMillions(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "s_averageFulfillmentInMillions") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) SAverageFulfillmentInMillions() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SAverageFulfillmentInMillions(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) SAverageFulfillmentInMillions() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SAverageFulfillmentInMillions(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) SFastestFulfillment(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "s_fastestFulfillment") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) SFastestFulfillment() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SFastestFulfillment(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) SFastestFulfillment() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SFastestFulfillment(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) SLastRequestId(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "s_lastRequestId") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) SLastRequestId() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SLastRequestId(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) SLastRequestId() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SLastRequestId(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) SRequestCount(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "s_requestCount") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) SRequestCount() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SRequestCount(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) SRequestCount() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SRequestCount(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) SRequests(opts *bind.CallOpts, arg0 *big.Int) (SRequests, + + error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "s_requests", arg0) + + outstruct := new(SRequests) + if err != nil { + return *outstruct, err + } + + outstruct.Paid = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.Fulfilled = *abi.ConvertType(out[1], new(bool)).(*bool) + outstruct.RequestTimestamp = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) + outstruct.FulfilmentTimestamp = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.RequestBlockNumber = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int) + outstruct.FulfilmentBlockNumber = *abi.ConvertType(out[5], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) SRequests(arg0 *big.Int) (SRequests, + + error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SRequests(&_VRFV2WrapperLoadTestConsumer.CallOpts, arg0) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) SRequests(arg0 *big.Int) (SRequests, + + error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SRequests(&_VRFV2WrapperLoadTestConsumer.CallOpts, arg0) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) SResponseCount(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "s_responseCount") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) SResponseCount() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SResponseCount(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) SResponseCount() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SResponseCount(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) SSlowestFulfillment(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "s_slowestFulfillment") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) SSlowestFulfillment() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SSlowestFulfillment(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) SSlowestFulfillment() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SSlowestFulfillment(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.contract.Transact(opts, "acceptOwnership") +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) AcceptOwnership() (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.AcceptOwnership(&_VRFV2WrapperLoadTestConsumer.TransactOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.AcceptOwnership(&_VRFV2WrapperLoadTestConsumer.TransactOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactor) MakeRequests(opts *bind.TransactOpts, _callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32, _requestCount uint16) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.contract.Transact(opts, "makeRequests", _callbackGasLimit, _requestConfirmations, _numWords, _requestCount) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) MakeRequests(_callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32, _requestCount uint16) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.MakeRequests(&_VRFV2WrapperLoadTestConsumer.TransactOpts, _callbackGasLimit, _requestConfirmations, _numWords, _requestCount) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorSession) MakeRequests(_callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32, _requestCount uint16) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.MakeRequests(&_VRFV2WrapperLoadTestConsumer.TransactOpts, _callbackGasLimit, _requestConfirmations, _numWords, _requestCount) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactor) RawFulfillRandomWords(opts *bind.TransactOpts, _requestId *big.Int, _randomWords []*big.Int) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.contract.Transact(opts, "rawFulfillRandomWords", _requestId, _randomWords) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) RawFulfillRandomWords(_requestId *big.Int, _randomWords []*big.Int) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.RawFulfillRandomWords(&_VRFV2WrapperLoadTestConsumer.TransactOpts, _requestId, _randomWords) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorSession) RawFulfillRandomWords(_requestId *big.Int, _randomWords []*big.Int) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.RawFulfillRandomWords(&_VRFV2WrapperLoadTestConsumer.TransactOpts, _requestId, _randomWords) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactor) Reset(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.contract.Transact(opts, "reset") +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) Reset() (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.Reset(&_VRFV2WrapperLoadTestConsumer.TransactOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorSession) Reset() (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.Reset(&_VRFV2WrapperLoadTestConsumer.TransactOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.contract.Transact(opts, "transferOwnership", to) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.TransferOwnership(&_VRFV2WrapperLoadTestConsumer.TransactOpts, to) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.TransferOwnership(&_VRFV2WrapperLoadTestConsumer.TransactOpts, to) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactor) WithdrawLink(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.contract.Transact(opts, "withdrawLink", amount) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) WithdrawLink(amount *big.Int) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.WithdrawLink(&_VRFV2WrapperLoadTestConsumer.TransactOpts, amount) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorSession) WithdrawLink(amount *big.Int) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.WithdrawLink(&_VRFV2WrapperLoadTestConsumer.TransactOpts, amount) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.contract.RawTransact(opts, nil) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) Receive() (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.Receive(&_VRFV2WrapperLoadTestConsumer.TransactOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorSession) Receive() (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.Receive(&_VRFV2WrapperLoadTestConsumer.TransactOpts) +} + +type VRFV2WrapperLoadTestConsumerOwnershipTransferRequestedIterator struct { + Event *VRFV2WrapperLoadTestConsumerOwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFV2WrapperLoadTestConsumerOwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFV2WrapperLoadTestConsumerOwnershipTransferRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(VRFV2WrapperLoadTestConsumerOwnershipTransferRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *VRFV2WrapperLoadTestConsumerOwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *VRFV2WrapperLoadTestConsumerOwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFV2WrapperLoadTestConsumerOwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2WrapperLoadTestConsumerOwnershipTransferRequestedIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _VRFV2WrapperLoadTestConsumer.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &VRFV2WrapperLoadTestConsumerOwnershipTransferRequestedIterator{contract: _VRFV2WrapperLoadTestConsumer.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFV2WrapperLoadTestConsumerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _VRFV2WrapperLoadTestConsumer.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFV2WrapperLoadTestConsumerOwnershipTransferRequested) + if err := _VRFV2WrapperLoadTestConsumer.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) ParseOwnershipTransferRequested(log types.Log) (*VRFV2WrapperLoadTestConsumerOwnershipTransferRequested, error) { + event := new(VRFV2WrapperLoadTestConsumerOwnershipTransferRequested) + if err := _VRFV2WrapperLoadTestConsumer.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFV2WrapperLoadTestConsumerOwnershipTransferredIterator struct { + Event *VRFV2WrapperLoadTestConsumerOwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFV2WrapperLoadTestConsumerOwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFV2WrapperLoadTestConsumerOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(VRFV2WrapperLoadTestConsumerOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *VRFV2WrapperLoadTestConsumerOwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *VRFV2WrapperLoadTestConsumerOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFV2WrapperLoadTestConsumerOwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2WrapperLoadTestConsumerOwnershipTransferredIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _VRFV2WrapperLoadTestConsumer.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &VRFV2WrapperLoadTestConsumerOwnershipTransferredIterator{contract: _VRFV2WrapperLoadTestConsumer.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFV2WrapperLoadTestConsumerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _VRFV2WrapperLoadTestConsumer.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFV2WrapperLoadTestConsumerOwnershipTransferred) + if err := _VRFV2WrapperLoadTestConsumer.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) ParseOwnershipTransferred(log types.Log) (*VRFV2WrapperLoadTestConsumerOwnershipTransferred, error) { + event := new(VRFV2WrapperLoadTestConsumerOwnershipTransferred) + if err := _VRFV2WrapperLoadTestConsumer.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFV2WrapperLoadTestConsumerWrappedRequestFulfilledIterator struct { + Event *VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFV2WrapperLoadTestConsumerWrappedRequestFulfilledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *VRFV2WrapperLoadTestConsumerWrappedRequestFulfilledIterator) Error() error { + return it.fail +} + +func (it *VRFV2WrapperLoadTestConsumerWrappedRequestFulfilledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled struct { + RequestId *big.Int + RandomWords []*big.Int + Payment *big.Int + Raw types.Log +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) FilterWrappedRequestFulfilled(opts *bind.FilterOpts) (*VRFV2WrapperLoadTestConsumerWrappedRequestFulfilledIterator, error) { + + logs, sub, err := _VRFV2WrapperLoadTestConsumer.contract.FilterLogs(opts, "WrappedRequestFulfilled") + if err != nil { + return nil, err + } + return &VRFV2WrapperLoadTestConsumerWrappedRequestFulfilledIterator{contract: _VRFV2WrapperLoadTestConsumer.contract, event: "WrappedRequestFulfilled", logs: logs, sub: sub}, nil +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) WatchWrappedRequestFulfilled(opts *bind.WatchOpts, sink chan<- *VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled) (event.Subscription, error) { + + logs, sub, err := _VRFV2WrapperLoadTestConsumer.contract.WatchLogs(opts, "WrappedRequestFulfilled") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled) + if err := _VRFV2WrapperLoadTestConsumer.contract.UnpackLog(event, "WrappedRequestFulfilled", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) ParseWrappedRequestFulfilled(log types.Log) (*VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled, error) { + event := new(VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled) + if err := _VRFV2WrapperLoadTestConsumer.contract.UnpackLog(event, "WrappedRequestFulfilled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFV2WrapperLoadTestConsumerWrapperRequestMadeIterator struct { + Event *VRFV2WrapperLoadTestConsumerWrapperRequestMade + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFV2WrapperLoadTestConsumerWrapperRequestMadeIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFV2WrapperLoadTestConsumerWrapperRequestMade) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(VRFV2WrapperLoadTestConsumerWrapperRequestMade) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *VRFV2WrapperLoadTestConsumerWrapperRequestMadeIterator) Error() error { + return it.fail +} + +func (it *VRFV2WrapperLoadTestConsumerWrapperRequestMadeIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFV2WrapperLoadTestConsumerWrapperRequestMade struct { + RequestId *big.Int + Paid *big.Int + Raw types.Log +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) FilterWrapperRequestMade(opts *bind.FilterOpts, requestId []*big.Int) (*VRFV2WrapperLoadTestConsumerWrapperRequestMadeIterator, error) { + + var requestIdRule []interface{} + for _, requestIdItem := range requestId { + requestIdRule = append(requestIdRule, requestIdItem) + } + + logs, sub, err := _VRFV2WrapperLoadTestConsumer.contract.FilterLogs(opts, "WrapperRequestMade", requestIdRule) + if err != nil { + return nil, err + } + return &VRFV2WrapperLoadTestConsumerWrapperRequestMadeIterator{contract: _VRFV2WrapperLoadTestConsumer.contract, event: "WrapperRequestMade", logs: logs, sub: sub}, nil +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) WatchWrapperRequestMade(opts *bind.WatchOpts, sink chan<- *VRFV2WrapperLoadTestConsumerWrapperRequestMade, requestId []*big.Int) (event.Subscription, error) { + + var requestIdRule []interface{} + for _, requestIdItem := range requestId { + requestIdRule = append(requestIdRule, requestIdItem) + } + + logs, sub, err := _VRFV2WrapperLoadTestConsumer.contract.WatchLogs(opts, "WrapperRequestMade", requestIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFV2WrapperLoadTestConsumerWrapperRequestMade) + if err := _VRFV2WrapperLoadTestConsumer.contract.UnpackLog(event, "WrapperRequestMade", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) ParseWrapperRequestMade(log types.Log) (*VRFV2WrapperLoadTestConsumerWrapperRequestMade, error) { + event := new(VRFV2WrapperLoadTestConsumerWrapperRequestMade) + if err := _VRFV2WrapperLoadTestConsumer.contract.UnpackLog(event, "WrapperRequestMade", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type GetRequestStatus struct { + Paid *big.Int + Fulfilled bool + RandomWords []*big.Int + RequestTimestamp *big.Int + FulfilmentTimestamp *big.Int + RequestBlockNumber *big.Int + FulfilmentBlockNumber *big.Int +} +type SRequests struct { + Paid *big.Int + Fulfilled bool + RequestTimestamp *big.Int + FulfilmentTimestamp *big.Int + RequestBlockNumber *big.Int + FulfilmentBlockNumber *big.Int +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumer) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _VRFV2WrapperLoadTestConsumer.abi.Events["OwnershipTransferRequested"].ID: + return _VRFV2WrapperLoadTestConsumer.ParseOwnershipTransferRequested(log) + case _VRFV2WrapperLoadTestConsumer.abi.Events["OwnershipTransferred"].ID: + return _VRFV2WrapperLoadTestConsumer.ParseOwnershipTransferred(log) + case _VRFV2WrapperLoadTestConsumer.abi.Events["WrappedRequestFulfilled"].ID: + return _VRFV2WrapperLoadTestConsumer.ParseWrappedRequestFulfilled(log) + case _VRFV2WrapperLoadTestConsumer.abi.Events["WrapperRequestMade"].ID: + return _VRFV2WrapperLoadTestConsumer.ParseWrapperRequestMade(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (VRFV2WrapperLoadTestConsumerOwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (VRFV2WrapperLoadTestConsumerOwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled) Topic() common.Hash { + return common.HexToHash("0x6c84e12b4c188e61f1b4727024a5cf05c025fa58467e5eedf763c0744c89da7b") +} + +func (VRFV2WrapperLoadTestConsumerWrapperRequestMade) Topic() common.Hash { + return common.HexToHash("0x5f56b4c20db9f5b294cbf6f681368de4a992a27e2de2ee702dcf2cbbfa791ec4") +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumer) Address() common.Address { + return _VRFV2WrapperLoadTestConsumer.address +} + +type VRFV2WrapperLoadTestConsumerInterface interface { + GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, + + error) + + IVrfV2Wrapper(opts *bind.CallOpts) (common.Address, error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + SAverageFulfillmentInMillions(opts *bind.CallOpts) (*big.Int, error) + + SFastestFulfillment(opts *bind.CallOpts) (*big.Int, error) + + SLastRequestId(opts *bind.CallOpts) (*big.Int, error) + + SRequestCount(opts *bind.CallOpts) (*big.Int, error) + + SRequests(opts *bind.CallOpts, arg0 *big.Int) (SRequests, + + error) + + SResponseCount(opts *bind.CallOpts) (*big.Int, error) + + SSlowestFulfillment(opts *bind.CallOpts) (*big.Int, error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + MakeRequests(opts *bind.TransactOpts, _callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32, _requestCount uint16) (*types.Transaction, error) + + RawFulfillRandomWords(opts *bind.TransactOpts, _requestId *big.Int, _randomWords []*big.Int) (*types.Transaction, error) + + Reset(opts *bind.TransactOpts) (*types.Transaction, error) + + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + + WithdrawLink(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) + + Receive(opts *bind.TransactOpts) (*types.Transaction, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2WrapperLoadTestConsumerOwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFV2WrapperLoadTestConsumerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*VRFV2WrapperLoadTestConsumerOwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2WrapperLoadTestConsumerOwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFV2WrapperLoadTestConsumerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*VRFV2WrapperLoadTestConsumerOwnershipTransferred, error) + + FilterWrappedRequestFulfilled(opts *bind.FilterOpts) (*VRFV2WrapperLoadTestConsumerWrappedRequestFulfilledIterator, error) + + WatchWrappedRequestFulfilled(opts *bind.WatchOpts, sink chan<- *VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled) (event.Subscription, error) + + ParseWrappedRequestFulfilled(log types.Log) (*VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled, error) + + FilterWrapperRequestMade(opts *bind.FilterOpts, requestId []*big.Int) (*VRFV2WrapperLoadTestConsumerWrapperRequestMadeIterator, error) + + WatchWrapperRequestMade(opts *bind.WatchOpts, sink chan<- *VRFV2WrapperLoadTestConsumerWrapperRequestMade, requestId []*big.Int) (event.Subscription, error) + + ParseWrapperRequestMade(log types.Log) (*VRFV2WrapperLoadTestConsumerWrapperRequestMade, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 917d59dbb11..2079d89580b 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 @@ -101,6 +101,7 @@ vrfv2_transparent_upgradeable_proxy: ../../contracts/solc/v0.8.6/VRFV2Transparen vrfv2_wrapper: ../../contracts/solc/v0.8.6/VRFV2Wrapper/VRFV2Wrapper.abi ../../contracts/solc/v0.8.6/VRFV2Wrapper/VRFV2Wrapper.bin d5e9a982325d2d4f517c4f2bc818795f61555408ef4b38fb59b923d144970e38 vrfv2_wrapper_consumer_example: ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample/VRFV2WrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample/VRFV2WrapperConsumerExample.bin 3c5c9f1c501e697a7e77e959b48767e2a0bb1372393fd7686f7aaef3eb794231 vrfv2_wrapper_interface: ../../contracts/solc/v0.8.6/VRFV2WrapperInterface/VRFV2WrapperInterface.abi ../../contracts/solc/v0.8.6/VRFV2WrapperInterface/VRFV2WrapperInterface.bin ff8560169de171a68b360b7438d13863682d07040d984fd0fb096b2379421003 +vrfv2_wrapper_load_test_consumer: ../../contracts/solc/v0.8.6/VRFV2WrapperLoadTestConsumer/VRFV2WrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2WrapperLoadTestConsumer/VRFV2WrapperLoadTestConsumer.bin 664ca7fdf4dd65cc183bc25f20708c4b369c3401bba3ee12797a93bcd70138b6 vrfv2plus_client: ../../contracts/solc/v0.8.6/VRFV2PlusClient/VRFV2PlusClient.abi ../../contracts/solc/v0.8.6/VRFV2PlusClient/VRFV2PlusClient.bin 3ffbfa4971a7e5f46051a26b1722613f265d89ea1867547ecec58500953a9501 vrfv2plus_consumer_example: ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.bin 2c480a6d7955d33a00690fdd943486d95802e48a03f3cc243df314448e4ddb2c vrfv2plus_malicious_migrator: ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.abi ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.bin 80dbc98be5e42246960c889d29488f978d3db0127e95e9b295352c481d8c9b07 diff --git a/core/gethwrappers/go_generate.go b/core/gethwrappers/go_generate.go index 5a4ef541148..9bd3f2fd41a 100644 --- a/core/gethwrappers/go_generate.go +++ b/core/gethwrappers/go_generate.go @@ -108,6 +108,7 @@ package gethwrappers //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2Wrapper/VRFV2Wrapper.abi ../../contracts/solc/v0.8.6/VRFV2Wrapper/VRFV2Wrapper.bin VRFV2Wrapper vrfv2_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2WrapperInterface/VRFV2WrapperInterface.abi ../../contracts/solc/v0.8.6/VRFV2WrapperInterface/VRFV2WrapperInterface.bin VRFV2WrapperInterface vrfv2_wrapper_interface //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample/VRFV2WrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample/VRFV2WrapperConsumerExample.bin VRFV2WrapperConsumerExample vrfv2_wrapper_consumer_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2WrapperLoadTestConsumer/VRFV2WrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2WrapperLoadTestConsumer/VRFV2WrapperLoadTestConsumer.bin VRFV2WrapperLoadTestConsumer vrfv2_wrapper_load_test_consumer // Keepers X VRF v2 //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeepersVRFConsumer/KeepersVRFConsumer.abi ../../contracts/solc/v0.8.6/KeepersVRFConsumer/KeepersVRFConsumer.bin KeepersVRFConsumer keepers_vrf_consumer diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index fceb58ccdab..c7abfb31a2a 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -311,8 +311,6 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn auditLogger = audit.NoopLogger } - var eventBroadcaster pg.EventBroadcaster = pg.NewNullEventBroadcaster() - url := cfg.Database().URL() db, err := pg.NewConnection(url.String(), cfg.Database().Dialect(), cfg.Database()) require.NoError(t, err) @@ -329,8 +327,6 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn ethClient = dep case webhook.ExternalInitiatorManager: externalInitiatorManager = dep - case pg.EventBroadcaster: - eventBroadcaster = dep default: switch flag { case UseRealExternalInitiatorManager: @@ -360,10 +356,9 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn evmOpts := chainlink.EVMFactoryConfig{ ChainOpts: legacyevm.ChainOpts{ - AppConfig: cfg, - EventBroadcaster: eventBroadcaster, - MailMon: mailMon, - DB: db, + AppConfig: cfg, + MailMon: mailMon, + DB: db, }, CSAETHKeystore: keyStore, } @@ -416,7 +411,6 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn c := clhttptest.NewTestLocalOnlyHTTPClient() appInstance, err := chainlink.NewApplication(chainlink.ApplicationOpts{ Config: cfg, - EventBroadcaster: eventBroadcaster, MailMon: mailMon, SqlxDB: db, KeyStore: keyStore, @@ -698,27 +692,27 @@ type HTTPClientCleaner struct { } func (r *HTTPClientCleaner) Get(path string, headers ...map[string]string) (*http.Response, func()) { - resp, err := r.HTTPClient.Get(path, headers...) + resp, err := r.HTTPClient.Get(testutils.Context(r.t), path, headers...) return bodyCleaner(r.t, resp, err) } func (r *HTTPClientCleaner) Post(path string, body io.Reader) (*http.Response, func()) { - resp, err := r.HTTPClient.Post(path, body) + resp, err := r.HTTPClient.Post(testutils.Context(r.t), path, body) return bodyCleaner(r.t, resp, err) } func (r *HTTPClientCleaner) Put(path string, body io.Reader) (*http.Response, func()) { - resp, err := r.HTTPClient.Put(path, body) + resp, err := r.HTTPClient.Put(testutils.Context(r.t), path, body) return bodyCleaner(r.t, resp, err) } func (r *HTTPClientCleaner) Patch(path string, body io.Reader, headers ...map[string]string) (*http.Response, func()) { - resp, err := r.HTTPClient.Patch(path, body, headers...) + resp, err := r.HTTPClient.Patch(testutils.Context(r.t), path, body, headers...) return bodyCleaner(r.t, resp, err) } func (r *HTTPClientCleaner) Delete(path string) (*http.Response, func()) { - resp, err := r.HTTPClient.Delete(path) + resp, err := r.HTTPClient.Delete(testutils.Context(r.t), path) return bodyCleaner(r.t, resp, err) } @@ -878,10 +872,7 @@ func CreateExternalInitiatorViaWeb( t.Helper() client := app.NewHTTPClient(nil) - resp, cleanup := client.Post( - "/v2/external_initiators", - bytes.NewBufferString(payload), - ) + resp, cleanup := client.Post("/v2/external_initiators", bytes.NewBufferString(payload)) defer cleanup() AssertServerResponse(t, resp, http.StatusCreated) ei := &webpresenters.ExternalInitiatorAuthentication{} @@ -1131,7 +1122,7 @@ func unauthenticatedHTTP(t testing.TB, method string, url string, body io.Reader t.Helper() client := clhttptest.NewTestLocalOnlyHTTPClient() - request, err := http.NewRequest(method, url, body) + request, err := http.NewRequestWithContext(testutils.Context(t), method, url, body) require.NoError(t, err) request.Header.Set("Content-Type", "application/json") for key, value := range headers { diff --git a/core/internal/cltest/mocks.go b/core/internal/cltest/mocks.go index 073b3ba246c..fbfd820309a 100644 --- a/core/internal/cltest/mocks.go +++ b/core/internal/cltest/mocks.go @@ -355,7 +355,7 @@ func (m MockCookieAuthenticator) Cookie() (*http.Cookie, error) { return MustGenerateSessionCookie(m.t, m.SessionID), m.Error } -func (m MockCookieAuthenticator) Authenticate(sessions.SessionRequest) (*http.Cookie, error) { +func (m MockCookieAuthenticator) Authenticate(context.Context, sessions.SessionRequest) (*http.Cookie, error) { return MustGenerateSessionCookie(m.t, m.SessionID), m.Error } diff --git a/core/internal/cltest/simulated_backend.go b/core/internal/cltest/simulated_backend.go index 0aecc7f8324..cde060d7f4a 100644 --- a/core/internal/cltest/simulated_backend.go +++ b/core/internal/cltest/simulated_backend.go @@ -7,7 +7,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/core" - "github.com/google/uuid" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -16,7 +15,6 @@ import ( "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" ) func NewSimulatedBackend(t *testing.T, alloc core.GenesisAlloc, gasLimit uint32) *backends.SimulatedBackend { @@ -41,9 +39,8 @@ func NewApplicationWithConfigV2OnSimulatedBlockchain( require.Zero(t, evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()).Cmp(testutils.SimulatedChainID)) chainID := big.New(testutils.SimulatedChainID) client := client.NewSimulatedBackendClient(t, backend, testutils.SimulatedChainID) - eventBroadcaster := pg.NewEventBroadcaster(cfg.Database().URL(), 0, 0, logger.TestLogger(t), uuid.New()) - flagsAndDeps = append(flagsAndDeps, client, eventBroadcaster, chainID) + flagsAndDeps = append(flagsAndDeps, client, chainID) // app.Stop() will call client.Close on the simulated backend app := NewApplicationWithConfig(t, cfg, flagsAndDeps...) @@ -66,9 +63,8 @@ func NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain( require.Zero(t, evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()).Cmp(testutils.SimulatedChainID)) chainID := big.New(testutils.SimulatedChainID) client := client.NewSimulatedBackendClient(t, backend, testutils.SimulatedChainID) - eventBroadcaster := pg.NewEventBroadcaster(cfg.Database().URL(), 0, 0, logger.TestLogger(t), uuid.New()) - flagsAndDeps = append(flagsAndDeps, client, eventBroadcaster, chainID) + flagsAndDeps = append(flagsAndDeps, client, chainID) // app.Stop() will call client.Close on the simulated backend return NewApplicationWithConfigAndKey(t, cfg, flagsAndDeps...) diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index a0588f6abdc..1c4d097d633 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -39,6 +39,8 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting/confighelper" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -85,7 +87,7 @@ func TestIntegration_ExternalInitiatorV2(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.JobPipeline.ExternalInitiatorsEnabled = ptr(true) - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(10 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(10 * time.Millisecond) }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient, cltest.UseRealExternalInitiatorManager) @@ -362,7 +364,7 @@ func TestIntegration_DirectRequest(t *testing.T) { // Simulate a consumer contract calling to obtain ETH quotes in 3 different currencies // in a single callback. config := configtest.NewGeneralConfigSimulated(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(100 * time.Millisecond) c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) }) operatorContracts := setupOperatorContracts(t) @@ -467,7 +469,7 @@ func setupAppForEthTx(t *testing.T, operatorContracts OperatorContracts) (app *c lggr, o := logger.TestLoggerObserved(t, zapcore.DebugLevel) cfg := configtest.NewGeneralConfigSimulated(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(100 * time.Millisecond) }) app = cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, cfg, b, lggr) b.Commit() @@ -522,8 +524,8 @@ observationSource = """ cltest.AwaitJobActive(t, app.JobSpawner(), j.ID, testutils.WaitTimeout(t)) run := cltest.CreateJobRunViaUser(t, app, j.ExternalJobID, "") - assert.Equal(t, []*string([]*string(nil)), run.Outputs) - assert.Equal(t, []*string([]*string(nil)), run.Errors) + assert.Equal(t, []*string(nil), run.Outputs) + assert.Equal(t, []*string(nil), run.Errors) testutils.WaitForLogMessage(t, o, "Sending transaction") b.Commit() // Needs at least two confirmations @@ -568,8 +570,8 @@ observationSource = """ cltest.AwaitJobActive(t, app.JobSpawner(), j.ID, testutils.WaitTimeout(t)) run := cltest.CreateJobRunViaUser(t, app, j.ExternalJobID, "") - assert.Equal(t, []*string([]*string(nil)), run.Outputs) - assert.Equal(t, []*string([]*string(nil)), run.Errors) + assert.Equal(t, []*string(nil), run.Outputs) + assert.Equal(t, []*string(nil), run.Errors) testutils.WaitForLogMessage(t, o, "Sending transaction") b.Commit() // Needs at least two confirmations @@ -606,8 +608,8 @@ observationSource = """ cltest.AwaitJobActive(t, app.JobSpawner(), j.ID, testutils.WaitTimeout(t)) run := cltest.CreateJobRunViaUser(t, app, j.ExternalJobID, "") - assert.Equal(t, []*string([]*string(nil)), run.Outputs) - assert.Equal(t, []*string([]*string(nil)), run.Errors) + assert.Equal(t, []*string(nil), run.Outputs) + assert.Equal(t, []*string(nil), run.Errors) testutils.WaitForLogMessage(t, o, "Sending transaction") b.Commit() // Needs at least two confirmations @@ -689,10 +691,10 @@ func setupNode(t *testing.T, owner *bind.TransactOpts, portV2 int, c.P2P.V2.Enabled = ptr(true) c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", portV2)} - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) + c.P2P.V2.DeltaReconcile = commonconfig.MustNewDuration(5 * time.Second) // GracePeriod < ObservationTimeout - c.EVM[0].OCR.ObservationGracePeriod = models.MustNewDuration(100 * time.Millisecond) + c.EVM[0].OCR.ObservationGracePeriod = commonconfig.MustNewDuration(100 * time.Millisecond) if overrides != nil { overrides(c, s) @@ -732,7 +734,7 @@ func setupForwarderEnabledNode(t *testing.T, owner *bind.TransactOpts, portV2 in c.P2P.PeerID = ptr(p2pKey.PeerID()) c.P2P.V2.Enabled = ptr(true) c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", portV2)} - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) + c.P2P.V2.DeltaReconcile = commonconfig.MustNewDuration(5 * time.Second) c.EVM[0].Transactions.ForwardersEnabled = ptr(true) @@ -1318,7 +1320,7 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) { legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(cc) for _, re := range cc.Slice() { - require.NoError(t, re.Start(testutils.Context(t))) + servicetest.Run(t, re) } var newHeads evmtest.RawSub[*evmtypes.Head] select { @@ -1342,6 +1344,7 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) { elems := args.Get(1).([]rpc.BatchElem) elems[0].Result = &b43 }) + ethClient.On("Close").Return().Once() // Simulate one new head and check the gas price got updated h43 := cltest.Head(43) diff --git a/core/internal/features/ocr2/features_ocr2_test.go b/core/internal/features/ocr2/features_ocr2_test.go index 4727d686818..9a1a6d7537d 100644 --- a/core/internal/features/ocr2/features_ocr2_test.go +++ b/core/internal/features/ocr2/features_ocr2_test.go @@ -34,6 +34,7 @@ import ( confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" @@ -120,14 +121,14 @@ func setupNodeOCR2( c.P2P.PeerID = ptr(p2pKey.PeerID()) c.P2P.V2.Enabled = ptr(true) - c.P2P.V2.DeltaDial = models.MustNewDuration(500 * time.Millisecond) - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) + c.P2P.V2.DeltaDial = commonconfig.MustNewDuration(500 * time.Millisecond) + c.P2P.V2.DeltaReconcile = commonconfig.MustNewDuration(5 * time.Second) c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", port)} if len(p2pV2Bootstrappers) > 0 { c.P2P.V2.DefaultBootstrappers = &p2pV2Bootstrappers } - c.EVM[0].LogPollInterval = models.MustNewDuration(5 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(5 * time.Second) c.EVM[0].Transactions.ForwardersEnabled = &useForwarder }) diff --git a/core/internal/testutils/configtest/general_config.go b/core/internal/testutils/configtest/general_config.go index c414c973160..d2851035855 100644 --- a/core/internal/testutils/configtest/general_config.go +++ b/core/internal/testutils/configtest/general_config.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" @@ -45,21 +46,21 @@ func overrides(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) c.InsecureFastScrypt = ptr(true) - c.ShutdownGracePeriod = models.MustNewDuration(testutils.DefaultWaitTimeout) + c.ShutdownGracePeriod = commonconfig.MustNewDuration(testutils.DefaultWaitTimeout) c.Database.Dialect = dialects.TransactionWrappedPostgres c.Database.Lock.Enabled = ptr(false) c.Database.MaxIdleConns = ptr[int64](20) c.Database.MaxOpenConns = ptr[int64](20) c.Database.MigrateOnStartup = ptr(false) - c.Database.DefaultLockTimeout = models.MustNewDuration(1 * time.Minute) + c.Database.DefaultLockTimeout = commonconfig.MustNewDuration(1 * time.Minute) - c.JobPipeline.ReaperInterval = models.MustNewDuration(0) + c.JobPipeline.ReaperInterval = commonconfig.MustNewDuration(0) c.P2P.V2.Enabled = ptr(false) - c.WebServer.SessionTimeout = models.MustNewDuration(2 * time.Minute) - c.WebServer.BridgeResponseURL = models.MustParseURL("http://localhost:6688") + c.WebServer.SessionTimeout = commonconfig.MustNewDuration(2 * time.Minute) + c.WebServer.BridgeResponseURL = commonconfig.MustParseURL("http://localhost:6688") testIP := net.ParseIP("127.0.0.1") c.WebServer.ListenIP = &testIP c.WebServer.TLS.ListenIP = &testIP @@ -71,8 +72,8 @@ func overrides(c *chainlink.Config, s *chainlink.Secrets) { Nodes: evmcfg.EVMNodes{ &evmcfg.Node{ Name: ptr("test"), - WSURL: &models.URL{}, - HTTPURL: &models.URL{}, + WSURL: &commonconfig.URL{}, + HTTPURL: &commonconfig.URL{}, SendOnly: new(bool), Order: ptr[int32](100), }, @@ -112,8 +113,8 @@ func simulated(c *chainlink.Config, s *chainlink.Secrets) { var validTestNode = evmcfg.Node{ Name: ptr("simulated-node"), - WSURL: models.MustParseURL("WSS://simulated-wss.com/ws"), - HTTPURL: models.MustParseURL("http://simulated.com"), + WSURL: commonconfig.MustParseURL("WSS://simulated-wss.com/ws"), + HTTPURL: commonconfig.MustParseURL("http://simulated.com"), SendOnly: nil, Order: ptr(int32(1)), } diff --git a/core/internal/testutils/evmtest/evmtest.go b/core/internal/testutils/evmtest/evmtest.go index 9397db53acb..cc56c3c9e9b 100644 --- a/core/internal/testutils/evmtest/evmtest.go +++ b/core/internal/testutils/evmtest/evmtest.go @@ -37,7 +37,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/relay" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) @@ -87,11 +86,10 @@ func NewChainRelayExtOpts(t testing.TB, testopts TestChainOpts) legacyevm.ChainR Logger: lggr, KeyStore: testopts.KeyStore, ChainOpts: legacyevm.ChainOpts{ - AppConfig: testopts.GeneralConfig, - EventBroadcaster: pg.NewNullEventBroadcaster(), - MailMon: testopts.MailMon, - GasEstimator: testopts.GasEstimator, - DB: testopts.DB, + AppConfig: testopts.GeneralConfig, + MailMon: testopts.MailMon, + GasEstimator: testopts.GasEstimator, + DB: testopts.DB, }, } opts.GenEthClient = func(*big.Int) evmclient.Client { diff --git a/core/logger/audit/audit_logger.go b/core/logger/audit/audit_logger.go index ef66a063a55..2f96c40586f 100644 --- a/core/logger/audit/audit_logger.go +++ b/core/logger/audit/audit_logger.go @@ -13,8 +13,8 @@ import ( "os" "time" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -38,7 +38,7 @@ type HTTPAuditLoggerInterface interface { type AuditLoggerService struct { logger logger.Logger // The standard logger configured in the node enabled bool // Whether the audit logger is enabled or not - forwardToUrl models.URL // Location we are going to send logs to + forwardToUrl commonconfig.URL // Location we are going to send logs to headers []models.ServiceHeader // Headers to be sent along with logs for identification/authentication jsonWrapperKey string // Wrap audit data as a map under this key if present environmentName string // Decorate the environment this is coming from diff --git a/core/logger/audit/audit_logger_test.go b/core/logger/audit/audit_logger_test.go index 576d11df3a4..a28c35b129d 100644 --- a/core/logger/audit/audit_logger_test.go +++ b/core/logger/audit/audit_logger_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -65,10 +66,10 @@ func (c Config) Environment() string { return "test" } -func (c Config) ForwardToUrl() (models.URL, error) { - url, err := models.ParseURL("http://localhost:9898") +func (c Config) ForwardToUrl() (commonconfig.URL, error) { + url, err := commonconfig.ParseURL("http://localhost:9898") if err != nil { - return models.URL{}, err + return commonconfig.URL{}, err } return *url, nil } diff --git a/core/null/int64.go b/core/null/int64.go index 2a31aea7594..ca236784486 100644 --- a/core/null/int64.go +++ b/core/null/int64.go @@ -43,7 +43,7 @@ func (i *Int64) UnmarshalJSON(data []byte) error { // Unmarshal again, directly to value, to avoid intermediate float64 err = json.Unmarshal(data, &i.Int64) case string: - str := string(x) + str := x if len(str) == 0 { i.Valid = false return nil @@ -85,7 +85,7 @@ func (i Int64) MarshalJSON() ([]byte, error) { if !i.Valid { return []byte("null"), nil } - return []byte(strconv.FormatInt(int64(i.Int64), 10)), nil + return []byte(strconv.FormatInt(i.Int64, 10)), nil } // MarshalText implements encoding.TextMarshaler. @@ -94,7 +94,7 @@ func (i Int64) MarshalText() ([]byte, error) { if !i.Valid { return []byte{}, nil } - return []byte(strconv.FormatInt(int64(i.Int64), 10)), nil + return []byte(strconv.FormatInt(i.Int64, 10)), nil } // SetValid changes this Int64's value and also sets it to be non-null. @@ -112,7 +112,7 @@ func (i Int64) Value() (driver.Value, error) { // golang's sql driver types as determined by IsValue only supports: // []byte, bool, float64, int64, string, time.Time // https://golang.org/src/database/sql/driver/types.go - return int64(i.Int64), nil + return i.Int64, nil } // Scan reads the database value and returns an instance. @@ -130,7 +130,7 @@ func (i *Int64) Scan(value interface{}) error { safe := int64(typed) *i = Int64From(safe) case int64: - safe := int64(typed) + safe := typed *i = Int64From(safe) case uint: if typed > uint(math.MaxInt64) { diff --git a/core/null/uint32.go b/core/null/uint32.go index 0bafef0c24e..1d4fbc15b79 100644 --- a/core/null/uint32.go +++ b/core/null/uint32.go @@ -42,7 +42,7 @@ func (i *Uint32) UnmarshalJSON(data []byte) error { // Unmarshal again, directly to value, to avoid intermediate float64 err = json.Unmarshal(data, &i.Uint32) case string: - str := string(x) + str := x if len(str) == 0 { i.Valid = false return nil diff --git a/core/scripts/chaincli/.env.debugging.example b/core/scripts/chaincli/.env.debugging.example new file mode 100644 index 00000000000..6934bb107f5 --- /dev/null +++ b/core/scripts/chaincli/.env.debugging.example @@ -0,0 +1,15 @@ +# [Mandatory] http url of the archival node for your network +NODE_URL= +# [Mandatory] address of the KeeperRegistry contract for your upkeep +KEEPER_REGISTRY_ADDRESS= + +# [Optional] it is strongly recommended (not mandatory) to use tenderly for more debugging info +#TENDERLY_KEY= +#TENDERLY_ACCOUNT_NAME= +#TENDERLY_PROJECT_NAME= + +# [Optional] add mercury info only if your upkeep uses mercury +#MERCURY_ID= +#MERCURY_KEY= +#MERCURY_LEGACY_URL= +#MERCURY_URL= \ No newline at end of file diff --git a/core/scripts/chaincli/handler/bootstrap.go b/core/scripts/chaincli/handler/bootstrap.go index 4cc19299cca..bf79f5698dc 100644 --- a/core/scripts/chaincli/handler/bootstrap.go +++ b/core/scripts/chaincli/handler/bootstrap.go @@ -47,17 +47,17 @@ func (h *baseHandler) StartBootstrapNode(ctx context.Context, addr string, uiPor lggr.Fatal("Failed to launch chainlink node, ", err) } - cl, err := authenticate(urlRaw, defaultChainlinkNodeLogin, defaultChainlinkNodePassword, lggr) + cl, err := authenticate(ctx, urlRaw, defaultChainlinkNodeLogin, defaultChainlinkNodePassword, lggr) if err != nil { lggr.Fatal("Authentication failed, ", err) } - p2pKeyID, err := getP2PKeyID(cl) + p2pKeyID, err := getP2PKeyID(ctx, cl) if err != nil { lggr.Fatal("Failed to get P2P key ID, ", err) } - if err = h.createBootstrapJob(cl, addr); err != nil { + if err = h.createBootstrapJob(ctx, cl, addr); err != nil { lggr.Fatal("Failed to create keeper job: ", err) } @@ -68,7 +68,7 @@ func (h *baseHandler) StartBootstrapNode(ctx context.Context, addr string, uiPor } // createBootstrapJob creates a bootstrap job in the chainlink node by the given address -func (h *baseHandler) createBootstrapJob(client cmd.HTTPClient, contractAddr string) error { +func (h *baseHandler) createBootstrapJob(ctx context.Context, client cmd.HTTPClient, contractAddr string) error { request, err := json.Marshal(web.CreateJobRequest{ TOML: fmt.Sprintf(bootstrapJobSpec, contractAddr, h.cfg.ChainID), }) @@ -76,7 +76,7 @@ func (h *baseHandler) createBootstrapJob(client cmd.HTTPClient, contractAddr str return fmt.Errorf("failed to marshal request: %s", err) } - resp, err := client.Post("/v2/jobs", bytes.NewReader(request)) + resp, err := client.Post(ctx, "/v2/jobs", bytes.NewReader(request)) if err != nil { return fmt.Errorf("failed to create bootstrap job: %s", err) } diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go index 46b0e42e2a0..c317edcac37 100644 --- a/core/scripts/chaincli/handler/debug.go +++ b/core/scripts/chaincli/handler/debug.go @@ -25,6 +25,7 @@ import ( evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" commonhex "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" + "github.com/smartcontractkit/chainlink/core/scripts/chaincli/config" "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" @@ -149,7 +150,7 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if err != nil { failUnknown("failed to pack raw checkUpkeep call", err) } - addLink("checkUpkeep simulation", tenderlySimLink(k.cfg, chainID, 0, rawCall, registryAddress)) + addLink("checkUpkeep simulation", tenderlySimLink(ctx, k.cfg, chainID, 0, rawCall, registryAddress)) } else if triggerType == LogTrigger { // validate inputs message("upkeep identified as log trigger") @@ -242,9 +243,9 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if err != nil { failUnknown("failed to pack raw checkUpkeep call", err) } - addLink("checkUpkeep simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, registryAddress)) + addLink("checkUpkeep simulation", tenderlySimLink(ctx, k.cfg, chainID, blockNum, rawCall, registryAddress)) rawCall = append(core.ILogAutomationABI.Methods["checkLog"].ID, triggerData...) - addLink("checkLog (direct) simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, upkeepInfo.Target)) + addLink("checkLog (direct) simulation", tenderlySimLink(ctx, k.cfg, chainID, blockNum, rawCall, upkeepInfo.Target)) } else { resolveIneligible(fmt.Sprintf("invalid trigger type: %d", triggerType)) } @@ -333,12 +334,12 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if err != nil { failUnknown("failed to pack raw checkCallback call", err) } - addLink("checkCallback simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, registryAddress)) + addLink("checkCallback simulation", tenderlySimLink(ctx, k.cfg, chainID, blockNum, rawCall, registryAddress)) rawCall, err = core.StreamsCompatibleABI.Pack("checkCallback", values, streamsLookup.ExtraData) if err != nil { failUnknown("failed to pack raw checkCallback (direct) call", err) } - addLink("checkCallback (direct) simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, upkeepInfo.Target)) + addLink("checkCallback (direct) simulation", tenderlySimLink(ctx, k.cfg, chainID, blockNum, rawCall, upkeepInfo.Target)) } else { message("did not revert with StreamsLookup error") } @@ -357,12 +358,22 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if err != nil { failUnknown("failed to pack raw simulatePerformUpkeep call", err) } - addLink("simulatePerformUpkeep simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, registryAddress)) + addLink("simulatePerformUpkeep simulation", tenderlySimLink(ctx, k.cfg, chainID, blockNum, rawCall, registryAddress)) if simulateResult.Success { resolveEligible() } else { - resolveIneligible("simulate perform upkeep unsuccessful") + // Convert performGas to *big.Int for comparison + performGasBigInt := new(big.Int).SetUint64(uint64(upkeepInfo.PerformGas)) + // Compare PerformGas and GasUsed + result := performGasBigInt.Cmp(simulateResult.GasUsed) + + if result < 0 { + // PerformGas is smaller than GasUsed + resolveIneligible(fmt.Sprintf("simulate perform upkeep unsuccessful, PerformGas (%d) is lower than GasUsed (%s)", upkeepInfo.PerformGas, simulateResult.GasUsed.String())) + } else { + resolveIneligible("simulate perform upkeep unsuccessful") + } } } @@ -525,7 +536,7 @@ type TenderlyAPIResponse struct { } } -func tenderlySimLink(cfg *config.Config, chainID int64, blockNumber uint64, input []byte, contractAddress gethcommon.Address) string { +func tenderlySimLink(ctx context.Context, cfg *config.Config, chainID int64, blockNumber uint64, input []byte, contractAddress gethcommon.Address) string { errResult := "" if cfg.TenderlyAccountName == "" || cfg.TenderlyKey == "" || cfg.TenderlyProjectName == "" { warning("tenderly credentials not properly configured - this is optional but helpful") @@ -547,7 +558,8 @@ func tenderlySimLink(cfg *config.Config, chainID int64, blockNumber uint64, inpu warning(fmt.Sprintf("unable to marshal tenderly request data: %v", err)) return errResult } - request, err := http.NewRequest( + request, err := http.NewRequestWithContext( + ctx, "POST", fmt.Sprintf("https://api.tenderly.co/api/v1/account/%s/project/%s/simulate", cfg.TenderlyAccountName, cfg.TenderlyProjectName), bytes.NewBuffer(jsonData), diff --git a/core/scripts/chaincli/handler/handler.go b/core/scripts/chaincli/handler/handler.go index 6423df3aa23..591431555a9 100644 --- a/core/scripts/chaincli/handler/handler.go +++ b/core/scripts/chaincli/handler/handler.go @@ -399,7 +399,7 @@ func (h *baseHandler) launchChainlinkNode(ctx context.Context, port int, contain addr := fmt.Sprintf("http://localhost:%s", portStr) log.Println("Node docker container successfully created and started: ", nodeContainerResp.ID, addr) - if err = waitForNodeReady(addr); err != nil { + if err = waitForNodeReady(ctx, addr); err != nil { log.Fatal(err, nodeContainerResp.ID) } log.Println("Node ready: ", nodeContainerResp.ID) @@ -477,13 +477,13 @@ func checkAndRemoveContainer(ctx context.Context, dockerClient *client.Client, c return nil } -func waitForNodeReady(addr string) error { +func waitForNodeReady(ctx context.Context, addr string) error { client := &http.Client{} defer client.CloseIdleConnections() const timeout = 120 startTime := time.Now().Unix() for { - req, err := http.NewRequest("GET", fmt.Sprintf("%s/health", addr), nil) + req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/health", addr), nil) if err != nil { return err } @@ -503,7 +503,7 @@ func waitForNodeReady(addr string) error { } // authenticate creates a http client with URL, email and password -func authenticate(urlStr, email, password string, lggr logger.Logger) (cmd.HTTPClient, error) { +func authenticate(ctx context.Context, urlStr, email, password string, lggr logger.Logger) (cmd.HTTPClient, error) { remoteNodeURL, err := url.Parse(urlStr) if err != nil { return nil, err @@ -514,7 +514,7 @@ func authenticate(urlStr, email, password string, lggr logger.Logger) (cmd.HTTPC store := &cmd.MemoryCookieStore{} tca := cmd.NewSessionCookieAuthenticator(c, store, lggr) - if _, err = tca.Authenticate(sr); err != nil { + if _, err = tca.Authenticate(ctx, sr); err != nil { log.Println("failed to authenticate: ", err) return nil, err } @@ -522,8 +522,8 @@ func authenticate(urlStr, email, password string, lggr logger.Logger) (cmd.HTTPC return cmd.NewAuthenticatedHTTPClient(lggr, c, tca, sr), nil } -func nodeRequest(client cmd.HTTPClient, path string) ([]byte, error) { - resp, err := client.Get(path) +func nodeRequest(ctx context.Context, client cmd.HTTPClient, path string) ([]byte, error) { + resp, err := client.Get(ctx, path) if err != nil { return []byte{}, fmt.Errorf("GET error from client: %w", err) } @@ -551,8 +551,8 @@ func nodeRequest(client cmd.HTTPClient, path string) ([]byte, error) { } // getNodeAddress returns chainlink node's wallet address -func getNodeAddress(client cmd.HTTPClient) (string, error) { - resp, err := nodeRequest(client, ethKeysEndpoint) +func getNodeAddress(ctx context.Context, client cmd.HTTPClient) (string, error) { + resp, err := nodeRequest(ctx, client, ethKeysEndpoint) if err != nil { return "", fmt.Errorf("failed to get ETH keys: %w", err) } @@ -566,8 +566,8 @@ func getNodeAddress(client cmd.HTTPClient) (string, error) { } // getNodeOCR2Config returns chainlink node's OCR2 bundle key ID -func getNodeOCR2Config(client cmd.HTTPClient) (*cmd.OCR2KeyBundlePresenter, error) { - resp, err := nodeRequest(client, ocr2KeysEndpoint) +func getNodeOCR2Config(ctx context.Context, client cmd.HTTPClient) (*cmd.OCR2KeyBundlePresenter, error) { + resp, err := nodeRequest(ctx, client, ocr2KeysEndpoint) if err != nil { return nil, fmt.Errorf("failed to get OCR2 keys: %w", err) } @@ -589,8 +589,8 @@ func getNodeOCR2Config(client cmd.HTTPClient) (*cmd.OCR2KeyBundlePresenter, erro } // getP2PKeyID returns chainlink node's P2P key ID -func getP2PKeyID(client cmd.HTTPClient) (string, error) { - resp, err := nodeRequest(client, p2pKeysEndpoint) +func getP2PKeyID(ctx context.Context, client cmd.HTTPClient) (string, error) { + resp, err := nodeRequest(ctx, client, p2pKeysEndpoint) if err != nil { return "", fmt.Errorf("failed to get P2P keys: %w", err) } diff --git a/core/scripts/chaincli/handler/jobs.go b/core/scripts/chaincli/handler/jobs.go index 9787d7fc175..89f1a3ea5bc 100644 --- a/core/scripts/chaincli/handler/jobs.go +++ b/core/scripts/chaincli/handler/jobs.go @@ -8,10 +8,10 @@ import ( ) func (k *Keeper) CreateJob(ctx context.Context) { - k.createJobs() + k.createJobs(ctx) } -func (k *Keeper) createJobs() { +func (k *Keeper) createJobs(ctx context.Context) { lggr, closeLggr := logger.NewLogger() logger.Sugared(lggr).ErrorIfFn(closeLggr, "Failed to close logger") @@ -27,12 +27,12 @@ func (k *Keeper) createJobs() { pwd = defaultChainlinkNodePassword } - cl, err := authenticate(url, email, pwd, lggr) + cl, err := authenticate(ctx, url, email, pwd, lggr) if err != nil { log.Fatal(err) } - if err = k.createKeeperJob(cl, k.cfg.RegistryAddress, keeperAddr); err != nil { + if err = k.createKeeperJob(ctx, cl, k.cfg.RegistryAddress, keeperAddr); err != nil { log.Fatal(err) } } diff --git a/core/scripts/chaincli/handler/keeper.go b/core/scripts/chaincli/handler/keeper.go index a5fb505adb4..1f56eb14080 100644 --- a/core/scripts/chaincli/handler/keeper.go +++ b/core/scripts/chaincli/handler/keeper.go @@ -77,13 +77,13 @@ func (k *Keeper) DeployKeepers(ctx context.Context) { pwd = defaultChainlinkNodePassword } - cl, err := authenticate(url, email, pwd, lggr) + cl, err := authenticate(ctx, url, email, pwd, lggr) if err != nil { log.Fatal(err) } cls[i] = cl - if err = k.createKeeperJob(cl, k.cfg.RegistryAddress, keeperAddr); err != nil { + if err = k.createKeeperJob(ctx, cl, k.cfg.RegistryAddress, keeperAddr); err != nil { log.Fatal(err) } } @@ -753,7 +753,8 @@ func (k *Keeper) deployUpkeeps(ctx context.Context, registryAddr common.Address, func (k *Keeper) setKeepers(ctx context.Context, cls []cmd.HTTPClient, deployer keepersDeployer, keepers, owners []common.Address) { if len(keepers) > 0 { log.Println("Set keepers...") - setKeepersTx, err := deployer.SetKeepers(k.buildTxOpts(ctx), cls, keepers, owners) + opts := k.buildTxOpts(ctx) + setKeepersTx, err := deployer.SetKeepers(ctx, opts, cls, keepers, owners) if err != nil { log.Fatal("SetKeepers failed: ", err) } diff --git a/core/scripts/chaincli/handler/keeper_deployer.go b/core/scripts/chaincli/handler/keeper_deployer.go index 7c532753426..118cbbb0ff9 100644 --- a/core/scripts/chaincli/handler/keeper_deployer.go +++ b/core/scripts/chaincli/handler/keeper_deployer.go @@ -1,6 +1,7 @@ package handler import ( + "context" "crypto/ed25519" "encoding/hex" "encoding/json" @@ -48,14 +49,14 @@ type upkeepDeployer interface { type keepersDeployer interface { canceller upkeepDeployer - SetKeepers(opts *bind.TransactOpts, _ []cmd.HTTPClient, keepers []common.Address, payees []common.Address) (*types.Transaction, error) + SetKeepers(ctx context.Context, opts *bind.TransactOpts, _ []cmd.HTTPClient, keepers []common.Address, payees []common.Address) (*types.Transaction, error) } type v11KeeperDeployer struct { registry11.KeeperRegistryInterface } -func (d *v11KeeperDeployer) SetKeepers(opts *bind.TransactOpts, _ []cmd.HTTPClient, keepers []common.Address, payees []common.Address) (*types.Transaction, error) { +func (d *v11KeeperDeployer) SetKeepers(ctx context.Context, opts *bind.TransactOpts, _ []cmd.HTTPClient, keepers []common.Address, payees []common.Address) (*types.Transaction, error) { return d.KeeperRegistryInterface.SetKeepers(opts, keepers, payees) } @@ -71,7 +72,7 @@ type v12KeeperDeployer struct { registry12.KeeperRegistryInterface } -func (d *v12KeeperDeployer) SetKeepers(opts *bind.TransactOpts, _ []cmd.HTTPClient, keepers []common.Address, payees []common.Address) (*types.Transaction, error) { +func (d *v12KeeperDeployer) SetKeepers(ctx context.Context, opts *bind.TransactOpts, _ []cmd.HTTPClient, keepers []common.Address, payees []common.Address) (*types.Transaction, error) { return d.KeeperRegistryInterface.SetKeepers(opts, keepers, payees) } @@ -88,7 +89,7 @@ type v20KeeperDeployer struct { cfg *config.Config } -func (d *v20KeeperDeployer) SetKeepers(opts *bind.TransactOpts, cls []cmd.HTTPClient, keepers []common.Address, _ []common.Address) (*types.Transaction, error) { +func (d *v20KeeperDeployer) SetKeepers(ctx context.Context, opts *bind.TransactOpts, cls []cmd.HTTPClient, keepers []common.Address, _ []common.Address) (*types.Transaction, error) { S := make([]int, len(cls)) oracleIdentities := make([]ocr2config.OracleIdentityExtra, len(cls)) sharedSecretEncryptionPublicKeys := make([]ocr2types.ConfigEncryptionPublicKey, len(cls)) @@ -98,12 +99,12 @@ func (d *v20KeeperDeployer) SetKeepers(opts *bind.TransactOpts, cls []cmd.HTTPCl go func(i int, cl cmd.HTTPClient) { defer wg.Done() - ocr2Config, err := getNodeOCR2Config(cl) + ocr2Config, err := getNodeOCR2Config(ctx, cl) if err != nil { panic(err) } - p2pKeyID, err := getP2PKeyID(cl) + p2pKeyID, err := getP2PKeyID(ctx, cl) if err != nil { panic(err) } @@ -228,7 +229,7 @@ type v21KeeperDeployer struct { cfg *config.Config } -func (d *v21KeeperDeployer) SetKeepers(opts *bind.TransactOpts, cls []cmd.HTTPClient, keepers []common.Address, _ []common.Address) (*types.Transaction, error) { +func (d *v21KeeperDeployer) SetKeepers(ctx context.Context, opts *bind.TransactOpts, cls []cmd.HTTPClient, keepers []common.Address, _ []common.Address) (*types.Transaction, error) { S := make([]int, len(cls)) oracleIdentities := make([]ocr2config.OracleIdentityExtra, len(cls)) sharedSecretEncryptionPublicKeys := make([]ocr2types.ConfigEncryptionPublicKey, len(cls)) @@ -238,12 +239,12 @@ func (d *v21KeeperDeployer) SetKeepers(opts *bind.TransactOpts, cls []cmd.HTTPCl go func(i int, cl cmd.HTTPClient) { defer wg.Done() - ocr2Config, err := getNodeOCR2Config(cl) + ocr2Config, err := getNodeOCR2Config(ctx, cl) if err != nil { panic(err) } - p2pKeyID, err := getP2PKeyID(cl) + p2pKeyID, err := getP2PKeyID(ctx, cl) if err != nil { panic(err) } diff --git a/core/scripts/chaincli/handler/keeper_launch.go b/core/scripts/chaincli/handler/keeper_launch.go index e8be82a4bb7..25af77f1d5c 100644 --- a/core/scripts/chaincli/handler/keeper_launch.go +++ b/core/scripts/chaincli/handler/keeper_launch.go @@ -92,7 +92,7 @@ func (k *Keeper) LaunchAndTest(ctx context.Context, withdraw, printLogs, force, // Create authenticated client var cl cmd.HTTPClient var err error - cl, err = authenticate(startedNode.url, defaultChainlinkNodeLogin, defaultChainlinkNodePassword, lggr) + cl, err = authenticate(ctx, startedNode.url, defaultChainlinkNodeLogin, defaultChainlinkNodePassword, lggr) if err != nil { log.Fatal("Authentication failed, ", err) } @@ -101,13 +101,13 @@ func (k *Keeper) LaunchAndTest(ctx context.Context, withdraw, printLogs, force, if len(k.cfg.KeeperKeys) > 0 { // import key if exists - nodeAddrHex, err = k.addKeyToKeeper(cl, k.cfg.KeeperKeys[i]) + nodeAddrHex, err = k.addKeyToKeeper(ctx, cl, k.cfg.KeeperKeys[i]) if err != nil { log.Fatal("could not add key to keeper", err) } } else { // get node's default wallet address - nodeAddrHex, err = getNodeAddress(cl) + nodeAddrHex, err = getNodeAddress(ctx, cl) if err != nil { log.Println("Failed to get node addr: ", err) continue @@ -117,7 +117,7 @@ func (k *Keeper) LaunchAndTest(ctx context.Context, withdraw, printLogs, force, nodeAddr := common.HexToAddress(nodeAddrHex) // Create keepers - if err = k.createKeeperJob(cl, registryAddr.Hex(), nodeAddr.Hex()); err != nil { + if err = k.createKeeperJob(ctx, cl, registryAddr.Hex(), nodeAddr.Hex()); err != nil { log.Println("Failed to create keeper job: ", err) continue } @@ -291,12 +291,12 @@ func (k *Keeper) cancelAndWithdrawUpkeeps(ctx context.Context, upkeepCount *big. } // createKeeperJob creates a keeper job in the chainlink node by the given address -func (k *Keeper) createKeeperJob(client cmd.HTTPClient, registryAddr, nodeAddr string) error { +func (k *Keeper) createKeeperJob(ctx context.Context, client cmd.HTTPClient, registryAddr, nodeAddr string) error { var err error if k.cfg.OCR2Keepers { - err = k.createOCR2KeeperJob(client, registryAddr, nodeAddr) + err = k.createOCR2KeeperJob(ctx, client, registryAddr, nodeAddr) } else { - err = k.createLegacyKeeperJob(client, registryAddr, nodeAddr) + err = k.createLegacyKeeperJob(ctx, client, registryAddr, nodeAddr) } if err != nil { return err @@ -308,7 +308,7 @@ func (k *Keeper) createKeeperJob(client cmd.HTTPClient, registryAddr, nodeAddr s } // createLegacyKeeperJob creates a legacy keeper job in the chainlink node by the given address -func (k *Keeper) createLegacyKeeperJob(client cmd.HTTPClient, registryAddr, nodeAddr string) error { +func (k *Keeper) createLegacyKeeperJob(ctx context.Context, client cmd.HTTPClient, registryAddr, nodeAddr string) error { request, err := json.Marshal(web.CreateJobRequest{ TOML: testspecs.GenerateKeeperSpec(testspecs.KeeperSpecParams{ Name: fmt.Sprintf("keeper job - registry %s", registryAddr), @@ -321,7 +321,7 @@ func (k *Keeper) createLegacyKeeperJob(client cmd.HTTPClient, registryAddr, node return fmt.Errorf("failed to marshal request: %s", err) } - resp, err := client.Post("/v2/jobs", bytes.NewReader(request)) + resp, err := client.Post(ctx, "/v2/jobs", bytes.NewReader(request)) if err != nil { return fmt.Errorf("failed to create keeper job: %s", err) } @@ -363,8 +363,8 @@ contractVersion = "%s" mercuryCredentialName = "%s"` // createOCR2KeeperJob creates an ocr2keeper job in the chainlink node by the given address -func (k *Keeper) createOCR2KeeperJob(client cmd.HTTPClient, contractAddr, nodeAddr string) error { - ocr2KeyConfig, err := getNodeOCR2Config(client) +func (k *Keeper) createOCR2KeeperJob(ctx context.Context, client cmd.HTTPClient, contractAddr, nodeAddr string) error { + ocr2KeyConfig, err := getNodeOCR2Config(ctx, client) if err != nil { return fmt.Errorf("failed to get node OCR2 key bundle ID: %s", err) } @@ -390,7 +390,7 @@ func (k *Keeper) createOCR2KeeperJob(client cmd.HTTPClient, contractAddr, nodeAd return fmt.Errorf("failed to marshal request: %s", err) } - resp, err := client.Post("/v2/jobs", bytes.NewReader(request)) + resp, err := client.Post(ctx, "/v2/jobs", bytes.NewReader(request)) if err != nil { return fmt.Errorf("failed to create ocr2keeper job: %s", err) } @@ -409,7 +409,7 @@ func (k *Keeper) createOCR2KeeperJob(client cmd.HTTPClient, contractAddr, nodeAd } // addKeyToKeeper imports the provided ETH sending key to the keeper -func (k *Keeper) addKeyToKeeper(client cmd.HTTPClient, privKeyHex string) (string, error) { +func (k *Keeper) addKeyToKeeper(ctx context.Context, client cmd.HTTPClient, privKeyHex string) (string, error) { privkey, err := crypto.HexToECDSA(hex.TrimPrefix(privKeyHex)) if err != nil { log.Fatalf("Failed to decode priv key %s: %v", privKeyHex, err) @@ -429,7 +429,7 @@ func (k *Keeper) addKeyToKeeper(client cmd.HTTPClient, privKeyHex string) (strin query.Set("evmChainID", fmt.Sprint(k.cfg.ChainID)) importUrl.RawQuery = query.Encode() - resp, err := client.Post(importUrl.String(), bytes.NewReader(keyJSON)) + resp, err := client.Post(ctx, importUrl.String(), bytes.NewReader(keyJSON)) if err != nil { log.Fatalf("Failed to import priv key %s: %v", privKeyHex, err) } diff --git a/core/scripts/chaincli/handler/scrape_node_config.go b/core/scripts/chaincli/handler/scrape_node_config.go index aaaf5d26477..6525a4794d0 100644 --- a/core/scripts/chaincli/handler/scrape_node_config.go +++ b/core/scripts/chaincli/handler/scrape_node_config.go @@ -114,7 +114,7 @@ func (h *baseHandler) scrapeNodes(ctx context.Context, log logger.Logger) { pwd = defaultChainlinkNodePassword } - cl, err := authenticate(url, email, pwd, log) + cl, err := authenticate(ctx, url, email, pwd, log) if err != nil { log.Fatal(err) } @@ -125,7 +125,7 @@ func (h *baseHandler) scrapeNodes(ctx context.Context, log logger.Logger) { var wg sync.WaitGroup for i, cl := range cls { wg.Add(1) - go h.scrapeNodeInfo(&wg, i, cl, nodes, log) + go h.scrapeNodeInfo(ctx, &wg, i, cl, nodes, log) } wg.Wait() @@ -184,8 +184,8 @@ func (h *baseHandler) fetchNodeInfosFromWeiwatchers(ctx context.Context, log log return nodeInfos } -func (h *baseHandler) fetchNodeInfosFromNodes(i int, cl cmd.HTTPClient, log logger.Logger) ([]string, *cmd.OCR2KeyBundlePresenter, string, *cmd.CSAKeyPresenters) { - resp, err := nodeRequest(cl, ethKeysEndpoint) +func (h *baseHandler) fetchNodeInfosFromNodes(ctx context.Context, i int, cl cmd.HTTPClient, log logger.Logger) ([]string, *cmd.OCR2KeyBundlePresenter, string, *cmd.CSAKeyPresenters) { + resp, err := nodeRequest(ctx, cl, ethKeysEndpoint) if err != nil { log.Fatalf("failed to get ETH keys: %s", err) } @@ -204,17 +204,17 @@ func (h *baseHandler) fetchNodeInfosFromNodes(i int, cl cmd.HTTPClient, log logg log.Warnf("%d th node has more than 1 node addresses. is this a multi-chain node? or this node used to serve another chain?", i) } - ocr2Config, err := getNodeOCR2Config(cl) + ocr2Config, err := getNodeOCR2Config(ctx, cl) if err != nil { log.Fatalf("failed to get node OCR2 config: %s", err) } - peerId, err := getP2PKeyID(cl) + peerId, err := getP2PKeyID(ctx, cl) if err != nil { log.Fatalf("failed to get p2p keys: %s", err) } - resp, err = nodeRequest(cl, csaKeysEndpoint) + resp, err = nodeRequest(ctx, cl, csaKeysEndpoint) if err != nil { log.Fatalf("failed to get CSA keys: %s", err) } @@ -232,10 +232,10 @@ func (h *baseHandler) fetchNodeInfosFromNodes(i int, cl cmd.HTTPClient, log logg return nodeAddresses, ocr2Config, peerId, &csaKeys } -func (h *baseHandler) scrapeNodeInfo(wg *sync.WaitGroup, i int, cl cmd.HTTPClient, nodes map[string]*NodeInfo, log logger.Logger) { +func (h *baseHandler) scrapeNodeInfo(ctx context.Context, wg *sync.WaitGroup, i int, cl cmd.HTTPClient, nodes map[string]*NodeInfo, log logger.Logger) { defer wg.Done() - nodeAddresses, ocr2Config, peerId, csaKeys := h.fetchNodeInfosFromNodes(i, cl, log) + nodeAddresses, ocr2Config, peerId, csaKeys := h.fetchNodeInfosFromNodes(ctx, i, cl, log) // this assumes the nodes are not multichain nodes and have only 1 node address assigned. // for a multichain node, we can pass in a chain id and filter `ethKeys` array based on the chain id diff --git a/core/scripts/common/helpers.go b/core/scripts/common/helpers.go index 9d2d06c89d0..0ed9929956a 100644 --- a/core/scripts/common/helpers.go +++ b/core/scripts/common/helpers.go @@ -171,6 +171,8 @@ func explorerLinkPrefix(chainID int64) (prefix string) { prefix = "https://goerli.arbiscan.io" case ArbitrumOneChainID: // Arbitrum mainnet prefix = "https://arbiscan.io" + case ArbitrumSepoliaChainID: // Arbitrum Sepolia + prefix = "https://sepolia.arbiscan.io" case 56: // BSC mainnet prefix = "https://bscscan.com" @@ -233,6 +235,8 @@ func automationExplorerNetworkName(chainID int64) (prefix string) { prefix = "arbitrum-goerli" case ArbitrumOneChainID: // Arbitrum mainnet prefix = "arbitrum" + case ArbitrumSepoliaChainID: // Arbitrum Sepolia + prefix = "arbitrum-sepolia" case 56: // BSC mainnet prefix = "bsc" diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 10d31a3001e..babbbd92e0f 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -19,7 +19,7 @@ require ( github.com/pelletier/go-toml/v2 v2.1.1 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240110155415-407896b07206 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240113162114-77e747a4ef17 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7 @@ -244,7 +244,7 @@ require ( github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231222201016-da3f0a763f71 // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 // indirect - github.com/smartcontractkit/chainlink-feeds v0.0.0-20240112193433-af835dc4b1a3 // indirect + github.com/smartcontractkit/chainlink-feeds v0.0.0-20240113162230-9b808fd915ee // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231222220348-c7d81beaf8fd // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231221191127-1f32389044ea // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 00d949045b9..61a3b70225e 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1164,14 +1164,14 @@ github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumv github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= github.com/smartcontractkit/chainlink-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240110155415-407896b07206 h1:CfKu1c/DBx5qi1lFC9e/aVWwO0IyWKw2poBQR2VflnA= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240110155415-407896b07206/go.mod h1:f+0ei9N4PlTJHu7pbGzEjTnBUr45syPdGFu5+31lS5Q= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240113162114-77e747a4ef17 h1:/2FBQi0y48AwRq0Rr34JKsINAf7WHcaHr8XdbVXDt54= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240113162114-77e747a4ef17/go.mod h1:f+0ei9N4PlTJHu7pbGzEjTnBUr45syPdGFu5+31lS5Q= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231222201016-da3f0a763f71 h1:Ju0cxdrzGFwHGDPp16IzkOyX87LZ/kKDFG1A+VSEJHY= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231222201016-da3f0a763f71/go.mod h1:Ppv5X8MTUkkpKdb270dLefjio724vMkCWmSSaWo7CzI= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20240112193433-af835dc4b1a3 h1:w18bLofojboL74efMvH9iePjBa3KwlpvxR0FL/DN9Wc= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20240112193433-af835dc4b1a3/go.mod h1:L2b9/3wYVUqPAeKG/SLG/T0VsMOJtg+ygw8vTmRDMGE= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240113162230-9b808fd915ee h1:EC8tcNKx3f6qYln5WD+xVhzz60PKPH+sgrbjzAm3xcw= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240113162230-9b808fd915ee/go.mod h1:kXeFFq7kA+pmeG/A27wMi3geIRGn7G+r61v787ZyJtU= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231222220348-c7d81beaf8fd h1:9xSwDgRJDIfDw6171PQEyn5IQ1JKpaJnG5NX6KfCaHQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231222220348-c7d81beaf8fd/go.mod h1:kY435jBtHbyzhe+ImAxZ6G229uHbB0ablA+A0tJkDn8= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231221191127-1f32389044ea h1:WzMa0O6DEauMYMIjzS/T1JF8zvFDt4aG6EUTDlStaZo= diff --git a/core/scripts/ocr2vrf/main.go b/core/scripts/ocr2vrf/main.go index 532fbd3f22c..e7da4589951 100644 --- a/core/scripts/ocr2vrf/main.go +++ b/core/scripts/ocr2vrf/main.go @@ -364,7 +364,7 @@ func main() { *consumerAddress, uint16(*numWords), decimal.RequireFromString(*subID).BigInt(), - big.NewInt(int64(*confDelay)), + big.NewInt(*confDelay), uint32(*callbackGasLimit), nil, // test consumer doesn't use any args ) @@ -389,7 +389,7 @@ func main() { *consumerAddress, uint16(*numWords), decimal.RequireFromString(*subID).BigInt(), - big.NewInt(int64(*confDelay)), + big.NewInt(*confDelay), uint32(*callbackGasLimit), nil, // test consumer doesn't use any args, big.NewInt(*batchSize), @@ -411,7 +411,7 @@ func main() { *consumerAddress, uint16(*numWords), decimal.RequireFromString(*subID).BigInt(), - big.NewInt(int64(*confDelay)), + big.NewInt(*confDelay), uint32(*callbackGasLimit), nil, // test consumer doesn't use any args, big.NewInt(*batchSize), diff --git a/core/scripts/vrfv2/testnet/main.go b/core/scripts/vrfv2/testnet/main.go index 151549cc587..100440d6fb0 100644 --- a/core/scripts/vrfv2/testnet/main.go +++ b/core/scripts/vrfv2/testnet/main.go @@ -744,7 +744,7 @@ func main() { helpers.ParseArgs(addSubConsCmd, os.Args[2:], "coordinator-address", "sub-id", "consumer-address") coordinator, err := vrf_coordinator_v2.NewVRFCoordinatorV2(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - v2scripts.EoaAddConsumerToSub(e, *coordinator, uint64(*subID), *consumerAddress) + v2scripts.EoaAddConsumerToSub(e, *coordinator, *subID, *consumerAddress) case "eoa-create-fund-authorize-sub": // Lets just treat the owner key as the EOA controlling the sub cfaSubCmd := flag.NewFlagSet("eoa-create-fund-authorize-sub", flag.ExitOnError) diff --git a/core/services/blockhashstore/common.go b/core/services/blockhashstore/common.go index 677016253fb..a19a3b868f7 100644 --- a/core/services/blockhashstore/common.go +++ b/core/services/blockhashstore/common.go @@ -59,7 +59,7 @@ func GetUnfulfilledBlocksAndRequests( blockToRequests := make(map[uint64]map[string]struct{}) requestIDToBlock := make(map[string]uint64) - reqs, err := coordinator.Requests(ctx, uint64(fromBlock), uint64(toBlock)) + reqs, err := coordinator.Requests(ctx, fromBlock, toBlock) if err != nil { lggr.Errorw("Failed to fetch VRF requests", "err", err) @@ -73,7 +73,7 @@ func GetUnfulfilledBlocksAndRequests( requestIDToBlock[req.ID] = req.Block } - fuls, err := coordinator.Fulfillments(ctx, uint64(fromBlock)) + fuls, err := coordinator.Fulfillments(ctx, fromBlock) if err != nil { lggr.Errorw("Failed to fetch VRF fulfillments", "err", err) diff --git a/core/services/blockheaderfeeder/block_header_feeder.go b/core/services/blockheaderfeeder/block_header_feeder.go index 93799b8b419..a5bcb003613 100644 --- a/core/services/blockheaderfeeder/block_header_feeder.go +++ b/core/services/blockheaderfeeder/block_header_feeder.go @@ -120,7 +120,7 @@ func (f *BlockHeaderFeeder) Run(ctx context.Context) error { lggr.Debugw("found lowest block number without blockhash", "minBlockNumber", minBlockNumber) - earliestStoredBlockNumber, err := f.findEarliestBlockNumberWithBlockhash(ctx, lggr, minBlockNumber.Uint64()+1, uint64(toBlock)) + earliestStoredBlockNumber, err := f.findEarliestBlockNumberWithBlockhash(ctx, lggr, minBlockNumber.Uint64()+1, toBlock) if err != nil { return errors.Wrap(err, "finding earliest blocknumber with blockhash") } diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index e94f51abdf5..a9f9c22df52 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -53,6 +53,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/promreporter" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc" + "github.com/smartcontractkit/chainlink/v2/core/services/streams" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" "github.com/smartcontractkit/chainlink/v2/core/services/vrf" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" @@ -116,7 +117,6 @@ type Application interface { // in the services package, but the Store has its own package. type ChainlinkApplication struct { relayers *CoreRelayerChainInteroperators - EventBroadcaster pg.EventBroadcaster jobORM job.ORM jobSpawner job.Spawner pipelineORM pipeline.ORM @@ -150,7 +150,6 @@ type ChainlinkApplication struct { type ApplicationOpts struct { Config GeneralConfig Logger logger.Logger - EventBroadcaster pg.EventBroadcaster MailMon *mailbox.Monitor SqlxDB *sqlx.DB KeyStore keystore.Master @@ -178,7 +177,6 @@ func NewApplication(opts ApplicationOpts) (Application, error) { db := opts.SqlxDB cfg := opts.Config relayerChainInterops := opts.RelayerChainInteroperators - eventBroadcaster := opts.EventBroadcaster mailMon := opts.MailMon externalInitiatorManager := opts.ExternalInitiatorManager globalLogger := logger.Sugared(opts.Logger) @@ -254,7 +252,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { return nil, fmt.Errorf("no evm chains found") } - srvcs = append(srvcs, eventBroadcaster, mailMon) + srvcs = append(srvcs, mailMon) srvcs = append(srvcs, relayerChainInterops.Services()...) promReporter := promreporter.NewPromReporter(db.DB, legacyEVMChains, globalLogger) srvcs = append(srvcs, promReporter) @@ -293,6 +291,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { pipelineRunner = pipeline.NewRunner(pipelineORM, bridgeORM, cfg.JobPipeline(), cfg.WebServer(), legacyEVMChains, keyStore.Eth(), keyStore.VRF(), globalLogger, restrictedHTTPClient, unrestrictedHTTPClient) jobORM = job.NewORM(db, pipelineORM, bridgeORM, keyStore, globalLogger, cfg.Database()) txmORM = txmgr.NewTxStore(db, globalLogger, cfg.Database()) + streamRegistry = streams.NewRegistry(globalLogger, pipelineRunner) ) for _, chain := range legacyEVMChains.Slice() { @@ -347,6 +346,11 @@ func NewApplication(opts ApplicationOpts) (Application, error) { db, cfg.Database(), globalLogger), + job.Stream: streams.NewDelegate( + globalLogger, + streamRegistry, + pipelineRunner, + cfg.JobPipeline()), } webhookJobRunner = delegates[job.Webhook].(*webhook.Delegate).WebhookJobRunner() ) @@ -416,7 +420,6 @@ func NewApplication(opts ApplicationOpts) (Application, error) { keyStore.Eth(), opts.RelayerChainInteroperators, mailMon, - eventBroadcaster, ) delegates[job.Bootstrap] = ocrbootstrap.NewDelegateBootstrap( db, @@ -481,7 +484,6 @@ func NewApplication(opts ApplicationOpts) (Application, error) { return &ChainlinkApplication{ relayers: opts.RelayerChainInteroperators, - EventBroadcaster: eventBroadcaster, jobORM: jobORM, jobSpawner: jobSpawner, pipelineRunner: pipelineRunner, @@ -810,10 +812,6 @@ func (app *ChainlinkApplication) GetRelayers() RelayerChainInteroperators { return app.relayers } -func (app *ChainlinkApplication) GetEventBroadcaster() pg.EventBroadcaster { - return app.EventBroadcaster -} - func (app *ChainlinkApplication) GetSqlxDB() *sqlx.DB { return app.sqlxDB } diff --git a/core/services/chainlink/config.go b/core/services/chainlink/config.go index 192fbb311d3..6cd2732ece8 100644 --- a/core/services/chainlink/config.go +++ b/core/services/chainlink/config.go @@ -30,7 +30,7 @@ import ( // - TOML is limited to int64/float64, so fields requiring greater range/precision must use non-standard types // implementing encoding.TextMarshaler/TextUnmarshaler, like big.Big and decimal.Decimal // - std lib types that don't implement encoding.TextMarshaler/TextUnmarshaler (time.Duration, url.URL, big.Int) won't -// work as expected, and require wrapper types. See models.Duration, models.URL, big.Big. +// work as expected, and require wrapper types. See commonconfig.Duration, commonconfig.URL, big.Big. type Config struct { toml.Core diff --git a/core/services/chainlink/config_audit_logger.go b/core/services/chainlink/config_audit_logger.go index 1593f3887fb..5d8c00f771d 100644 --- a/core/services/chainlink/config_audit_logger.go +++ b/core/services/chainlink/config_audit_logger.go @@ -1,6 +1,7 @@ package chainlink import ( + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/build" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -14,7 +15,7 @@ func (a auditLoggerConfig) Enabled() bool { return *a.c.Enabled } -func (a auditLoggerConfig) ForwardToUrl() (models.URL, error) { +func (a auditLoggerConfig) ForwardToUrl() (commonconfig.URL, error) { return *a.c.ForwardToUrl, nil } diff --git a/core/services/chainlink/config_auto_pprof.go b/core/services/chainlink/config_auto_pprof.go index 8cc5f2dd3e8..48ec7749b79 100644 --- a/core/services/chainlink/config_auto_pprof.go +++ b/core/services/chainlink/config_auto_pprof.go @@ -3,9 +3,9 @@ package chainlink import ( "path/filepath" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -28,12 +28,12 @@ func (a *autoPprofConfig) CPUProfileRate() int { return int(*a.c.CPUProfileRate) } -func (a *autoPprofConfig) GatherDuration() models.Duration { - return models.MustMakeDuration(a.c.GatherDuration.Duration()) +func (a *autoPprofConfig) GatherDuration() commonconfig.Duration { + return *commonconfig.MustNewDuration(a.c.GatherDuration.Duration()) } -func (a *autoPprofConfig) GatherTraceDuration() models.Duration { - return models.MustMakeDuration(a.c.GatherTraceDuration.Duration()) +func (a *autoPprofConfig) GatherTraceDuration() commonconfig.Duration { + return *commonconfig.MustNewDuration(a.c.GatherTraceDuration.Duration()) } func (a *autoPprofConfig) GoroutineThreshold() int { @@ -56,7 +56,7 @@ func (a *autoPprofConfig) MutexProfileFraction() int { return int(*a.c.MutexProfileFraction) } -func (a *autoPprofConfig) PollInterval() models.Duration { +func (a *autoPprofConfig) PollInterval() commonconfig.Duration { return *a.c.PollInterval } diff --git a/core/services/chainlink/config_general.go b/core/services/chainlink/config_general.go index cb68ed0e72d..97243926973 100644 --- a/core/services/chainlink/config_general.go +++ b/core/services/chainlink/config_general.go @@ -357,12 +357,12 @@ func (g *generalConfig) AutoPprofCPUProfileRate() int { return int(*g.c.AutoPprof.CPUProfileRate) } -func (g *generalConfig) AutoPprofGatherDuration() models.Duration { - return models.MustMakeDuration(g.c.AutoPprof.GatherDuration.Duration()) +func (g *generalConfig) AutoPprofGatherDuration() commonconfig.Duration { + return *commonconfig.MustNewDuration(g.c.AutoPprof.GatherDuration.Duration()) } -func (g *generalConfig) AutoPprofGatherTraceDuration() models.Duration { - return models.MustMakeDuration(g.c.AutoPprof.GatherTraceDuration.Duration()) +func (g *generalConfig) AutoPprofGatherTraceDuration() commonconfig.Duration { + return *commonconfig.MustNewDuration(g.c.AutoPprof.GatherTraceDuration.Duration()) } func (g *generalConfig) AutoPprofGoroutineThreshold() int { @@ -385,7 +385,7 @@ func (g *generalConfig) AutoPprofMutexProfileFraction() int { return int(*g.c.AutoPprof.MutexProfileFraction) } -func (g *generalConfig) AutoPprofPollInterval() models.Duration { +func (g *generalConfig) AutoPprofPollInterval() commonconfig.Duration { return *g.c.AutoPprof.PollInterval } diff --git a/core/services/chainlink/config_job_pipeline.go b/core/services/chainlink/config_job_pipeline.go index 1586cbb3574..95106b84199 100644 --- a/core/services/chainlink/config_job_pipeline.go +++ b/core/services/chainlink/config_job_pipeline.go @@ -3,9 +3,9 @@ package chainlink import ( "time" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) var _ config.JobPipeline = (*jobPipelineConfig)(nil) @@ -18,7 +18,7 @@ func (j *jobPipelineConfig) DefaultHTTPLimit() int64 { return int64(*j.c.HTTPRequest.MaxSize) } -func (j *jobPipelineConfig) DefaultHTTPTimeout() models.Duration { +func (j *jobPipelineConfig) DefaultHTTPTimeout() commonconfig.Duration { return *j.c.HTTPRequest.DefaultTimeout } diff --git a/core/services/chainlink/config_job_pipeline_test.go b/core/services/chainlink/config_job_pipeline_test.go index 58c94067f25..9a865569eb3 100644 --- a/core/services/chainlink/config_job_pipeline_test.go +++ b/core/services/chainlink/config_job_pipeline_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -21,7 +21,7 @@ func TestJobPipelineConfigTest(t *testing.T) { jp := cfg.JobPipeline() assert.Equal(t, int64(100*utils.MB), jp.DefaultHTTPLimit()) - d, err := models.MakeDuration(1 * time.Minute) + d, err := commonconfig.NewDuration(1 * time.Minute) require.NoError(t, err) assert.Equal(t, d, jp.DefaultHTTPTimeout()) assert.Equal(t, 1*time.Hour, jp.MaxRunDuration()) diff --git a/core/services/chainlink/config_mercury.go b/core/services/chainlink/config_mercury.go index 61e48d340e4..49f1cf0a5f4 100644 --- a/core/services/chainlink/config_mercury.go +++ b/core/services/chainlink/config_mercury.go @@ -24,6 +24,14 @@ func (m *mercuryCacheConfig) LatestReportDeadline() time.Duration { return m.c.LatestReportDeadline.Duration() } +type mercuryTLSConfig struct { + c toml.MercuryTLS +} + +func (m *mercuryTLSConfig) CertFile() string { + return *m.c.CertFile +} + type mercuryConfig struct { c toml.Mercury s toml.MercurySecrets @@ -47,3 +55,7 @@ func (m *mercuryConfig) Credentials(credName string) *models.MercuryCredentials func (m *mercuryConfig) Cache() config.MercuryCache { return &mercuryCacheConfig{c: m.c.Cache} } + +func (m *mercuryConfig) TLS() config.MercuryTLS { + return &mercuryTLSConfig{c: m.c.TLS} +} diff --git a/core/services/chainlink/config_mercury_test.go b/core/services/chainlink/config_mercury_test.go index 58019a91557..71dfb2a01ce 100644 --- a/core/services/chainlink/config_mercury_test.go +++ b/core/services/chainlink/config_mercury_test.go @@ -7,6 +7,8 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" + + "github.com/smartcontractkit/chainlink/v2/core/config/toml" ) const ( @@ -34,3 +36,15 @@ func TestMercuryConfig(t *testing.T) { assert.Equal(t, &models.MercuryCredentials{URL: "https://chain1.link", Username: "username1", Password: "password1"}, m.Credentials("cred1")) assert.Equal(t, &models.MercuryCredentials{URL: "https://chain2.link", Username: "username2", Password: "password2"}, m.Credentials("cred2")) } + +func TestMercuryTLS(t *testing.T) { + certPath := "/path/to/cert.pem" + transmission := toml.Mercury{ + TLS: toml.MercuryTLS{ + CertFile: &certPath, + }, + } + cfg := mercuryConfig{c: transmission} + + assert.Equal(t, certPath, cfg.TLS().CertFile()) +} diff --git a/core/services/chainlink/config_p2p.go b/core/services/chainlink/config_p2p.go index 596a4fe0cae..4197358b148 100644 --- a/core/services/chainlink/config_p2p.go +++ b/core/services/chainlink/config_p2p.go @@ -1,12 +1,12 @@ package chainlink import ( - "github.com/smartcontractkit/libocr/commontypes" - + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + + "github.com/smartcontractkit/libocr/commontypes" ) type p2p struct { @@ -59,19 +59,19 @@ func (v *p2pv2) DefaultBootstrappers() (locators []commontypes.BootstrapperLocat return nil } -func (v *p2pv2) DeltaDial() models.Duration { +func (v *p2pv2) DeltaDial() commonconfig.Duration { if d := v.c.DeltaDial; d != nil { return *d } - return models.Duration{} + return commonconfig.Duration{} } -func (v *p2pv2) DeltaReconcile() models.Duration { +func (v *p2pv2) DeltaReconcile() commonconfig.Duration { if d := v.c.DeltaReconcile; d != nil { return *d } - return models.Duration{} + return commonconfig.Duration{} } func (v *p2pv2) ListenAddresses() []string { diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index f0c88db65fe..a7ac1e86d84 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -20,6 +20,7 @@ import ( commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/config" commoncfg "github.com/smartcontractkit/chainlink-common/pkg/config" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" @@ -66,7 +67,7 @@ var ( }, Database: toml.Database{ Listener: toml.DatabaseListener{ - FallbackPollInterval: models.MustNewDuration(2 * time.Minute), + FallbackPollInterval: commonconfig.MustNewDuration(2 * time.Minute), }, }, Log: toml.Log{ @@ -75,16 +76,16 @@ var ( }, JobPipeline: toml.JobPipeline{ HTTPRequest: toml.JobPipelineHTTPRequest{ - DefaultTimeout: models.MustNewDuration(30 * time.Second), + DefaultTimeout: commonconfig.MustNewDuration(30 * time.Second), }, }, OCR2: toml.OCR2{ Enabled: ptr(true), - DatabaseTimeout: models.MustNewDuration(20 * time.Second), + DatabaseTimeout: commonconfig.MustNewDuration(20 * time.Second), }, OCR: toml.OCR{ Enabled: ptr(true), - BlockchainTimeout: models.MustNewDuration(5 * time.Second), + BlockchainTimeout: commonconfig.MustNewDuration(5 * time.Second), }, P2P: toml.P2P{ IncomingMessageBufferSize: ptr[int64](999), @@ -194,10 +195,10 @@ var ( ) func TestConfig_Marshal(t *testing.T) { - zeroSeconds := models.MustMakeDuration(time.Second * 0) - second := models.MustMakeDuration(time.Second) - minute := models.MustMakeDuration(time.Minute) - hour := models.MustMakeDuration(time.Hour) + zeroSeconds := *commonconfig.MustNewDuration(time.Second * 0) + second := *commonconfig.MustNewDuration(time.Second) + minute := *commonconfig.MustNewDuration(time.Minute) + hour := *commonconfig.MustNewDuration(time.Hour) mustPeerID := func(s string) *p2pkey.PeerID { id, err := p2pkey.MakePeerID(s) require.NoError(t, err) @@ -219,7 +220,7 @@ func TestConfig_Marshal(t *testing.T) { Core: toml.Core{ InsecureFastScrypt: ptr(true), RootDir: ptr("test/root/dir"), - ShutdownGracePeriod: models.MustNewDuration(10 * time.Second), + ShutdownGracePeriod: commonconfig.MustNewDuration(10 * time.Second), Insecure: toml.Insecure{ DevWebServer: ptr(false), OCRDevelopmentMode: ptr(false), @@ -260,17 +261,17 @@ func TestConfig_Marshal(t *testing.T) { UICSAKeys: ptr(true), } full.Database = toml.Database{ - DefaultIdleInTxSessionTimeout: models.MustNewDuration(time.Minute), - DefaultLockTimeout: models.MustNewDuration(time.Hour), - DefaultQueryTimeout: models.MustNewDuration(time.Second), + DefaultIdleInTxSessionTimeout: commonconfig.MustNewDuration(time.Minute), + DefaultLockTimeout: commonconfig.MustNewDuration(time.Hour), + DefaultQueryTimeout: commonconfig.MustNewDuration(time.Second), LogQueries: ptr(true), MigrateOnStartup: ptr(true), MaxIdleConns: ptr[int64](7), MaxOpenConns: ptr[int64](13), Listener: toml.DatabaseListener{ - MaxReconnectDuration: models.MustNewDuration(time.Minute), - MinReconnectInterval: models.MustNewDuration(5 * time.Minute), - FallbackPollInterval: models.MustNewDuration(2 * time.Minute), + MaxReconnectDuration: commonconfig.MustNewDuration(time.Minute), + MinReconnectInterval: commonconfig.MustNewDuration(5 * time.Minute), + FallbackPollInterval: commonconfig.MustNewDuration(2 * time.Minute), }, Lock: toml.DatabaseLock{ Enabled: ptr(false), @@ -289,10 +290,10 @@ func TestConfig_Marshal(t *testing.T) { Logging: ptr(true), BufferSize: ptr[uint16](1234), MaxBatchSize: ptr[uint16](4321), - SendInterval: models.MustNewDuration(time.Minute), - SendTimeout: models.MustNewDuration(5 * time.Second), + SendInterval: commonconfig.MustNewDuration(time.Minute), + SendTimeout: commonconfig.MustNewDuration(5 * time.Second), UseBatchSend: ptr(true), - URL: ptr(models.URL{}), + URL: ptr(commonconfig.URL{}), ServerPubKey: ptr(""), Endpoints: []toml.TelemetryIngressEndpoint{{ Network: ptr("EVM"), @@ -317,14 +318,14 @@ func TestConfig_Marshal(t *testing.T) { AuthenticationMethod: ptr("local"), AllowOrigins: ptr("*"), BridgeResponseURL: mustURL("https://bridge.response"), - BridgeCacheTTL: models.MustNewDuration(10 * time.Second), - HTTPWriteTimeout: models.MustNewDuration(time.Minute), + BridgeCacheTTL: commonconfig.MustNewDuration(10 * time.Second), + HTTPWriteTimeout: commonconfig.MustNewDuration(time.Minute), HTTPPort: ptr[uint16](56), SecureCookies: ptr(true), - SessionTimeout: models.MustNewDuration(time.Hour), - SessionReaperExpiration: models.MustNewDuration(7 * 24 * time.Hour), + SessionTimeout: commonconfig.MustNewDuration(time.Hour), + SessionReaperExpiration: commonconfig.MustNewDuration(7 * 24 * time.Hour), HTTPMaxSize: ptr(utils.FileSize(uint64(32770))), - StartTimeout: models.MustNewDuration(15 * time.Second), + StartTimeout: commonconfig.MustNewDuration(15 * time.Second), ListenIP: mustIP("192.158.1.37"), MFA: toml.WebServerMFA{ RPID: ptr("test-rpid"), @@ -332,8 +333,8 @@ func TestConfig_Marshal(t *testing.T) { }, LDAP: toml.WebServerLDAP{ ServerTLS: ptr(true), - SessionTimeout: models.MustNewDuration(15 * time.Minute), - QueryTimeout: models.MustNewDuration(2 * time.Minute), + SessionTimeout: commonconfig.MustNewDuration(15 * time.Minute), + QueryTimeout: commonconfig.MustNewDuration(2 * time.Minute), BaseUserAttr: ptr("uid"), BaseDN: ptr("dc=custom,dc=example,dc=com"), UsersDN: ptr("ou=users"), @@ -345,15 +346,15 @@ func TestConfig_Marshal(t *testing.T) { RunUserGroupCN: ptr("NodeRunners"), ReadUserGroupCN: ptr("NodeReadOnly"), UserApiTokenEnabled: ptr(false), - UserAPITokenDuration: models.MustNewDuration(240 * time.Hour), - UpstreamSyncInterval: models.MustNewDuration(0 * time.Second), - UpstreamSyncRateLimit: models.MustNewDuration(2 * time.Minute), + UserAPITokenDuration: commonconfig.MustNewDuration(240 * time.Hour), + UpstreamSyncInterval: commonconfig.MustNewDuration(0 * time.Second), + UpstreamSyncRateLimit: commonconfig.MustNewDuration(2 * time.Minute), }, RateLimit: toml.WebServerRateLimit{ Authenticated: ptr[int64](42), - AuthenticatedPeriod: models.MustNewDuration(time.Second), + AuthenticatedPeriod: commonconfig.MustNewDuration(time.Second), Unauthenticated: ptr[int64](7), - UnauthenticatedPeriod: models.MustNewDuration(time.Minute), + UnauthenticatedPeriod: commonconfig.MustNewDuration(time.Minute), }, TLS: toml.WebServerTLS{ CertPath: ptr("tls/cert/path"), @@ -366,14 +367,14 @@ func TestConfig_Marshal(t *testing.T) { } full.JobPipeline = toml.JobPipeline{ ExternalInitiatorsEnabled: ptr(true), - MaxRunDuration: models.MustNewDuration(time.Hour), + MaxRunDuration: commonconfig.MustNewDuration(time.Hour), MaxSuccessfulRuns: ptr[uint64](123456), - ReaperInterval: models.MustNewDuration(4 * time.Hour), - ReaperThreshold: models.MustNewDuration(7 * 24 * time.Hour), + ReaperInterval: commonconfig.MustNewDuration(4 * time.Hour), + ReaperThreshold: commonconfig.MustNewDuration(7 * 24 * time.Hour), ResultWriteQueueDepth: ptr[uint32](10), HTTPRequest: toml.JobPipelineHTTPRequest{ MaxSize: ptr[utils.FileSize](100 * utils.MB), - DefaultTimeout: models.MustNewDuration(time.Minute), + DefaultTimeout: commonconfig.MustNewDuration(time.Minute), }, } full.FluxMonitor = toml.FluxMonitor{ @@ -383,11 +384,11 @@ func TestConfig_Marshal(t *testing.T) { full.OCR2 = toml.OCR2{ Enabled: ptr(true), ContractConfirmations: ptr[uint32](11), - BlockchainTimeout: models.MustNewDuration(3 * time.Second), - ContractPollInterval: models.MustNewDuration(time.Hour), - ContractSubscribeInterval: models.MustNewDuration(time.Minute), - ContractTransmitterTransmitTimeout: models.MustNewDuration(time.Minute), - DatabaseTimeout: models.MustNewDuration(8 * time.Second), + BlockchainTimeout: commonconfig.MustNewDuration(3 * time.Second), + ContractPollInterval: commonconfig.MustNewDuration(time.Hour), + ContractSubscribeInterval: commonconfig.MustNewDuration(time.Minute), + ContractTransmitterTransmitTimeout: commonconfig.MustNewDuration(time.Minute), + DatabaseTimeout: commonconfig.MustNewDuration(8 * time.Second), KeyBundleID: ptr(models.MustSha256HashFromHex("7a5f66bbe6594259325bf2b4f5b1a9c9")), CaptureEATelemetry: ptr(false), CaptureAutomationCustomTelemetry: ptr(true), @@ -397,10 +398,10 @@ func TestConfig_Marshal(t *testing.T) { } full.OCR = toml.OCR{ Enabled: ptr(true), - ObservationTimeout: models.MustNewDuration(11 * time.Second), - BlockchainTimeout: models.MustNewDuration(3 * time.Second), - ContractPollInterval: models.MustNewDuration(time.Hour), - ContractSubscribeInterval: models.MustNewDuration(time.Minute), + ObservationTimeout: commonconfig.MustNewDuration(11 * time.Second), + BlockchainTimeout: commonconfig.MustNewDuration(3 * time.Second), + ContractPollInterval: commonconfig.MustNewDuration(time.Hour), + ContractSubscribeInterval: commonconfig.MustNewDuration(time.Minute), DefaultTransactionQueueDepth: ptr[uint32](12), KeyBundleID: ptr(models.MustSha256HashFromHex("acdd42797a8b921b2910497badc50006")), SimulateTransactions: ptr(true), @@ -420,8 +421,8 @@ func TestConfig_Marshal(t *testing.T) { {PeerID: "12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw", Addrs: []string{"foo:42", "bar:10"}}, {PeerID: "12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw", Addrs: []string{"test:99"}}, }, - DeltaDial: models.MustNewDuration(time.Minute), - DeltaReconcile: models.MustNewDuration(time.Second), + DeltaDial: commonconfig.MustNewDuration(time.Minute), + DeltaReconcile: commonconfig.MustNewDuration(time.Second), ListenAddresses: &[]string{"foo", "bar"}, }, } @@ -435,7 +436,7 @@ func TestConfig_Marshal(t *testing.T) { Registry: toml.KeeperRegistry{ CheckGasOverhead: ptr[uint32](90), PerformGasOverhead: ptr[uint32](math.MaxUint32), - SyncInterval: models.MustNewDuration(time.Hour), + SyncInterval: commonconfig.MustNewDuration(time.Hour), SyncUpkeepQueueSize: ptr[uint32](31), MaxPerformDataSize: ptr[uint32](5000), }, @@ -443,9 +444,9 @@ func TestConfig_Marshal(t *testing.T) { full.AutoPprof = toml.AutoPprof{ Enabled: ptr(true), ProfileRoot: ptr("prof/root"), - PollInterval: models.MustNewDuration(time.Minute), - GatherDuration: models.MustNewDuration(12 * time.Second), - GatherTraceDuration: models.MustNewDuration(13 * time.Second), + PollInterval: commonconfig.MustNewDuration(time.Minute), + GatherDuration: commonconfig.MustNewDuration(12 * time.Second), + GatherTraceDuration: commonconfig.MustNewDuration(13 * time.Second), MaxProfileSize: ptr[utils.FileSize](utils.GB), CPUProfileRate: ptr[int64](7), MemProfileRate: ptr[int64](9), @@ -564,8 +565,8 @@ func TestConfig_Marshal(t *testing.T) { ContractConfirmations: ptr[uint16](11), ContractTransmitterTransmitTimeout: &minute, DatabaseTimeout: &second, - DeltaCOverride: models.MustNewDuration(time.Hour), - DeltaCJitterOverride: models.MustNewDuration(time.Second), + DeltaCOverride: commonconfig.MustNewDuration(time.Hour), + DeltaCJitterOverride: commonconfig.MustNewDuration(time.Second), ObservationGracePeriod: &second, }, OCR2: evmcfg.OCR2{ @@ -662,9 +663,12 @@ func TestConfig_Marshal(t *testing.T) { } full.Mercury = toml.Mercury{ Cache: toml.MercuryCache{ - LatestReportTTL: models.MustNewDuration(100 * time.Second), - MaxStaleAge: models.MustNewDuration(101 * time.Second), - LatestReportDeadline: models.MustNewDuration(102 * time.Second), + LatestReportTTL: commonconfig.MustNewDuration(100 * time.Second), + MaxStaleAge: commonconfig.MustNewDuration(101 * time.Second), + LatestReportDeadline: commonconfig.MustNewDuration(102 * time.Second), + }, + TLS: toml.MercuryTLS{ + CertFile: ptr("/path/to/cert.pem"), }, } @@ -1097,6 +1101,9 @@ URL = 'http://stark.node' LatestReportTTL = '1m40s' MaxStaleAge = '1m41s' LatestReportDeadline = '1m42s' + +[Mercury.TLS] +CertFile = '/path/to/cert.pem' `}, {"full", full, fullTOML}, {"multi-chain", multiChain, multiChainTOML}, @@ -1123,7 +1130,7 @@ func TestConfig_full(t *testing.T) { for c := range got.EVM { for n := range got.EVM[c].Nodes { if got.EVM[c].Nodes[n].WSURL == nil { - got.EVM[c].Nodes[n].WSURL = new(models.URL) + got.EVM[c].Nodes[n].WSURL = new(commonconfig.URL) } if got.EVM[c].Nodes[n].SendOnly == nil { got.EVM[c].Nodes[n].SendOnly = ptr(true) @@ -1142,7 +1149,7 @@ func TestConfig_full(t *testing.T) { // Except for TelemetryIngress.URL as this will be removed in the future // and its only use is to signal to NOPs that these fields are no longer allowed if got.TelemetryIngress.URL == nil { - got.TelemetryIngress.URL = new(models.URL) + got.TelemetryIngress.URL = new(commonconfig.URL) } cfgtest.AssertFieldsNotNil(t, got) @@ -1255,8 +1262,8 @@ func TestConfig_Validate(t *testing.T) { } } -func mustURL(s string) *models.URL { - var u models.URL +func mustURL(s string) *commonconfig.URL { + var u commonconfig.URL if err := u.UnmarshalText([]byte(s)); err != nil { panic(err) } diff --git a/core/services/chainlink/config_web_server.go b/core/services/chainlink/config_web_server.go index 06db398e2ea..473f70a4c9c 100644 --- a/core/services/chainlink/config_web_server.go +++ b/core/services/chainlink/config_web_server.go @@ -9,9 +9,9 @@ import ( "github.com/gin-contrib/sessions" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) var _ config.WebServer = (*webServerConfig)(nil) @@ -153,7 +153,7 @@ func (w *webServerConfig) HTTPPort() uint16 { return *w.c.HTTPPort } -func (w *webServerConfig) SessionReaperExpiration() models.Duration { +func (w *webServerConfig) SessionReaperExpiration() commonconfig.Duration { return *w.c.SessionReaperExpiration } @@ -170,8 +170,8 @@ func (w *webServerConfig) SessionOptions() sessions.Options { } } -func (w *webServerConfig) SessionTimeout() models.Duration { - return models.MustMakeDuration(w.c.SessionTimeout.Duration()) +func (w *webServerConfig) SessionTimeout() commonconfig.Duration { + return *commonconfig.MustNewDuration(w.c.SessionTimeout.Duration()) } func (w *webServerConfig) ListenIP() net.IP { @@ -211,7 +211,7 @@ func (l *ldapConfig) ServerTLS() bool { return *l.c.ServerTLS } -func (l *ldapConfig) SessionTimeout() models.Duration { +func (l *ldapConfig) SessionTimeout() commonconfig.Duration { return *l.c.SessionTimeout } @@ -219,7 +219,7 @@ func (l *ldapConfig) QueryTimeout() time.Duration { return l.c.QueryTimeout.Duration() } -func (l *ldapConfig) UserAPITokenDuration() models.Duration { +func (l *ldapConfig) UserAPITokenDuration() commonconfig.Duration { return *l.c.UserAPITokenDuration } @@ -300,16 +300,16 @@ func (l *ldapConfig) UserApiTokenEnabled() bool { return *l.c.UserApiTokenEnabled } -func (l *ldapConfig) UpstreamSyncInterval() models.Duration { +func (l *ldapConfig) UpstreamSyncInterval() commonconfig.Duration { if l.c.UpstreamSyncInterval == nil { - return models.Duration{} + return commonconfig.Duration{} } return *l.c.UpstreamSyncInterval } -func (l *ldapConfig) UpstreamSyncRateLimit() models.Duration { +func (l *ldapConfig) UpstreamSyncRateLimit() commonconfig.Duration { if l.c.UpstreamSyncRateLimit == nil { - return models.Duration{} + return commonconfig.Duration{} } return *l.c.UpstreamSyncRateLimit } diff --git a/core/services/chainlink/config_web_server_test.go b/core/services/chainlink/config_web_server_test.go index 92e8dde460a..946e0b0c12b 100644 --- a/core/services/chainlink/config_web_server_test.go +++ b/core/services/chainlink/config_web_server_test.go @@ -4,10 +4,10 @@ import ( "testing" "time" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func TestWebServerConfig(t *testing.T) { @@ -24,8 +24,8 @@ func TestWebServerConfig(t *testing.T) { assert.Equal(t, 1*time.Minute, ws.HTTPWriteTimeout()) assert.Equal(t, uint16(56), ws.HTTPPort()) assert.True(t, ws.SecureCookies()) - assert.Equal(t, *models.MustNewDuration(1 * time.Hour), ws.SessionTimeout()) - assert.Equal(t, *models.MustNewDuration(168 * time.Hour), ws.SessionReaperExpiration()) + assert.Equal(t, *commonconfig.MustNewDuration(1 * time.Hour), ws.SessionTimeout()) + assert.Equal(t, *commonconfig.MustNewDuration(168 * time.Hour), ws.SessionReaperExpiration()) assert.Equal(t, int64(32770), ws.HTTPMaxSize()) assert.Equal(t, 15*time.Second, ws.StartTimeout()) tls := ws.TLS() diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index d89fbce12db..ea1a9ec3746 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - commoncfg "github.com/smartcontractkit/chainlink-common/pkg/config" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" @@ -25,9 +25,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/relay" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/plugins" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" @@ -46,22 +44,22 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { cfg := evmcfg.Defaults(evmChainID1) node1_1 := evmcfg.Node{ Name: ptr("Test node chain1:1"), - WSURL: models.MustParseURL("ws://localhost:8546"), - HTTPURL: models.MustParseURL("http://localhost:8546"), + WSURL: commonconfig.MustParseURL("ws://localhost:8546"), + HTTPURL: commonconfig.MustParseURL("http://localhost:8546"), SendOnly: ptr(false), Order: ptr(int32(15)), } node1_2 := evmcfg.Node{ Name: ptr("Test node chain1:2"), - WSURL: models.MustParseURL("ws://localhost:8547"), - HTTPURL: models.MustParseURL("http://localhost:8547"), + WSURL: commonconfig.MustParseURL("ws://localhost:8547"), + HTTPURL: commonconfig.MustParseURL("http://localhost:8547"), SendOnly: ptr(false), Order: ptr(int32(36)), } node2_1 := evmcfg.Node{ Name: ptr("Test node chain2:1"), - WSURL: models.MustParseURL("ws://localhost:8547"), - HTTPURL: models.MustParseURL("http://localhost:8547"), + WSURL: commonconfig.MustParseURL("ws://localhost:8547"), + HTTPURL: commonconfig.MustParseURL("http://localhost:8547"), SendOnly: ptr(false), Order: ptr(int32(11)), } @@ -86,7 +84,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Chain: solcfg.Chain{}, Nodes: []*solcfg.Node{{ Name: ptr("solana chain 1 node 1"), - URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:8547").URL())), + URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:8547").URL())), }}, }, &solana.TOMLConfig{ @@ -95,7 +93,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Chain: solcfg.Chain{}, Nodes: []*solcfg.Node{{ Name: ptr("solana chain 2 node 1"), - URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:8527").URL())), + URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:8527").URL())), }}, }, } @@ -108,15 +106,15 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Nodes: []*stkcfg.Node{ { Name: ptr("starknet chain 1 node 1"), - URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:8547").URL())), + URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:8547").URL())), }, { Name: ptr("starknet chain 1 node 2"), - URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:8548").URL())), + URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:8548").URL())), }, { Name: ptr("starknet chain 1 node 3"), - URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:8549").URL())), + URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:8549").URL())), }, }, }, @@ -127,7 +125,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Nodes: []*stkcfg.Node{ { Name: ptr("starknet chain 2 node 1"), - URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:3547").URL())), + URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:3547").URL())), }, }, }, @@ -145,7 +143,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Nodes: coscfg.Nodes{ &coscfg.Node{ Name: ptr("cosmos chain 1 node 1"), - TendermintURL: (*commoncfg.URL)(models.MustParseURL("http://localhost:9548").URL()), + TendermintURL: (*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:9548").URL()), }, }, }, @@ -160,7 +158,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Nodes: coscfg.Nodes{ &coscfg.Node{ Name: ptr("cosmos chain 2 node 1"), - TendermintURL: (*commoncfg.URL)(models.MustParseURL("http://localhost:9598").URL()), + TendermintURL: (*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:9598").URL()), }, }, }, @@ -206,10 +204,9 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { initFuncs: []chainlink.CoreRelayerChainInitFunc{ chainlink.InitEVM(testctx, factory, chainlink.EVMFactoryConfig{ ChainOpts: legacyevm.ChainOpts{ - AppConfig: cfg, - EventBroadcaster: pg.NewNullEventBroadcaster(), - MailMon: &mailbox.Monitor{}, - DB: db, + AppConfig: cfg, + MailMon: &mailbox.Monitor{}, + DB: db, }, CSAETHKeystore: keyStore, }), @@ -217,8 +214,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { expectedEVMChainCnt: 2, expectedEVMNodeCnt: 3, expectedEVMRelayerIds: []relay.ID{ - {Network: relay.EVM, ChainID: relay.ChainID(evmChainID1.String())}, - {Network: relay.EVM, ChainID: relay.ChainID(evmChainID2.String())}, + {Network: relay.EVM, ChainID: evmChainID1.String()}, + {Network: relay.EVM, ChainID: evmChainID2.String()}, }, expectedRelayerNetworks: map[relay.Network]struct{}{relay.EVM: {}}, }, @@ -233,8 +230,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { expectedSolanaChainCnt: 2, expectedSolanaNodeCnt: 2, expectedSolanaRelayerIds: []relay.ID{ - {Network: relay.Solana, ChainID: relay.ChainID(solanaChainID1)}, - {Network: relay.Solana, ChainID: relay.ChainID(solanaChainID2)}, + {Network: relay.Solana, ChainID: solanaChainID1}, + {Network: relay.Solana, ChainID: solanaChainID2}, }, expectedRelayerNetworks: map[relay.Network]struct{}{relay.Solana: {}}, }, @@ -249,8 +246,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { expectedStarknetChainCnt: 2, expectedStarknetNodeCnt: 4, expectedStarknetRelayerIds: []relay.ID{ - {Network: relay.StarkNet, ChainID: relay.ChainID(starknetChainID1)}, - {Network: relay.StarkNet, ChainID: relay.ChainID(starknetChainID2)}, + {Network: relay.StarkNet, ChainID: starknetChainID1}, + {Network: relay.StarkNet, ChainID: starknetChainID2}, }, expectedRelayerNetworks: map[relay.Network]struct{}{relay.StarkNet: {}}, }, @@ -267,8 +264,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { expectedCosmosChainCnt: 2, expectedCosmosNodeCnt: 2, expectedCosmosRelayerIds: []relay.ID{ - {Network: relay.Cosmos, ChainID: relay.ChainID(cosmosChainID1)}, - {Network: relay.Cosmos, ChainID: relay.ChainID(cosmosChainID2)}, + {Network: relay.Cosmos, ChainID: cosmosChainID1}, + {Network: relay.Cosmos, ChainID: cosmosChainID2}, }, expectedRelayerNetworks: map[relay.Network]struct{}{relay.Cosmos: {}}, }, @@ -280,10 +277,10 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { TOMLConfigs: cfg.SolanaConfigs()}), chainlink.InitEVM(testctx, factory, chainlink.EVMFactoryConfig{ ChainOpts: legacyevm.ChainOpts{ - AppConfig: cfg, - EventBroadcaster: pg.NewNullEventBroadcaster(), - MailMon: &mailbox.Monitor{}, - DB: db, + AppConfig: cfg, + + MailMon: &mailbox.Monitor{}, + DB: db, }, CSAETHKeystore: keyStore, }), @@ -300,29 +297,29 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { expectedEVMChainCnt: 2, expectedEVMNodeCnt: 3, expectedEVMRelayerIds: []relay.ID{ - {Network: relay.EVM, ChainID: relay.ChainID(evmChainID1.String())}, - {Network: relay.EVM, ChainID: relay.ChainID(evmChainID2.String())}, + {Network: relay.EVM, ChainID: evmChainID1.String()}, + {Network: relay.EVM, ChainID: evmChainID2.String()}, }, expectedSolanaChainCnt: 2, expectedSolanaNodeCnt: 2, expectedSolanaRelayerIds: []relay.ID{ - {Network: relay.Solana, ChainID: relay.ChainID(solanaChainID1)}, - {Network: relay.Solana, ChainID: relay.ChainID(solanaChainID2)}, + {Network: relay.Solana, ChainID: solanaChainID1}, + {Network: relay.Solana, ChainID: solanaChainID2}, }, expectedStarknetChainCnt: 2, expectedStarknetNodeCnt: 4, expectedStarknetRelayerIds: []relay.ID{ - {Network: relay.StarkNet, ChainID: relay.ChainID(starknetChainID1)}, - {Network: relay.StarkNet, ChainID: relay.ChainID(starknetChainID2)}, + {Network: relay.StarkNet, ChainID: starknetChainID1}, + {Network: relay.StarkNet, ChainID: starknetChainID2}, }, expectedCosmosChainCnt: 2, expectedCosmosNodeCnt: 2, expectedCosmosRelayerIds: []relay.ID{ - {Network: relay.Cosmos, ChainID: relay.ChainID(cosmosChainID1)}, - {Network: relay.Cosmos, ChainID: relay.ChainID(cosmosChainID2)}, + {Network: relay.Cosmos, ChainID: cosmosChainID1}, + {Network: relay.Cosmos, ChainID: cosmosChainID2}, }, expectedRelayerNetworks: map[relay.Network]struct{}{relay.EVM: {}, relay.Cosmos: {}, relay.Solana: {}, relay.StarkNet: {}}, diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index b4bd530d080..49582e2d52a 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -67,11 +67,10 @@ func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (m } relayerOpts := evmrelay.RelayerOpts{ - DB: ccOpts.DB, - QConfig: ccOpts.AppConfig.Database(), - CSAETHKeystore: config.CSAETHKeystore, - EventBroadcaster: ccOpts.EventBroadcaster, - MercuryPool: r.MercuryPool, + DB: ccOpts.DB, + QConfig: ccOpts.AppConfig.Database(), + CSAETHKeystore: config.CSAETHKeystore, + MercuryPool: r.MercuryPool, } relayer, err2 := evmrelay.NewRelayer(lggr.Named(relayID.ChainID), chain, relayerOpts) if err2 != nil { diff --git a/core/services/chainlink/testdata/config-empty-effective.toml b/core/services/chainlink/testdata/config-empty-effective.toml index 9efad05c03a..cc4dddcf8af 100644 --- a/core/services/chainlink/testdata/config-empty-effective.toml +++ b/core/services/chainlink/testdata/config-empty-effective.toml @@ -227,3 +227,6 @@ TLSCertPath = '' LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' + +[Mercury.TLS] +CertFile = '' diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index c6387e4ef67..da8b68cfdb1 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -238,6 +238,9 @@ LatestReportTTL = '1m40s' MaxStaleAge = '1m41s' LatestReportDeadline = '1m42s' +[Mercury.TLS] +CertFile = '/path/to/cert.pem' + [[EVM]] ChainID = '1' Enabled = false diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index 40c18f28eb9..d5352a685c4 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -228,6 +228,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/core/services/feeds/config.go b/core/services/feeds/config.go index 605e70c24c9..141e4910960 100644 --- a/core/services/feeds/config.go +++ b/core/services/feeds/config.go @@ -3,11 +3,11 @@ package feeds import ( "time" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" ) type JobConfig interface { - DefaultHTTPTimeout() models.Duration + DefaultHTTPTimeout() commonconfig.Duration } type InsecureConfig interface { diff --git a/core/services/feeds/mocks/config.go b/core/services/feeds/mocks/config.go deleted file mode 100644 index f2e4dcaa883..00000000000 --- a/core/services/feeds/mocks/config.go +++ /dev/null @@ -1,292 +0,0 @@ -// Code generated by mockery v2.22.1. DO NOT EDIT. - -package mocks - -import ( - time "time" - - models "github.com/smartcontractkit/chainlink/v2/core/store/models" - mock "github.com/stretchr/testify/mock" -) - -// Config is an autogenerated mock type for the Config type -type Config struct { - mock.Mock -} - -// DatabaseDefaultQueryTimeout provides a mock function with given fields: -func (_m *Config) DatabaseDefaultQueryTimeout() time.Duration { - ret := _m.Called() - - var r0 time.Duration - if rf, ok := ret.Get(0).(func() time.Duration); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(time.Duration) - } - - return r0 -} - -// DefaultHTTPTimeout provides a mock function with given fields: -func (_m *Config) DefaultHTTPTimeout() models.Duration { - ret := _m.Called() - - var r0 models.Duration - if rf, ok := ret.Get(0).(func() models.Duration); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(models.Duration) - } - - return r0 -} - -// Dev provides a mock function with given fields: -func (_m *Config) Dev() bool { - ret := _m.Called() - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// FeatureOffchainReporting provides a mock function with given fields: -func (_m *Config) FeatureOffchainReporting() bool { - ret := _m.Called() - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// FeatureOffchainReporting2 provides a mock function with given fields: -func (_m *Config) FeatureOffchainReporting2() bool { - ret := _m.Called() - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// JobPipelineMaxSuccessfulRuns provides a mock function with given fields: -func (_m *Config) JobPipelineMaxSuccessfulRuns() uint64 { - ret := _m.Called() - - var r0 uint64 - if rf, ok := ret.Get(0).(func() uint64); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint64) - } - - return r0 -} - -// JobPipelineResultWriteQueueDepth provides a mock function with given fields: -func (_m *Config) JobPipelineResultWriteQueueDepth() uint64 { - ret := _m.Called() - - var r0 uint64 - if rf, ok := ret.Get(0).(func() uint64); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint64) - } - - return r0 -} - -// LogSQL provides a mock function with given fields: -func (_m *Config) LogSQL() bool { - ret := _m.Called() - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// OCR2BlockchainTimeout provides a mock function with given fields: -func (_m *Config) OCR2BlockchainTimeout() time.Duration { - ret := _m.Called() - - var r0 time.Duration - if rf, ok := ret.Get(0).(func() time.Duration); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(time.Duration) - } - - return r0 -} - -// OCR2CaptureEATelemetry provides a mock function with given fields: -func (_m *Config) OCR2CaptureEATelemetry() bool { - ret := _m.Called() - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// OCR2ContractConfirmations provides a mock function with given fields: -func (_m *Config) OCR2ContractConfirmations() uint16 { - ret := _m.Called() - - var r0 uint16 - if rf, ok := ret.Get(0).(func() uint16); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint16) - } - - return r0 -} - -// OCR2ContractPollInterval provides a mock function with given fields: -func (_m *Config) OCR2ContractPollInterval() time.Duration { - ret := _m.Called() - - var r0 time.Duration - if rf, ok := ret.Get(0).(func() time.Duration); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(time.Duration) - } - - return r0 -} - -// OCR2ContractSubscribeInterval provides a mock function with given fields: -func (_m *Config) OCR2ContractSubscribeInterval() time.Duration { - ret := _m.Called() - - var r0 time.Duration - if rf, ok := ret.Get(0).(func() time.Duration); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(time.Duration) - } - - return r0 -} - -// OCR2ContractTransmitterTransmitTimeout provides a mock function with given fields: -func (_m *Config) OCR2ContractTransmitterTransmitTimeout() time.Duration { - ret := _m.Called() - - var r0 time.Duration - if rf, ok := ret.Get(0).(func() time.Duration); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(time.Duration) - } - - return r0 -} - -// OCR2DatabaseTimeout provides a mock function with given fields: -func (_m *Config) OCR2DatabaseTimeout() time.Duration { - ret := _m.Called() - - var r0 time.Duration - if rf, ok := ret.Get(0).(func() time.Duration); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(time.Duration) - } - - return r0 -} - -// OCR2KeyBundleID provides a mock function with given fields: -func (_m *Config) OCR2KeyBundleID() (string, error) { - ret := _m.Called() - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// OCR2TraceLogging provides a mock function with given fields: -func (_m *Config) OCR2TraceLogging() bool { - ret := _m.Called() - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// OCRDevelopmentMode provides a mock function with given fields: -func (_m *Config) OCRDevelopmentMode() bool { - ret := _m.Called() - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -type mockConstructorTestingTNewConfig interface { - mock.TestingT - Cleanup(func()) -} - -// NewConfig creates a new instance of Config. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewConfig(t mockConstructorTestingTNewConfig) *Config { - mock := &Config{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/feeds/orm_test.go b/core/services/feeds/orm_test.go index 88d3b132beb..78af9bf6912 100644 --- a/core/services/feeds/orm_test.go +++ b/core/services/feeds/orm_test.go @@ -645,7 +645,7 @@ func Test_ORM_CountJobProposalsByStatus(t *testing.T) { jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) // Create a spec for the pending job proposal - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) // Defer the FK requirement of an existing job for a job proposal to be approved require.NoError(t, utils.JustError(orm.db.Exec( @@ -870,7 +870,7 @@ func Test_ORM_UpsertJobProposal(t *testing.T) { assert.True(t, actual.PendingUpdate) // Approve - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) // Defer the FK requirement of an existing job for a job proposal. require.NoError(t, utils.JustError(orm.db.Exec( @@ -943,7 +943,7 @@ func Test_ORM_ApproveSpec(t *testing.T) { PendingUpdate: true, }) require.NoError(t, err) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) // Defer the FK requirement of an existing job for a job proposal. require.NoError(t, utils.JustError(orm.db.Exec( @@ -982,7 +982,7 @@ func Test_ORM_CancelSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -994,7 +994,7 @@ func Test_ORM_CancelSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusDeleted, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -1056,7 +1056,7 @@ func Test_ORM_DeleteProposal(t *testing.T) { before: func(orm *TestORM) int64 { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - createJobSpec(t, orm, int64(jpID)) + createJobSpec(t, orm, jpID) return jpID }, @@ -1068,7 +1068,7 @@ func Test_ORM_DeleteProposal(t *testing.T) { before: func(orm *TestORM) int64 { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) externalJobID := uuid.NullUUID{UUID: uuid.New(), Valid: true} @@ -1090,7 +1090,7 @@ func Test_ORM_DeleteProposal(t *testing.T) { before: func(orm *TestORM) int64 { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) externalJobID := uuid.NullUUID{UUID: uuid.New(), Valid: true} @@ -1131,7 +1131,7 @@ func Test_ORM_DeleteProposal(t *testing.T) { before: func(orm *TestORM) int64 { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusCancelled, fmID) - createJobSpec(t, orm, int64(jpID)) + createJobSpec(t, orm, jpID) return jpID }, @@ -1143,7 +1143,7 @@ func Test_ORM_DeleteProposal(t *testing.T) { before: func(orm *TestORM) int64 { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusRejected, fmID) - createJobSpec(t, orm, int64(jpID)) + createJobSpec(t, orm, jpID) return jpID }, @@ -1211,7 +1211,7 @@ func Test_ORM_RevokeSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -1224,7 +1224,7 @@ func Test_ORM_RevokeSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) externalJobID := uuid.NullUUID{UUID: uuid.New(), Valid: true} @@ -1246,7 +1246,7 @@ func Test_ORM_RevokeSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusCancelled, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -1258,7 +1258,7 @@ func Test_ORM_RevokeSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusRejected, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -1270,7 +1270,7 @@ func Test_ORM_RevokeSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusDeleted, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -1324,7 +1324,7 @@ func Test_ORM_ExistsSpecByJobProposalIDAndVersion(t *testing.T) { jpID = createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) ) - createJobSpec(t, orm, int64(jpID)) + createJobSpec(t, orm, jpID) exists, err := orm.ExistsSpecByJobProposalIDAndVersion(jpID, 1) require.NoError(t, err) @@ -1342,7 +1342,7 @@ func Test_ORM_GetSpec(t *testing.T) { orm = setupORM(t) fmID = createFeedsManager(t, orm) jpID = createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID = createJobSpec(t, orm, int64(jpID)) + specID = createJobSpec(t, orm, jpID) ) actual, err := orm.GetSpec(specID) @@ -1361,7 +1361,7 @@ func Test_ORM_GetApprovedSpec(t *testing.T) { orm = setupORM(t) fmID = createFeedsManager(t, orm) jpID = createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID = createJobSpec(t, orm, int64(jpID)) + specID = createJobSpec(t, orm, jpID) externalJobID = uuid.NullUUID{UUID: uuid.New(), Valid: true} ) @@ -1398,7 +1398,7 @@ func Test_ORM_GetLatestSpec(t *testing.T) { jpID = createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) ) - _ = createJobSpec(t, orm, int64(jpID)) + _ = createJobSpec(t, orm, jpID) spec2ID, err := orm.CreateSpec(feeds.JobProposalSpec{ Definition: "spec data", Version: 2, @@ -1429,8 +1429,8 @@ func Test_ORM_ListSpecsByJobProposalIDs(t *testing.T) { ) // Create the specs for the proposals - createJobSpec(t, orm, int64(jp1ID)) - createJobSpec(t, orm, int64(jp2ID)) + createJobSpec(t, orm, jp1ID) + createJobSpec(t, orm, jp2ID) specs, err := orm.ListSpecsByJobProposalIDs([]int64{jp1ID, jp2ID}) require.NoError(t, err) @@ -1466,7 +1466,7 @@ func Test_ORM_RejectSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -1478,7 +1478,7 @@ func Test_ORM_RejectSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) externalJobID := uuid.NullUUID{UUID: uuid.New(), Valid: true} @@ -1500,7 +1500,7 @@ func Test_ORM_RejectSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusCancelled, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -1512,7 +1512,7 @@ func Test_ORM_RejectSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusDeleted, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -1566,7 +1566,7 @@ func Test_ORM_UpdateSpecDefinition(t *testing.T) { orm = setupORM(t) fmID = createFeedsManager(t, orm) jpID = createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID = createJobSpec(t, orm, int64(jpID)) + specID = createJobSpec(t, orm, jpID) ) prev, err := orm.GetSpec(specID) @@ -1596,7 +1596,7 @@ func Test_ORM_IsJobManaged(t *testing.T) { orm = setupORM(t) fmID = createFeedsManager(t, orm) jpID = createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID = createJobSpec(t, orm, int64(jpID)) + specID = createJobSpec(t, orm, jpID) externalJobID = uuid.NullUUID{UUID: uuid.New(), Valid: true} ) diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index d37393eba9e..d822cd9787d 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -17,6 +17,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" @@ -41,7 +42,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/services/versioning" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils/crypto" ) @@ -626,7 +626,7 @@ func Test_Service_ProposeJob(t *testing.T) { JobProposalID: idBootstrap, } - httpTimeout = models.MustMakeDuration(1 * time.Second) + httpTimeout = *commonconfig.MustNewDuration(1 * time.Second) ) testCases := []struct { @@ -806,7 +806,7 @@ func Test_Service_DeleteJob(t *testing.T) { Status: feeds.JobProposalStatusApproved, } - httpTimeout = models.MustMakeDuration(1 * time.Second) + httpTimeout = *commonconfig.MustNewDuration(1 * time.Second) ) testCases := []struct { @@ -946,7 +946,7 @@ answer1 [type=median index=0]; Definition: defn, } - httpTimeout = models.MustMakeDuration(1 * time.Second) + httpTimeout = *commonconfig.MustNewDuration(1 * time.Second) ) testCases := []struct { @@ -1610,7 +1610,7 @@ answer1 [type=median index=0]; testCases := []struct { name string - httpTimeout *models.Duration + httpTimeout *commonconfig.Duration before func(svc *TestService) id int64 force bool @@ -1618,7 +1618,7 @@ answer1 [type=median index=0]; }{ { name: "pending job success for new proposals", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec, nil) @@ -1656,7 +1656,7 @@ answer1 [type=median index=0]; }, { name: "cancelled spec success when it is the latest spec", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", cancelledSpec.ID, mock.Anything).Return(cancelledSpec, nil) @@ -1695,7 +1695,7 @@ answer1 [type=median index=0]; }, { name: "pending job fail due to spec missing external job id", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec2, nil) @@ -1775,7 +1775,7 @@ answer1 [type=median index=0]; }, { name: "already existing job replacement (found via external job id) error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -1790,7 +1790,7 @@ answer1 [type=median index=0]; }, { name: "already existing job replacement error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -1806,7 +1806,7 @@ answer1 [type=median index=0]; }, { name: "already existing self managed job replacement success if forced (via external job id)", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec, nil) @@ -1845,7 +1845,7 @@ answer1 [type=median index=0]; }, { name: "already existing self managed job replacement success if forced", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec, nil) @@ -1885,7 +1885,7 @@ answer1 [type=median index=0]; }, { name: "already existing FMS managed job replacement success if forced", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec, nil) @@ -1944,7 +1944,7 @@ answer1 [type=median index=0]; }, { name: "bridges do not exist", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -1967,7 +1967,7 @@ answer1 [type=median index=0]; }, { name: "Fetching the approved spec fails (via external job id)", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec, nil) @@ -1982,7 +1982,7 @@ answer1 [type=median index=0]; }, { name: "Fetching the approved spec fails", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec, nil) @@ -1998,7 +1998,7 @@ answer1 [type=median index=0]; }, { name: "spec cancellation fails (via external job id)", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec, nil) @@ -2014,7 +2014,7 @@ answer1 [type=median index=0]; }, { name: "spec cancellation fails", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec, nil) @@ -2031,7 +2031,7 @@ answer1 [type=median index=0]; }, { name: "create job error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) @@ -2056,7 +2056,7 @@ answer1 [type=median index=0]; }, { name: "approve spec orm error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) @@ -2087,7 +2087,7 @@ answer1 [type=median index=0]; }, { name: "fms call error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) @@ -2250,7 +2250,7 @@ answer1 [type=median index=0]; testCases := []struct { name string - httpTimeout *models.Duration + httpTimeout *commonconfig.Duration before func(svc *TestService) id int64 force bool @@ -2258,7 +2258,7 @@ answer1 [type=median index=0]; }{ { name: "pending job success", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -2295,7 +2295,7 @@ answer1 [type=median index=0]; }, { name: "cancelled spec success when it is the latest spec", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", cancelledSpec.ID, mock.Anything).Return(cancelledSpec, nil) @@ -2361,7 +2361,7 @@ answer1 [type=median index=0]; }, { name: "already existing job replacement error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -2376,7 +2376,7 @@ answer1 [type=median index=0]; }, { name: "already existing self managed job replacement success if forced without feedID", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -2415,7 +2415,7 @@ answer1 [type=median index=0]; }, { name: "already existing self managed job replacement success if forced with feedID", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(&feeds.JobProposalSpec{ @@ -2460,7 +2460,7 @@ answer1 [type=median index=0]; }, { name: "already existing FMS managed job replacement success if forced", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -2548,7 +2548,7 @@ answer1 [type=median index=0]; }, { name: "bridges do not exist", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -2571,7 +2571,7 @@ answer1 [type=median index=0]; }, { name: "create job error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) @@ -2596,7 +2596,7 @@ answer1 [type=median index=0]; }, { name: "approve spec orm error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) @@ -2627,7 +2627,7 @@ answer1 [type=median index=0]; }, { name: "fms call error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) @@ -2756,7 +2756,7 @@ chainID = 0 testCases := []struct { name string - httpTimeout *models.Duration + httpTimeout *commonconfig.Duration before func(svc *TestService) id int64 force bool @@ -2764,7 +2764,7 @@ chainID = 0 }{ { name: "pending job success", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -2801,7 +2801,7 @@ chainID = 0 }, { name: "cancelled spec success when it is the latest spec", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", cancelledSpec.ID, mock.Anything).Return(cancelledSpec, nil) @@ -2867,7 +2867,7 @@ chainID = 0 }, { name: "already existing job replacement error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -2882,7 +2882,7 @@ chainID = 0 }, { name: "already existing self managed job replacement success if forced without feedID", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -2921,7 +2921,7 @@ chainID = 0 }, { name: "already existing self managed job replacement success if forced with feedID", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(&feeds.JobProposalSpec{ @@ -2966,7 +2966,7 @@ chainID = 0 }, { name: "already existing FMS managed job replacement success if forced", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -3054,7 +3054,7 @@ chainID = 0 }, { name: "bridges do not exist", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -3077,7 +3077,7 @@ chainID = 0 }, { name: "create job error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) @@ -3102,7 +3102,7 @@ chainID = 0 }, { name: "approve spec orm error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) @@ -3133,7 +3133,7 @@ chainID = 0 }, { name: "fms call error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) diff --git a/core/services/fluxmonitorv2/config.go b/core/services/fluxmonitorv2/config.go index 2680f30a777..18fdf72798b 100644 --- a/core/services/fluxmonitorv2/config.go +++ b/core/services/fluxmonitorv2/config.go @@ -4,8 +4,8 @@ import ( "time" "github.com/smartcontractkit/chainlink-common/pkg/assets" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) // Config defines the Flux Monitor configuration. @@ -28,7 +28,7 @@ type FluxMonitorConfig interface { } type JobPipelineConfig interface { - DefaultHTTPTimeout() models.Duration + DefaultHTTPTimeout() commonconfig.Duration } // MinimumPollingInterval returns the minimum duration between polling ticks diff --git a/core/services/fluxmonitorv2/integrations_test.go b/core/services/fluxmonitorv2/integrations_test.go index 48c9ca24ac3..7f45e6eb19c 100644 --- a/core/services/fluxmonitorv2/integrations_test.go +++ b/core/services/fluxmonitorv2/integrations_test.go @@ -26,6 +26,7 @@ import ( "github.com/jmoiron/sqlx" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" @@ -448,8 +449,8 @@ func TestFluxMonitor_Deviation(t *testing.T) { // Set up chainlink app app := startApplication(t, fa, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(100 * time.Millisecond) - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(1 * time.Second) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(1 * time.Second) c.EVM[0].GasEstimator.EIP1559DynamicFees = &test.eip1559 }) @@ -518,7 +519,7 @@ func TestFluxMonitor_Deviation(t *testing.T) { s = fmt.Sprintf(s, fa.aggregatorContractAddress, 2*time.Second) requestBody, err := json.Marshal(web.CreateJobRequest{ - TOML: string(s), + TOML: s, }) assert.NoError(t, err) @@ -620,8 +621,8 @@ func TestFluxMonitor_NewRound(t *testing.T) { // Set up chainlink app app := startApplication(t, fa, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(100 * time.Millisecond) - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(1 * time.Second) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(1 * time.Second) flags := ethkey.EIP55AddressFromAddress(fa.flagsContractAddress) c.EVM[0].FlagsContractAddress = &flags }) @@ -675,7 +676,7 @@ ds1 -> ds1_parse fa.backend.Commit() requestBody, err := json.Marshal(web.CreateJobRequest{ - TOML: string(s), + TOML: s, }) assert.NoError(t, err) @@ -731,8 +732,8 @@ func TestFluxMonitor_HibernationMode(t *testing.T) { // Start chainlink app app := startApplication(t, fa, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(100 * time.Millisecond) - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(1 * time.Second) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(1 * time.Second) flags := ethkey.EIP55AddressFromAddress(fa.flagsContractAddress) c.EVM[0].FlagsContractAddress = &flags }) @@ -785,7 +786,7 @@ ds1 -> ds1_parse fa.backend.Commit() requestBody, err := json.Marshal(web.CreateJobRequest{ - TOML: string(s), + TOML: s, }) assert.NoError(t, err) @@ -848,8 +849,8 @@ func TestFluxMonitor_InvalidSubmission(t *testing.T) { // Set up chainlink app app := startApplication(t, fa, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(100 * time.Millisecond) - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(1 * time.Second) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) // Report a price that is above the maximum allowed value, @@ -895,7 +896,7 @@ ds1 -> ds1_parse fa.backend.Commit() requestBody, err := json.Marshal(web.CreateJobRequest{ - TOML: string(s), + TOML: s, }) assert.NoError(t, err) @@ -925,8 +926,8 @@ func TestFluxMonitorAntiSpamLogic(t *testing.T) { // Set up chainlink app app := startApplication(t, fa, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(100 * time.Millisecond) - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(1 * time.Second) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) answer := int64(1) // Answer the nodes give on the first round @@ -990,7 +991,7 @@ ds1 -> ds1_parse -> ds1_multiply s = fmt.Sprintf(s, fa.aggregatorContractAddress, testutils.SimulatedChainID.String(), "200ms", mockServer.URL) requestBody, err := json.Marshal(web.CreateJobRequest{ - TOML: string(s), + TOML: s, }) assert.NoError(t, err) diff --git a/core/services/fluxmonitorv2/validate.go b/core/services/fluxmonitorv2/validate.go index 02dbfb01284..fc531fc7cb4 100644 --- a/core/services/fluxmonitorv2/validate.go +++ b/core/services/fluxmonitorv2/validate.go @@ -8,13 +8,13 @@ import ( "github.com/pelletier/go-toml" "github.com/pkg/errors" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) type ValidationConfig interface { - DefaultHTTPTimeout() models.Duration + DefaultHTTPTimeout() commonconfig.Duration } func ValidatedFluxMonitorSpec(config ValidationConfig, ts string) (job.Job, error) { diff --git a/core/services/fluxmonitorv2/validate_test.go b/core/services/fluxmonitorv2/validate_test.go index 94dc8b6b709..40efd1d724d 100644 --- a/core/services/fluxmonitorv2/validate_test.go +++ b/core/services/fluxmonitorv2/validate_test.go @@ -6,8 +6,8 @@ import ( "time" "github.com/smartcontractkit/chainlink-common/pkg/assets" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils/tomlutils" "github.com/stretchr/testify/assert" @@ -16,7 +16,9 @@ import ( type testcfg struct{} -func (testcfg) DefaultHTTPTimeout() models.Duration { return models.MustMakeDuration(2 * time.Second) } +func (testcfg) DefaultHTTPTimeout() commonconfig.Duration { + return *commonconfig.MustNewDuration(2 * time.Second) +} func TestValidate(t *testing.T) { var tt = []struct { diff --git a/core/services/functions/listener_test.go b/core/services/functions/listener_test.go index 5d26f9a4f57..75161d3410b 100644 --- a/core/services/functions/listener_test.go +++ b/core/services/functions/listener_test.go @@ -161,7 +161,7 @@ func TestFunctionsListener_HandleOracleRequestV1_Success(t *testing.T) { request := types.OracleRequest{ RequestId: RequestID, - SubscriptionId: uint64(SubscriptionID), + SubscriptionId: SubscriptionID, SubscriptionOwner: SubscriptionOwner, Flags: packFlags(1, 0), // tier no 1 of request size, allows up to 100 bytes Data: make([]byte, 12), @@ -194,7 +194,7 @@ func TestFunctionsListener_HandleOffchainRequest_Success(t *testing.T) { request := &functions_service.OffchainRequest{ RequestId: RequestID[:], RequestInitiator: SubscriptionOwner.Bytes(), - SubscriptionId: uint64(SubscriptionID), + SubscriptionId: SubscriptionID, SubscriptionOwner: SubscriptionOwner.Bytes(), Timestamp: uint64(time.Now().Unix()), Data: functions_service.RequestData{}, @@ -210,7 +210,7 @@ func TestFunctionsListener_HandleOffchainRequest_Invalid(t *testing.T) { request := &functions_service.OffchainRequest{ RequestId: RequestID[:], RequestInitiator: []byte("invalid_address"), - SubscriptionId: uint64(SubscriptionID), + SubscriptionId: SubscriptionID, SubscriptionOwner: SubscriptionOwner.Bytes(), Timestamp: uint64(time.Now().Unix()), Data: functions_service.RequestData{}, @@ -238,7 +238,7 @@ func TestFunctionsListener_HandleOffchainRequest_InternalError(t *testing.T) { request := &functions_service.OffchainRequest{ RequestId: RequestID[:], RequestInitiator: SubscriptionOwner.Bytes(), - SubscriptionId: uint64(SubscriptionID), + SubscriptionId: SubscriptionID, SubscriptionOwner: SubscriptionOwner.Bytes(), Timestamp: uint64(time.Now().Unix()), Data: functions_service.RequestData{}, @@ -255,7 +255,7 @@ func TestFunctionsListener_HandleOracleRequestV1_ComputationError(t *testing.T) request := types.OracleRequest{ RequestId: RequestID, - SubscriptionId: uint64(SubscriptionID), + SubscriptionId: SubscriptionID, SubscriptionOwner: SubscriptionOwner, Flags: packFlags(1, 0), // tier no 1 of request size, allows up to 100 bytes Data: make([]byte, 12), @@ -291,7 +291,7 @@ func TestFunctionsListener_HandleOracleRequestV1_ThresholdDecryptedSecrets(t *te cborBytes = cborBytes[1:] request := types.OracleRequest{ RequestId: RequestID, - SubscriptionId: uint64(SubscriptionID), + SubscriptionId: SubscriptionID, SubscriptionOwner: SubscriptionOwner, Flags: packFlags(1, 1), // tiers no 1 of request size and secrets size, allow up to 100 bytes Data: cborBytes, @@ -324,7 +324,7 @@ func TestFunctionsListener_HandleOracleRequestV1_CBORTooBig(t *testing.T) { request := types.OracleRequest{ RequestId: RequestID, - SubscriptionId: uint64(SubscriptionID), + SubscriptionId: SubscriptionID, SubscriptionOwner: SubscriptionOwner, Flags: packFlags(0, 0), // tier no 0 of request size, allows only for max 10 bytes Data: make([]byte, 20), @@ -350,7 +350,7 @@ func TestFunctionsListener_ReportSourceCodeDomains(t *testing.T) { request := types.OracleRequest{ RequestId: RequestID, - SubscriptionId: uint64(SubscriptionID), + SubscriptionId: SubscriptionID, SubscriptionOwner: SubscriptionOwner, Flags: packFlags(1, 0), // tier no 1 of request size, allows up to 100 bytes Data: make([]byte, 12), diff --git a/core/services/gateway/connector/connector.go b/core/services/gateway/connector/connector.go index 6b399733a58..9f809a326c8 100644 --- a/core/services/gateway/connector/connector.go +++ b/core/services/gateway/connector/connector.go @@ -83,7 +83,7 @@ func NewGatewayConnector(config *ConnectorConfig, signer Signer, handler Gateway if config == nil || signer == nil || handler == nil || clock == nil || lggr == nil { return nil, errors.New("nil dependency") } - if len(config.DonId) == 0 || len(config.DonId) > int(network.HandshakeDonIdLen) { + if len(config.DonId) == 0 || len(config.DonId) > network.HandshakeDonIdLen { return nil, errors.New("invalid DON ID") } addressBytes, err := hex.DecodeString(config.NodeAddress) diff --git a/core/services/gateway/gateway_test.go b/core/services/gateway/gateway_test.go index 1c31a643c80..7a5457c788c 100644 --- a/core/services/gateway/gateway_test.go +++ b/core/services/gateway/gateway_test.go @@ -225,7 +225,7 @@ func TestGateway_ProcessRequest_HandlerTimeout(t *testing.T) { gw, handler := newGatewayWithMockHandler(t) handler.On("HandleUserMessage", mock.Anything, mock.Anything, mock.Anything).Return(nil) - timeoutCtx, cancel := context.WithTimeout(testutils.Context(t), time.Duration(time.Millisecond*10)) + timeoutCtx, cancel := context.WithTimeout(testutils.Context(t), time.Millisecond*10) defer cancel() req := newSignedRequest(t, "abcd", "request", "testDON", []byte{}) diff --git a/core/services/gateway/network/httpserver_test.go b/core/services/gateway/network/httpserver_test.go index 92215245e20..dac00df2a12 100644 --- a/core/services/gateway/network/httpserver_test.go +++ b/core/services/gateway/network/httpserver_test.go @@ -47,7 +47,7 @@ func startNewServer(t *testing.T, maxRequestBytes int64, readTimeoutMillis uint3 } func sendRequest(t *testing.T, url string, body []byte) *http.Response { - req, err := http.NewRequest("POST", url, bytes.NewBuffer(body)) + req, err := http.NewRequestWithContext(testutils.Context(t), "POST", url, bytes.NewBuffer(body)) require.NoError(t, err) client := &http.Client{} resp, err := client.Do(req) diff --git a/core/services/gateway/network/wsserver_test.go b/core/services/gateway/network/wsserver_test.go index 1a4c04787b4..0b24dbe6614 100644 --- a/core/services/gateway/network/wsserver_test.go +++ b/core/services/gateway/network/wsserver_test.go @@ -49,7 +49,7 @@ func startNewWSServer(t *testing.T, readTimeoutMillis uint32) (server network.We } func sendRequestWithHeader(t *testing.T, url string, headerName string, headerValue string) *http.Response { - req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte{})) + req, err := http.NewRequestWithContext(testutils.Context(t), "POST", url, bytes.NewBuffer([]byte{})) require.NoError(t, err) req.Header.Set(headerName, headerValue) diff --git a/core/services/health_test.go b/core/services/health_test.go index 3bd0e5d39b2..b95b266ca19 100644 --- a/core/services/health_test.go +++ b/core/services/health_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services" ) @@ -20,7 +21,9 @@ func TestNewInBackupHealthReport(t *testing.T) { require.Eventually(t, func() bool { return observed.Len() >= 1 }, time.Second*5, time.Millisecond*100) require.Equal(t, "Starting InBackupHealthReport", observed.TakeAll()[0].Message) - res, err := http.Get("http://localhost:1234/health") + req, err := http.NewRequestWithContext(tests.Context(t), "GET", "http://localhost:1234/health", nil) + require.NoError(t, err) + res, err := http.DefaultClient.Do(req) require.NoError(t, err) require.Equal(t, http.StatusNoContent, res.StatusCode) diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index 768d16ddeb7..3590b526022 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -21,6 +21,7 @@ import ( evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" @@ -1386,7 +1387,7 @@ func Test_FindPipelineRunIDsByJobID(t *testing.T) { var jb job.Job config := configtest.NewTestGeneralConfig(t) - db := pgtest.NewSqlxDB(t) + _, db := heavyweight.FullTestDBV2(t, nil) keyStore := cltest.NewKeyStore(t, db, config.Database()) require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) diff --git a/core/services/job/job_pipeline_orm_integration_test.go b/core/services/job/job_pipeline_orm_integration_test.go index f1307753d29..dd3062fa14b 100644 --- a/core/services/job/job_pipeline_orm_integration_test.go +++ b/core/services/job/job_pipeline_orm_integration_test.go @@ -9,6 +9,7 @@ import ( "github.com/jmoiron/sqlx" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -46,7 +47,7 @@ func TestPipelineORM_Integration(t *testing.T) { ` config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(30 * time.Millisecond) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(30 * time.Millisecond) }) db := pgtest.NewSqlxDB(t) keyStore := cltest.NewKeyStore(t, db, config.Database()) diff --git a/core/services/job/models.go b/core/services/job/models.go index 0911657abdc..e6e8fb631c3 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -33,20 +33,21 @@ import ( ) const ( + BlockHeaderFeeder Type = (Type)(pipeline.BlockHeaderFeederJobType) + BlockhashStore Type = (Type)(pipeline.BlockhashStoreJobType) + Bootstrap Type = (Type)(pipeline.BootstrapJobType) Cron Type = (Type)(pipeline.CronJobType) DirectRequest Type = (Type)(pipeline.DirectRequestJobType) FluxMonitor Type = (Type)(pipeline.FluxMonitorJobType) - OffchainReporting Type = (Type)(pipeline.OffchainReportingJobType) - OffchainReporting2 Type = (Type)(pipeline.OffchainReporting2JobType) + Gateway Type = (Type)(pipeline.GatewayJobType) Keeper Type = (Type)(pipeline.KeeperJobType) - VRF Type = (Type)(pipeline.VRFJobType) - BlockhashStore Type = (Type)(pipeline.BlockhashStoreJobType) - BlockHeaderFeeder Type = (Type)(pipeline.BlockHeaderFeederJobType) LegacyGasStationServer Type = (Type)(pipeline.LegacyGasStationServerJobType) LegacyGasStationSidecar Type = (Type)(pipeline.LegacyGasStationSidecarJobType) + OffchainReporting Type = (Type)(pipeline.OffchainReportingJobType) + OffchainReporting2 Type = (Type)(pipeline.OffchainReporting2JobType) + Stream Type = (Type)(pipeline.StreamJobType) + VRF Type = (Type)(pipeline.VRFJobType) Webhook Type = (Type)(pipeline.WebhookJobType) - Bootstrap Type = (Type)(pipeline.BootstrapJobType) - Gateway Type = (Type)(pipeline.GatewayJobType) ) //revive:disable:redefines-builtin-id @@ -70,52 +71,55 @@ func (t Type) SchemaVersion() uint32 { var ( requiresPipelineSpec = map[Type]bool{ + BlockHeaderFeeder: false, + BlockhashStore: false, + Bootstrap: false, Cron: true, DirectRequest: true, FluxMonitor: true, - OffchainReporting: false, // bootstrap jobs do not require it - OffchainReporting2: false, // bootstrap jobs do not require it + Gateway: false, Keeper: false, // observationSource is injected in the upkeep executor - VRF: true, - Webhook: true, - BlockhashStore: false, - BlockHeaderFeeder: false, LegacyGasStationServer: false, LegacyGasStationSidecar: false, - Bootstrap: false, - Gateway: false, + OffchainReporting2: false, // bootstrap jobs do not require it + OffchainReporting: false, // bootstrap jobs do not require it + Stream: true, + VRF: true, + Webhook: true, } supportsAsync = map[Type]bool{ + BlockHeaderFeeder: false, + BlockhashStore: false, + Bootstrap: false, Cron: true, DirectRequest: true, FluxMonitor: false, - OffchainReporting: false, - OffchainReporting2: false, + Gateway: false, Keeper: true, - VRF: true, - Webhook: true, - BlockhashStore: false, - BlockHeaderFeeder: false, LegacyGasStationServer: false, LegacyGasStationSidecar: false, - Bootstrap: false, - Gateway: false, + OffchainReporting2: false, + OffchainReporting: false, + Stream: true, + VRF: true, + Webhook: true, } schemaVersions = map[Type]uint32{ + BlockHeaderFeeder: 1, + BlockhashStore: 1, + Bootstrap: 1, Cron: 1, DirectRequest: 1, FluxMonitor: 1, - OffchainReporting: 1, - OffchainReporting2: 1, + Gateway: 1, Keeper: 1, - VRF: 1, - Webhook: 1, - BlockhashStore: 1, - BlockHeaderFeeder: 1, LegacyGasStationServer: 1, LegacyGasStationSidecar: 1, - Bootstrap: 1, - Gateway: 1, + OffchainReporting2: 1, + OffchainReporting: 1, + Stream: 1, + VRF: 1, + Webhook: 1, } ) @@ -232,7 +236,7 @@ func (pr *PipelineRun) SetID(value string) error { if err != nil { return err } - pr.ID = int64(ID) + pr.ID = ID return nil } @@ -380,7 +384,7 @@ func (s *OCR2OracleSpec) RelayID() (relay.ID, error) { func (s *OCR2OracleSpec) getChainID() (relay.ChainID, error) { if s.ChainID != "" { - return relay.ChainID(s.ChainID), nil + return s.ChainID, nil } // backward compatible job spec return s.getChainIdFromRelayConfig() @@ -394,13 +398,13 @@ func (s *OCR2OracleSpec) getChainIdFromRelayConfig() (relay.ChainID, error) { } switch t := v.(type) { case string: - return relay.ChainID(t), nil + return t, nil case int, int64, int32: - return relay.ChainID(fmt.Sprintf("%d", v)), nil + return fmt.Sprintf("%d", v), nil case float64: // backward compatibility with JSONConfig.EVMChainID i := int64(t) - return relay.ChainID(strconv.FormatInt(i, 10)), nil + return strconv.FormatInt(i, 10), nil default: return "", fmt.Errorf("unable to parse chainID: unexpected type %T", t) diff --git a/core/services/job/models_test.go b/core/services/job/models_test.go index 277f0d7eb29..ddbb815e730 100644 --- a/core/services/job/models_test.go +++ b/core/services/job/models_test.go @@ -30,7 +30,7 @@ func TestOCR2OracleSpec_RelayIdentifier(t *testing.T) { Relay: relay.EVM, ChainID: "1", }, - want: relay.ID{Network: relay.EVM, ChainID: relay.ChainID("1")}, + want: relay.ID{Network: relay.EVM, ChainID: "1"}, }, { name: "evm implicitly configured", @@ -38,7 +38,7 @@ func TestOCR2OracleSpec_RelayIdentifier(t *testing.T) { Relay: relay.EVM, RelayConfig: map[string]any{"chainID": 1}, }, - want: relay.ID{Network: relay.EVM, ChainID: relay.ChainID("1")}, + want: relay.ID{Network: relay.EVM, ChainID: "1"}, }, { name: "evm implicitly configured with bad value", diff --git a/core/services/job/orm.go b/core/services/job/orm.go index 6c5a879ebd0..82c6be2963c 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -440,6 +440,8 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { return errors.Wrap(err, "failed to create GatewaySpec for jobSpec") } jb.GatewaySpecID = &specID + case Stream: + // 'stream' type has no associated spec, nothing to do here default: o.lggr.Panicf("Unsupported jb.Type: %v", jb.Type) } @@ -695,7 +697,7 @@ func (o *orm) FindJobs(offset, limit int) (jobs []Job, count int, err error) { return nil }) - return jobs, int(count), err + return jobs, count, err } func LoadDefaultVRFPollPeriod(vrfs VRFSpec) *VRFSpec { diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index 27c0e0e8515..fb671982ec5 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -23,6 +23,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" @@ -68,8 +69,8 @@ func TestRunner(t *testing.T) { c.OCR.KeyBundleID = &kbid taddress := ethkey.EIP55AddressFromAddress(transmitterAddress) c.OCR.TransmitterAddress = &taddress - c.OCR2.DatabaseTimeout = models.MustNewDuration(time.Second) - c.OCR2.ContractTransmitterTransmitTimeout = models.MustNewDuration(time.Second) + c.OCR2.DatabaseTimeout = commonconfig.MustNewDuration(time.Second) + c.OCR2.ContractTransmitterTransmitTimeout = commonconfig.MustNewDuration(time.Second) c.Insecure.OCRDevelopmentMode = ptr(true) }) @@ -746,7 +747,7 @@ func TestRunner_Success_Callback_AsyncJob(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { t := true c.JobPipeline.ExternalInitiatorsEnabled = &t - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(10 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(10 * time.Millisecond) }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient, cltest.UseRealExternalInitiatorManager) @@ -925,7 +926,7 @@ func TestRunner_Error_Callback_AsyncJob(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { t := true c.JobPipeline.ExternalInitiatorsEnabled = &t - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(10 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(10 * time.Millisecond) }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient, cltest.UseRealExternalInitiatorManager) diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index a46d9ca6c32..3e8ccbab848 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -31,7 +31,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" @@ -285,10 +284,9 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { chain := evmtest.MustGetDefaultChain(t, legacyChains) evmRelayer, err := evmrelayer.NewRelayer(lggr, chain, evmrelayer.RelayerOpts{ - DB: db, - QConfig: testopts.GeneralConfig.Database(), - CSAETHKeystore: keyStore, - EventBroadcaster: pg.NewNullEventBroadcaster(), + DB: db, + QConfig: testopts.GeneralConfig.Database(), + CSAETHKeystore: keyStore, }) assert.NoError(t, err) @@ -306,7 +304,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { ocr2DelegateConfig := ocr2.NewDelegateConfig(config.OCR2(), config.Mercury(), config.Threshold(), config.Insecure(), config.JobPipeline(), config.Database(), processConfig) d := ocr2.NewDelegate(nil, orm, nil, nil, nil, nil, monitoringEndpoint, legacyChains, lggr, ocr2DelegateConfig, - keyStore.OCR2(), keyStore.DKGSign(), keyStore.DKGEncrypt(), ethKeyStore, testRelayGetter, mailMon, nil) + keyStore.OCR2(), keyStore.DKGSign(), keyStore.DKGEncrypt(), ethKeyStore, testRelayGetter, mailMon) delegateOCR2 := &delegate{jobOCR2VRF.Type, []job.ServiceCtx{}, 0, nil, d} spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{ diff --git a/core/services/job/validate.go b/core/services/job/validate.go index b7a1dca3616..f108031f72e 100644 --- a/core/services/job/validate.go +++ b/core/services/job/validate.go @@ -12,20 +12,21 @@ var ( ErrInvalidJobType = errors.New("invalid job type") ErrInvalidSchemaVersion = errors.New("invalid schema version") jobTypes = map[Type]struct{}{ + BlockHeaderFeeder: {}, + BlockhashStore: {}, + Bootstrap: {}, Cron: {}, DirectRequest: {}, FluxMonitor: {}, - OffchainReporting: {}, - OffchainReporting2: {}, - Keeper: {}, - VRF: {}, - Webhook: {}, - BlockhashStore: {}, - Bootstrap: {}, - BlockHeaderFeeder: {}, Gateway: {}, + Keeper: {}, LegacyGasStationServer: {}, LegacyGasStationSidecar: {}, + OffchainReporting2: {}, + OffchainReporting: {}, + Stream: {}, + VRF: {}, + Webhook: {}, } ) diff --git a/core/services/keeper/integration_test.go b/core/services/keeper/integration_test.go index c35ebc81b7f..af95788029f 100644 --- a/core/services/keeper/integration_test.go +++ b/core/services/keeper/integration_test.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/libocr/gethwrappers/link_token_interface" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" @@ -36,7 +37,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/store/models" webpresenters "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -238,8 +238,8 @@ func TestKeeperEthIntegration(t *testing.T) { // setup app config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = &test.eip1559 - c.Keeper.MaxGracePeriod = ptr[int64](0) // avoid waiting to re-submit for upkeeps - c.Keeper.Registry.SyncInterval = models.MustNewDuration(24 * time.Hour) // disable full sync ticker for test + c.Keeper.MaxGracePeriod = ptr[int64](0) // avoid waiting to re-submit for upkeeps + c.Keeper.Registry.SyncInterval = commonconfig.MustNewDuration(24 * time.Hour) // disable full sync ticker for test c.Keeper.TurnLookBack = ptr[int64](0) // testing doesn't need to do far look back @@ -396,8 +396,8 @@ func TestKeeperForwarderEthIntegration(t *testing.T) { config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Feature.LogPoller = ptr(true) c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) - c.Keeper.MaxGracePeriod = ptr[int64](0) // avoid waiting to re-submit for upkeeps - c.Keeper.Registry.SyncInterval = models.MustNewDuration(24 * time.Hour) // disable full sync ticker for test + c.Keeper.MaxGracePeriod = ptr[int64](0) // avoid waiting to re-submit for upkeeps + c.Keeper.Registry.SyncInterval = commonconfig.MustNewDuration(24 * time.Hour) // disable full sync ticker for test c.Keeper.TurnLookBack = ptr[int64](0) // testing doesn't need to do far look back @@ -541,9 +541,9 @@ func TestMaxPerformDataSize(t *testing.T) { // setup app config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.Keeper.MaxGracePeriod = ptr[int64](0) // avoid waiting to re-submit for upkeeps - c.Keeper.Registry.SyncInterval = models.MustNewDuration(24 * time.Hour) // disable full sync ticker for test - c.Keeper.Registry.MaxPerformDataSize = ptr(uint32(maxPerformDataSize)) // set the max perform data size + c.Keeper.MaxGracePeriod = ptr[int64](0) // avoid waiting to re-submit for upkeeps + c.Keeper.Registry.SyncInterval = commonconfig.MustNewDuration(24 * time.Hour) // disable full sync ticker for test + c.Keeper.Registry.MaxPerformDataSize = ptr(uint32(maxPerformDataSize)) // set the max perform data size c.Keeper.TurnLookBack = ptr[int64](0) // testing doesn't need to do far look back diff --git a/core/services/keystore/keys/ocr2key/offchain_keyring.go b/core/services/keystore/keys/ocr2key/offchain_keyring.go index 9e6d8f64e03..36fc1cfd02a 100644 --- a/core/services/keystore/keys/ocr2key/offchain_keyring.go +++ b/core/services/keystore/keys/ocr2key/offchain_keyring.go @@ -68,7 +68,7 @@ func (ok *OffchainKeyring) NaclBoxOpenAnonymous(ciphertext []byte) (plaintext [] // OffchainSign signs message using private key func (ok *OffchainKeyring) OffchainSign(msg []byte) (signature []byte, err error) { - return ed25519.Sign(ed25519.PrivateKey(ok.signingKey), msg), nil + return ed25519.Sign(ok.signingKey, msg), nil } // ConfigDiffieHellman returns the shared point obtained by multiplying someone's diff --git a/core/services/keystore/p2p_test.go b/core/services/keystore/p2p_test.go index 4e9ca75c456..4dc44651473 100644 --- a/core/services/keystore/p2p_test.go +++ b/core/services/keystore/p2p_test.go @@ -177,6 +177,7 @@ func Test_P2PKeyStore_E2E(t *testing.T) { RETURNING *;`, p2pTableName) stmt, err := db.PrepareNamed(sql) require.NoError(t, err) + t.Cleanup(func() { assert.NoError(t, stmt.Close()) }) require.NoError(t, stmt.Get(&p2pPeer1, &p2pPeer1)) require.NoError(t, stmt.Get(&p2pPeer2, &p2pPeer2)) cltest.AssertCount(t, db, p2pTableName, 2) diff --git a/core/services/nurse.go b/core/services/nurse.go index 3d896a80ff3..1b44beea21c 100644 --- a/core/services/nurse.go +++ b/core/services/nurse.go @@ -17,9 +17,9 @@ import ( "github.com/google/pprof/profile" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -40,14 +40,14 @@ type Nurse struct { type Config interface { BlockProfileRate() int CPUProfileRate() int - GatherDuration() models.Duration - GatherTraceDuration() models.Duration + GatherDuration() commonconfig.Duration + GatherTraceDuration() commonconfig.Duration GoroutineThreshold() int MaxProfileSize() utils.FileSize MemProfileRate() int MemThreshold() utils.FileSize MutexProfileFraction() int - PollInterval() models.Duration + PollInterval() commonconfig.Duration ProfileRoot() string } diff --git a/core/services/nurse_test.go b/core/services/nurse_test.go index 79f57d91235..7521168aa3f 100644 --- a/core/services/nurse_test.go +++ b/core/services/nurse_test.go @@ -9,18 +9,18 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) type mockConfig struct { t *testing.T root string - pollInterval *models.Duration - gatherDuration *models.Duration - traceDuration *models.Duration + pollInterval *commonconfig.Duration + gatherDuration *commonconfig.Duration + traceDuration *commonconfig.Duration profileSize utils.FileSize cpuProfileRate int memProfileRate int @@ -31,8 +31,8 @@ type mockConfig struct { } var ( - testInterval = time.Duration(50 * time.Millisecond) - testDuration = time.Duration(20 * time.Millisecond) + testInterval = 50 * time.Millisecond + testDuration = 20 * time.Millisecond testRate = 100 testSize = 16 * 1024 * 1024 ) @@ -40,9 +40,9 @@ var ( func newMockConfig(t *testing.T) *mockConfig { return &mockConfig{ root: t.TempDir(), - pollInterval: models.MustNewDuration(testInterval), - gatherDuration: models.MustNewDuration(testDuration), - traceDuration: models.MustNewDuration(testDuration), + pollInterval: commonconfig.MustNewDuration(testInterval), + gatherDuration: commonconfig.MustNewDuration(testDuration), + traceDuration: commonconfig.MustNewDuration(testDuration), profileSize: utils.FileSize(testSize), memProfileRate: runtime.MemProfileRate, blockProfileRate: testRate, @@ -57,15 +57,15 @@ func (c mockConfig) ProfileRoot() string { return c.root } -func (c mockConfig) PollInterval() models.Duration { +func (c mockConfig) PollInterval() commonconfig.Duration { return *c.pollInterval } -func (c mockConfig) GatherDuration() models.Duration { +func (c mockConfig) GatherDuration() commonconfig.Duration { return *c.gatherDuration } -func (c mockConfig) GatherTraceDuration() models.Duration { +func (c mockConfig) GatherTraceDuration() commonconfig.Duration { return *c.traceDuration } diff --git a/core/services/ocr/database.go b/core/services/ocr/database.go index cec9596bb91..977c371c15d 100644 --- a/core/services/ocr/database.go +++ b/core/services/ocr/database.go @@ -207,6 +207,7 @@ func (d *db) StorePendingTransmission(ctx context.Context, k ocrtypes.ReportTime } func (d *db) PendingTransmissionsWithConfigDigest(ctx context.Context, cd ocrtypes.ConfigDigest) (map[ocrtypes.ReportTimestamp]ocrtypes.PendingTransmission, error) { + //nolint sqlclosecheck false positive rows, err := d.q.QueryContext(ctx, ` SELECT config_digest, @@ -317,6 +318,7 @@ LIMIT 1 if err != nil { return rr, errors.Wrap(err, "LoadLatestRoundRequested failed to query rows") } + defer func() { err = multierr.Combine(err, rows.Close()) }() for rows.Next() { var configDigest []byte @@ -337,7 +339,5 @@ LIMIT 1 return } - err = multierr.Combine(err, rows.Close()) - return } diff --git a/core/services/ocr/validate_test.go b/core/services/ocr/validate_test.go index 4d8a9ae26c8..e55c5d1a484 100644 --- a/core/services/ocr/validate_test.go +++ b/core/services/ocr/validate_test.go @@ -11,13 +11,13 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func TestValidateOracleSpec(t *testing.T) { @@ -359,7 +359,7 @@ answer1 [type=median index=0]; require.Contains(t, err.Error(), "data source timeout must be between 1s and 20s, but is currently 20m0s") }, overrides: func(c *chainlink.Config, s *chainlink.Secrets) { - c.OCR.ObservationTimeout = models.MustNewDuration(20 * time.Minute) + c.OCR.ObservationTimeout = commonconfig.MustNewDuration(20 * time.Minute) }, }, } diff --git a/core/services/ocr2/database.go b/core/services/ocr2/database.go index 5591f33fd40..1d449047578 100644 --- a/core/services/ocr2/database.go +++ b/core/services/ocr2/database.go @@ -279,7 +279,7 @@ func (d *db) PendingTransmissionsWithConfigDigest(ctx context.Context, cd ocrtyp FROM ocr2_pending_transmissions WHERE ocr2_oracle_spec_id = $1 AND config_digest = $2 ` - rows, err := d.q.QueryxContext(ctx, stmt, d.oracleSpecID, cd) + rows, err := d.q.QueryxContext(ctx, stmt, d.oracleSpecID, cd) //nolint sqlclosecheck false positive if err != nil { return nil, errors.Wrap(err, "PendingTransmissionsWithConfigDigest failed to query rows") } diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 3136de44b8f..37235437de1 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -190,6 +190,7 @@ type jobPipelineConfig interface { type mercuryConfig interface { Credentials(credName string) *models.MercuryCredentials Cache() coreconfig.MercuryCache + TLS() coreconfig.MercuryTLS } type thresholdConfig interface { @@ -227,7 +228,6 @@ func NewDelegate( ethKs keystore.Eth, relayers RelayGetter, mailMon *mailbox.Monitor, - eventBroadcaster pg.EventBroadcaster, ) *Delegate { return &Delegate{ db: db, diff --git a/core/services/ocr2/plugins/dkg/persistence/db.go b/core/services/ocr2/plugins/dkg/persistence/db.go index 304422ace2d..72997e28699 100644 --- a/core/services/ocr2/plugins/dkg/persistence/db.go +++ b/core/services/ocr2/plugins/dkg/persistence/db.go @@ -65,7 +65,7 @@ func NewShareDB(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, chainID *big.In q: pg.NewQ(db, lggr, cfg), lggr: lggr, chainID: chainID, - chainType: string(chainType), + chainType: chainType, } } diff --git a/core/services/ocr2/plugins/dkg/persistence/db_test.go b/core/services/ocr2/plugins/dkg/persistence/db_test.go index b4fa000cb99..53a5ae26758 100644 --- a/core/services/ocr2/plugins/dkg/persistence/db_test.go +++ b/core/services/ocr2/plugins/dkg/persistence/db_test.go @@ -55,6 +55,7 @@ func TestShareDB_WriteShareRecords(t *testing.T) { rows, err := db.Query(`SELECT COUNT(*) AS count FROM dkg_shares`) require.NoError(tt, err) + t.Cleanup(func() { assert.NoError(t, rows.Close()) }) var count int for rows.Next() { @@ -84,6 +85,7 @@ func TestShareDB_WriteShareRecords(t *testing.T) { rows, err := db.Query(`SELECT COUNT(*) AS count FROM dkg_shares`) require.NoError(tt, err) + t.Cleanup(func() { assert.NoError(t, rows.Close()) }) var count int for rows.Next() { @@ -122,6 +124,7 @@ func TestShareDB_WriteShareRecords(t *testing.T) { // no rows should have been inserted rows, err := db.Query(`SELECT COUNT(*) AS count FROM dkg_shares`) require.NoError(tt, err) + t.Cleanup(func() { assert.NoError(t, rows.Close()) }) var count int for rows.Next() { diff --git a/core/services/ocr2/plugins/functions/aggregation.go b/core/services/ocr2/plugins/functions/aggregation.go index 32a2509e70e..7ae00532f3f 100644 --- a/core/services/ocr2/plugins/functions/aggregation.go +++ b/core/services/ocr2/plugins/functions/aggregation.go @@ -104,7 +104,7 @@ func aggregateMode(items [][]byte) []byte { mostFrequent = item } } - return []byte(mostFrequent) + return mostFrequent } func aggregateMedian(items [][]byte) []byte { diff --git a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go index 9388b93329b..5ea1d3e4030 100644 --- a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go +++ b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go @@ -28,6 +28,7 @@ import ( confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" @@ -318,14 +319,14 @@ func StartNewNode( c.P2P.PeerID = ptr(p2pKey.PeerID()) c.P2P.V2.Enabled = ptr(true) - c.P2P.V2.DeltaDial = models.MustNewDuration(500 * time.Millisecond) - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) + c.P2P.V2.DeltaDial = commonconfig.MustNewDuration(500 * time.Millisecond) + c.P2P.V2.DeltaReconcile = commonconfig.MustNewDuration(5 * time.Second) c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", port)} if len(p2pV2Bootstrappers) > 0 { c.P2P.V2.DefaultBootstrappers = &p2pV2Bootstrappers } - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) c.EVM[0].Transactions.ForwardersEnabled = ptr(false) c.EVM[0].GasEstimator.LimitDefault = ptr(maxGas) c.EVM[0].GasEstimator.Mode = ptr("FixedPrice") diff --git a/core/services/ocr2/plugins/mercury/helpers_test.go b/core/services/ocr2/plugins/mercury/helpers_test.go index 68fb27fa82e..473db53bc6f 100644 --- a/core/services/ocr2/plugins/mercury/helpers_test.go +++ b/core/services/ocr2/plugins/mercury/helpers_test.go @@ -25,6 +25,7 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" @@ -40,7 +41,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) var _ pb.MercuryServer = &mercuryServer{} @@ -199,8 +199,8 @@ func setupNode( c.P2P.V2.Enabled = ptr(true) c.P2P.V2.AnnounceAddresses = &p2paddresses c.P2P.V2.ListenAddresses = &p2paddresses - c.P2P.V2.DeltaDial = models.MustNewDuration(500 * time.Millisecond) - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) + c.P2P.V2.DeltaDial = commonconfig.MustNewDuration(500 * time.Millisecond) + c.P2P.V2.DeltaReconcile = commonconfig.MustNewDuration(5 * time.Second) }) lggr, observedLogs := logger.TestLoggerObserved(t, zapcore.DebugLevel) diff --git a/core/services/ocr2/plugins/mercury/integration_test.go b/core/services/ocr2/plugins/mercury/integration_test.go index 51f9eaa6683..6d847098f94 100644 --- a/core/services/ocr2/plugins/mercury/integration_test.go +++ b/core/services/ocr2/plugins/mercury/integration_test.go @@ -357,7 +357,7 @@ func TestIntegration_MercuryV1(t *testing.T) { err = reportcodecv1.ReportTypes.UnpackIntoMap(reportElems, report.([]byte)) require.NoError(t, err) - feedID := ([32]byte)(reportElems["feedId"].([32]uint8)) + feedID := reportElems["feedId"].([32]uint8) feed, exists := feedM[feedID] require.True(t, exists) @@ -421,7 +421,7 @@ func TestIntegration_MercuryV1(t *testing.T) { err = reportcodecv1.ReportTypes.UnpackIntoMap(reportElems, report.([]byte)) require.NoError(t, err) - feedID := ([32]byte)(reportElems["feedId"].([32]uint8)) + feedID := reportElems["feedId"].([32]uint8) feed, exists := feedM[feedID] require.True(t, exists) @@ -691,7 +691,7 @@ func TestIntegration_MercuryV2(t *testing.T) { err = reportcodecv2.ReportTypes.UnpackIntoMap(reportElems, report.([]byte)) require.NoError(t, err) - feedID := ([32]byte)(reportElems["feedId"].([32]uint8)) + feedID := reportElems["feedId"].([32]uint8) feed, exists := feedM[feedID] require.True(t, exists) @@ -971,7 +971,7 @@ func TestIntegration_MercuryV3(t *testing.T) { err = reportcodecv3.ReportTypes.UnpackIntoMap(reportElems, report.([]byte)) require.NoError(t, err) - feedID := ([32]byte)(reportElems["feedId"].([32]uint8)) + feedID := reportElems["feedId"].([32]uint8) feed, exists := feedM[feedID] require.True(t, exists) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go index 81f51311d44..f2c58fd30c1 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go @@ -176,8 +176,8 @@ func (b *logEventBuffer) enqueue(id *big.Int, logs ...logpoller.Log) int { lggr := b.lggr.With("id", id.String()) - maxBlockLogs := int(b.maxBlockLogs) - maxUpkeepLogs := int(b.maxUpkeepLogsPerBlock) + maxBlockLogs := b.maxBlockLogs + maxUpkeepLogs := b.maxUpkeepLogsPerBlock latestBlock := b.latestBlockSeen() added, dropped := 0, 0 diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/request.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/request.go index f69fbb35e35..202661145bf 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/request.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/request.go @@ -81,7 +81,7 @@ func (c *client) DoRequest(ctx context.Context, streamsLookup *mercury.StreamsLo retryable = retryable && m.Retryable allSuccess = false if m.State != encoding.NoPipelineError { - state = encoding.PipelineExecutionState(m.State) + state = m.State } continue } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache.go index 99e1f1dc164..2c0055482ed 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache.go @@ -28,7 +28,7 @@ func (c *transmitEventCache) get(block ocr2keepers.BlockNumber, logID string) (o c.lock.RLock() defer c.lock.RUnlock() - i := int64(block) % int64(c.cap) + i := int64(block) % c.cap b := c.buffer[i] if b.block != block { return ocr2keepers.TransmitEvent{}, false @@ -45,7 +45,7 @@ func (c *transmitEventCache) add(logID string, e ocr2keepers.TransmitEvent) { c.lock.Lock() defer c.lock.Unlock() - i := int64(e.TransmitBlock) % int64(c.cap) + i := int64(e.TransmitBlock) % c.cap b := c.buffer[i] isBlockEmpty := len(b.records) == 0 isNewBlock := b.block < e.TransmitBlock diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index d0a93f77631..56467c60abb 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -32,6 +32,7 @@ import ( ocrTypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-automation/pkg/v2/config" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -123,8 +124,8 @@ func setupNode( c.P2P.PeerID = ptr(p2pKey.PeerID()) c.P2P.V2.Enabled = ptr(true) - c.P2P.V2.DeltaDial = models.MustNewDuration(500 * time.Millisecond) - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) + c.P2P.V2.DeltaDial = commonconfig.MustNewDuration(500 * time.Millisecond) + c.P2P.V2.DeltaReconcile = commonconfig.MustNewDuration(5 * time.Second) c.P2P.V2.AnnounceAddresses = &p2paddresses c.P2P.V2.ListenAddresses = &p2paddresses if len(p2pV2Bootstrappers) > 0 { diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go index a25fcca9fec..88d6544d8c4 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go @@ -398,7 +398,7 @@ func (c *coordinator) ReportBlocks( // TODO BELOW: Write tests for the new blockhash retrieval. // Obtain recent blockhashes, ordered by ascending block height. - for i := recentBlockHashesStartHeight; i <= uint64(currentHeight); i++ { + for i := recentBlockHashesStartHeight; i <= currentHeight; i++ { recentBlockHashes = append(recentBlockHashes, blockhashesMapping[i]) } @@ -518,7 +518,7 @@ func (c *coordinator) getBlockhashesMappingFromRequests( } // Get a mapping of block numbers to block hashes. - blockhashesMapping, err = c.getBlockhashesMapping(ctx, append(requestedBlockNumbers, uint64(currentHeight), recentBlockHashesStartHeight)) + blockhashesMapping, err = c.getBlockhashesMapping(ctx, append(requestedBlockNumbers, currentHeight, recentBlockHashesStartHeight)) if err != nil { err = errors.Wrap(err, "get blockhashes for ReportBlocks") } diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go index 9c3eb087985..096589b2053 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go @@ -271,7 +271,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.NoError(t, err) assert.Len(t, blocks, 1) assert.Len(t, callbacks, 0) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -333,7 +333,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.False(t, b.ShouldStore) } assert.Len(t, callbacks, 3) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -400,7 +400,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.NoError(t, err) assert.Len(t, blocks, 0) assert.Len(t, callbacks, 0) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -471,7 +471,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.NoError(t, err) assert.Len(t, blocks, 0) assert.Len(t, callbacks, 0) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -533,7 +533,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.NoError(t, err) assert.Len(t, blocks, 0) assert.Len(t, callbacks, 0) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -635,7 +635,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.NoError(t, err) assert.Len(t, blocks, 0) assert.Len(t, callbacks, 0) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -705,7 +705,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.True(t, b.ShouldStore) } assert.Len(t, callbacks, 0) - assert.Equal(t, uint64(latestHeadNumber-blockhashLookback+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-blockhashLookback+1, recentHeightStart) assert.Len(t, recentBlocks, int(blockhashLookback)) }) @@ -772,7 +772,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.True(t, b.ShouldStore) } assert.Len(t, callbacks, 2) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -835,7 +835,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.NoError(t, err) assert.Len(t, blocks, 1) assert.Len(t, callbacks, 1) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -901,7 +901,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.NoError(t, err) assert.Len(t, blocks, 2) assert.Len(t, callbacks, 2) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -956,7 +956,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { ) assert.NoError(t, err) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Equal(t, common.HexToHash(fmt.Sprintf("0x00%d", 1)), recentBlocks[0]) assert.Equal(t, common.HexToHash(fmt.Sprintf("0x00%d", lookbackBlocks)), recentBlocks[len(recentBlocks)-1]) assert.Len(t, recentBlocks, int(lookbackBlocks)) @@ -1013,7 +1013,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { ) assert.NoError(t, err) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Equal(t, common.HexToHash(fmt.Sprintf("0x00%d", 1)), recentBlocks[0]) assert.Equal(t, common.HexToHash(fmt.Sprintf("0x00%d", lookbackBlocks)), recentBlocks[len(recentBlocks)-1]) assert.Len(t, recentBlocks, int(lookbackBlocks)) @@ -1035,7 +1035,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { lp.On("LatestBlock", mock.Anything). Return(logpoller.LogPollerBlock{BlockNumber: int64(latestHeadNumber)}, nil) - lp.On("GetBlocksRange", mock.Anything, append(requestedBlocks, uint64(latestHeadNumber-lookbackBlocks+1), uint64(latestHeadNumber)), mock.Anything). + lp.On("GetBlocksRange", mock.Anything, append(requestedBlocks, latestHeadNumber-lookbackBlocks+1, latestHeadNumber), mock.Anything). Return(nil, errors.New("GetBlocks error")) lp.On( "LogsWithSigs", diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/ocr_cache_test.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/ocr_cache_test.go index 6a4b97b9f0e..57aaf1c5e03 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/ocr_cache_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/ocr_cache_test.go @@ -11,7 +11,7 @@ import ( func TestNewCache(t *testing.T) { b := NewBlockCache[int](time.Second) - assert.Equal(t, time.Second, time.Duration(b.evictionWindow), "must set correct blockEvictionWindow") + assert.Equal(t, time.Second, b.evictionWindow, "must set correct blockEvictionWindow") } func TestCache(t *testing.T) { @@ -30,7 +30,7 @@ func TestCache(t *testing.T) { {Key: common.HexToHash("0x4"), Value: 5}, } - c := NewBlockCache[int](time.Second * 100) + c := NewBlockCache[int](100 * time.Second) // Populate cache with ordered items. for i, test := range tests { @@ -79,7 +79,7 @@ func TestCache(t *testing.T) { {Key: common.HexToHash("0x1"), Value: 5}, } - c := NewBlockCache[int](time.Duration(time.Second * 100)) + c := NewBlockCache[int](100 * time.Second) // Populate cache with items. for i, test := range tests { @@ -119,7 +119,7 @@ func TestCache(t *testing.T) { {Key: common.HexToHash("0x0"), Value: 5}, } - c := NewBlockCache[int](time.Duration(time.Second * 100)) + c := NewBlockCache[int](100 * time.Second) // Populate cache with items. for i, test := range tests { diff --git a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go index 55517d5719d..4a01ee7904f 100644 --- a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go @@ -30,6 +30,7 @@ import ( "github.com/smartcontractkit/chainlink-vrf/ocr2vrf" ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" @@ -55,7 +56,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) type ocr2vrfUniverse struct { @@ -234,8 +234,8 @@ func setupNodeOCR2( c.P2P.PeerID = ptr(p2pKey.PeerID()) c.P2P.V2.Enabled = ptr(true) - c.P2P.V2.DeltaDial = models.MustNewDuration(500 * time.Millisecond) - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) + c.P2P.V2.DeltaDial = commonconfig.MustNewDuration(500 * time.Millisecond) + c.P2P.V2.DeltaReconcile = commonconfig.MustNewDuration(5 * time.Second) c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", port)} if len(p2pV2Bootstrappers) > 0 { c.P2P.V2.DefaultBootstrappers = &p2pV2Bootstrappers @@ -244,10 +244,10 @@ func setupNodeOCR2( c.OCR.Enabled = ptr(false) c.OCR2.Enabled = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(500 * time.Millisecond) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(500 * time.Millisecond) c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](3_500_000) c.EVM[0].Transactions.ForwardersEnabled = &useForwarders - c.OCR2.ContractPollInterval = models.MustNewDuration(10 * time.Second) + c.OCR2.ContractPollInterval = commonconfig.MustNewDuration(10 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, b, p2pKey) diff --git a/core/services/ocr2/plugins/promwrapper/plugin.go b/core/services/ocr2/plugins/promwrapper/plugin.go index a409b5ba86c..58d8e171f39 100644 --- a/core/services/ocr2/plugins/promwrapper/plugin.go +++ b/core/services/ocr2/plugins/promwrapper/plugin.go @@ -39,7 +39,7 @@ var ( labels = []string{"chainType", "chainID", "plugin", "oracleID", "configDigest"} getLabelsValues = func(p *promPlugin, t types.ReportTimestamp) []string { return []string{ - string(p.chainType), // chainType + p.chainType, // chainType p.chainID.String(), // chainID p.name, // plugin p.oracleID, // oracleID @@ -333,11 +333,11 @@ func (p *promPlugin) Close() error { defer func() { duration := float64(time.Now().UTC().Sub(start)) labelValues := []string{ - string(p.chainType), // chainType - p.chainID.String(), // chainID - p.name, // plugin - p.oracleID, // oracleID - p.configDigest, // configDigest + p.chainType, // chainType + p.chainID.String(), // chainID + p.name, // plugin + p.oracleID, // oracleID + p.configDigest, // configDigest } p.prometheusBackend.SetCloseDuration(labelValues, duration) }() diff --git a/core/services/ocr2/plugins/s4/plugin.go b/core/services/ocr2/plugins/s4/plugin.go index 677743c091d..2b55ebf3cc5 100644 --- a/core/services/ocr2/plugins/s4/plugin.go +++ b/core/services/ocr2/plugins/s4/plugin.go @@ -167,9 +167,9 @@ func (c *plugin) Observation(ctx context.Context, ts types.ReportTimestamp, quer if !sr.Confirmed { continue } - k := key{address: sr.Address.String(), slotID: uint(sr.SlotId)} + k := key{address: sr.Address.String(), slotID: sr.SlotId} if _, ok := snapshotVersionsMap[k]; ok { - toBeAdded = append(toBeAdded, rkey{address: sr.Address, slotID: uint(sr.SlotId)}) + toBeAdded = append(toBeAdded, rkey{address: sr.Address, slotID: sr.SlotId}) if len(toBeAdded) == maxRemainingRows { break } @@ -332,7 +332,7 @@ func snapshotToVersionMap(rows []*s4.SnapshotRow) map[key]uint64 { m := make(map[key]uint64) for _, row := range rows { if row.Confirmed { - m[key{address: row.Address.String(), slotID: uint(row.SlotId)}] = row.Version + m[key{address: row.Address.String(), slotID: row.SlotId}] = row.Version } } return m diff --git a/core/services/ocr2/plugins/s4/plugin_test.go b/core/services/ocr2/plugins/s4/plugin_test.go index e0aa84183e1..b53ab40bfcb 100644 --- a/core/services/ocr2/plugins/s4/plugin_test.go +++ b/core/services/ocr2/plugins/s4/plugin_test.go @@ -322,7 +322,7 @@ func TestPlugin_Query(t *testing.T) { assert.Len(t, qq.Rows, 16) for _, r := range qq.Rows { thisAddress := s4.UnmarshalAddress(r.Address) - assert.True(t, ar.Contains((*big.Big)(thisAddress))) + assert.True(t, ar.Contains(thisAddress)) } ar.Advance() diff --git a/core/services/ocr2/validate/validate_test.go b/core/services/ocr2/validate/validate_test.go index b03f08f6b08..52dbe5f0042 100644 --- a/core/services/ocr2/validate/validate_test.go +++ b/core/services/ocr2/validate/validate_test.go @@ -11,13 +11,13 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" medianconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/median/config" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func TestValidateOracleSpec(t *testing.T) { @@ -308,7 +308,7 @@ chainID = 1337 require.Contains(t, err.Error(), "database timeout must be between 100ms and 10s, but is currently 20m0s") }, overrides: func(c *chainlink.Config, s *chainlink.Secrets) { - c.OCR2.DatabaseTimeout = models.MustNewDuration(20 * time.Minute) + c.OCR2.DatabaseTimeout = commonconfig.MustNewDuration(20 * time.Minute) }, }, { diff --git a/core/services/ocrcommon/discoverer_database.go b/core/services/ocrcommon/discoverer_database.go index 6468a910a65..9413b11ad07 100644 --- a/core/services/ocrcommon/discoverer_database.go +++ b/core/services/ocrcommon/discoverer_database.go @@ -39,27 +39,25 @@ updated_at = EXCLUDED.updated_at // ReadAnnouncements returns one serialized announcement (if available) for each of the peerIDs in the form of a map // keyed by each announcement's corresponding peer ID. -func (d *DiscovererDatabase) ReadAnnouncements(ctx context.Context, peerIDs []string) (map[string][]byte, error) { +func (d *DiscovererDatabase) ReadAnnouncements(ctx context.Context, peerIDs []string) (results map[string][]byte, err error) { rows, err := d.db.QueryContext(ctx, ` SELECT remote_peer_id, ann FROM ocr_discoverer_announcements WHERE remote_peer_id = ANY($1) AND local_peer_id = $2`, pq.Array(peerIDs), d.peerID) if err != nil { return nil, errors.Wrap(err, "DiscovererDatabase failed to ReadAnnouncements") } - results := make(map[string][]byte) + defer func() { err = multierr.Combine(err, rows.Close()) }() + results = make(map[string][]byte) for rows.Next() { var peerID string var ann []byte - err := rows.Scan(&peerID, &ann) + err = rows.Scan(&peerID, &ann) if err != nil { - return nil, multierr.Combine(err, rows.Close()) + return } results[peerID] = ann } - if err := rows.Err(); err != nil { - return nil, err - } - if err := rows.Close(); err != nil { - return nil, errors.WithStack(err) + if err = rows.Err(); err != nil { + return } return results, nil } diff --git a/core/services/ocrcommon/peer_wrapper_test.go b/core/services/ocrcommon/peer_wrapper_test.go index 278e0684fd2..f46b2af27c5 100644 --- a/core/services/ocrcommon/peer_wrapper_test.go +++ b/core/services/ocrcommon/peer_wrapper_test.go @@ -9,6 +9,7 @@ import ( ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -18,7 +19,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func Test_SingletonPeerWrapper_Start(t *testing.T) { @@ -123,8 +123,8 @@ func Test_SingletonPeerWrapper_Close(t *testing.T) { cfg = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.P2P.V2.Enabled = ptr(true) c.P2P.PeerID = ptr(k.PeerID()) - c.P2P.V2.DeltaDial = models.MustNewDuration(100 * time.Millisecond) - c.P2P.V2.DeltaReconcile = models.MustNewDuration(1 * time.Second) + c.P2P.V2.DeltaDial = commonconfig.MustNewDuration(100 * time.Millisecond) + c.P2P.V2.DeltaReconcile = commonconfig.MustNewDuration(1 * time.Second) p2paddresses := []string{ "127.0.0.1:17193", diff --git a/core/services/ocrcommon/run_saver.go b/core/services/ocrcommon/run_saver.go index b1a0fc7b141..6d85aa857a4 100644 --- a/core/services/ocrcommon/run_saver.go +++ b/core/services/ocrcommon/run_saver.go @@ -5,15 +5,20 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" ) +type Runner interface { + InsertFinishedRun(run *pipeline.Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) error +} + type RunResultSaver struct { services.StateMachine maxSuccessfulRuns uint64 runResults chan *pipeline.Run - pipelineRunner pipeline.Runner + pipelineRunner Runner done chan struct{} logger logger.Logger } @@ -24,7 +29,7 @@ func (r *RunResultSaver) HealthReport() map[string]error { func (r *RunResultSaver) Name() string { return r.logger.Name() } -func NewResultRunSaver(pipelineRunner pipeline.Runner, +func NewResultRunSaver(pipelineRunner Runner, logger logger.Logger, maxSuccessfulRuns uint64, resultsWriteDepth uint64, ) *RunResultSaver { return &RunResultSaver{ diff --git a/core/services/pg/channels.go b/core/services/pg/channels.go deleted file mode 100644 index aed132a7f2c..00000000000 --- a/core/services/pg/channels.go +++ /dev/null @@ -1,4 +0,0 @@ -package pg - -// Postgres channel to listen for new evm.txes -const ChannelInsertOnEVMLogs = "evm.insert_on_logs" diff --git a/core/services/pg/event_broadcaster.go b/core/services/pg/event_broadcaster.go deleted file mode 100644 index a575ab33489..00000000000 --- a/core/services/pg/event_broadcaster.go +++ /dev/null @@ -1,346 +0,0 @@ -package pg - -import ( - "context" - "database/sql" - "net/url" - "sync" - "time" - - "github.com/google/uuid" - "github.com/lib/pq" - "github.com/pkg/errors" - - "github.com/smartcontractkit/chainlink-common/pkg/services" - commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" - - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/static" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -//go:generate mockery --quiet --name EventBroadcaster --output ./mocks/ --case=underscore -//go:generate mockery --quiet --name Subscription --output ./mocks/ --case=underscore - -// EventBroadcaster opaquely manages a collection of Postgres event listeners -// and broadcasts events to subscribers (with an optional payload filter). -type EventBroadcaster interface { - services.Service - Subscribe(channel, payloadFilter string) (Subscription, error) - Notify(channel string, payload string) error -} - -type eventBroadcaster struct { - services.StateMachine - uri string - minReconnectInterval time.Duration - maxReconnectDuration time.Duration - db *sql.DB - listener *pq.Listener - subscriptions map[string]map[Subscription]struct{} - subscriptionsMu sync.RWMutex - chStop chan struct{} - chDone chan struct{} - lggr logger.Logger -} - -var _ EventBroadcaster = (*eventBroadcaster)(nil) - -type Event struct { - Channel string - Payload string -} - -func NewEventBroadcaster(uri url.URL, minReconnectInterval time.Duration, maxReconnectDuration time.Duration, lggr logger.Logger, appID uuid.UUID) *eventBroadcaster { - if minReconnectInterval == time.Duration(0) { - minReconnectInterval = 1 * time.Second - } - if maxReconnectDuration == time.Duration(0) { - maxReconnectDuration = 1 * time.Minute - } - static.SetConsumerName(&uri, "EventBroadcaster", &appID) - return &eventBroadcaster{ - uri: uri.String(), - minReconnectInterval: minReconnectInterval, - maxReconnectDuration: maxReconnectDuration, - subscriptions: make(map[string]map[Subscription]struct{}), - chStop: make(chan struct{}), - chDone: make(chan struct{}), - lggr: lggr.Named("EventBroadcaster"), - } -} - -// Start starts EventBroadcaster. -func (b *eventBroadcaster) Start(context.Context) error { - return b.StartOnce("Postgres event broadcaster", func() (err error) { - // Explicitly using the lib/pq for notifications so we use the postgres driverName - // and NOT pgx. - db, err := sql.Open("postgres", b.uri) - if err != nil { - return err - } - b.db = db - b.listener = pq.NewListener(b.uri, b.minReconnectInterval, b.maxReconnectDuration, func(ev pq.ListenerEventType, err error) { - // sanity check since these can still be called after closing the listener - select { - case <-b.chStop: - return - default: - } - // These are always connection-related events, and the pq library - // automatically handles reconnecting to the DB. Therefore, we do not - // need to terminate, but rather simply log these events for node - // operators' sanity. - switch ev { - case pq.ListenerEventConnected: - b.lggr.Debug("Postgres event broadcaster: connected") - case pq.ListenerEventDisconnected: - b.lggr.Warnw("Postgres event broadcaster: disconnected, trying to reconnect...", "err", err) - case pq.ListenerEventReconnected: - b.lggr.Debug("Postgres event broadcaster: reconnected") - case pq.ListenerEventConnectionAttemptFailed: - b.lggr.Warnw("Postgres event broadcaster: reconnect attempt failed, trying again...", "err", err) - } - }) - - go b.runLoop() - return nil - }) -} - -// Stop permanently destroys the EventBroadcaster. Calling this does not clean -// up any outstanding subscriptions. Subscribers must explicitly call `.Close()` -// or they will leak goroutines. -func (b *eventBroadcaster) Close() error { - return b.StopOnce("Postgres event broadcaster", func() (err error) { - b.subscriptionsMu.RLock() - defer b.subscriptionsMu.RUnlock() - b.subscriptions = nil - - err = services.CloseAll(b.db, b.listener) - close(b.chStop) - <-b.chDone - return err - }) -} - -func (b *eventBroadcaster) Name() string { - return b.lggr.Name() -} - -func (b *eventBroadcaster) HealthReport() map[string]error { - return map[string]error{b.Name(): b.Healthy()} -} - -func (b *eventBroadcaster) runLoop() { - defer close(b.chDone) - for { - select { - case <-b.chStop: - return - - case notification, open := <-b.listener.NotificationChannel(): - if !open { - return - } else if notification == nil { - continue - } - b.lggr.Debugw("Postgres event broadcaster: received notification", - "channel", notification.Channel, - "payload", notification.Extra, - ) - b.broadcast(notification) - } - } -} - -func (b *eventBroadcaster) Notify(channel string, payload string) error { - _, err := b.db.Exec(`SELECT pg_notify($1, $2)`, channel, payload) - return errors.Wrap(err, "Postgres event broadcaster could not notify") -} - -func (b *eventBroadcaster) Subscribe(channel, payloadFilter string) (Subscription, error) { - b.subscriptionsMu.Lock() - defer b.subscriptionsMu.Unlock() - - if _, exists := b.subscriptions[channel]; !exists { - err := b.listener.Listen(channel) - if err != nil { - return nil, errors.Wrap(err, "Postgres event broadcaster could not subscribe") - } - b.subscriptions[channel] = make(map[Subscription]struct{}) - } - - sub := &subscription{ - channel: channel, - payloadFilter: payloadFilter, - eventBroadcaster: b, - queue: utils.NewBoundedQueue[Event](1000), - chEvents: make(chan Event), - chDone: make(chan struct{}), - lggr: logger.Sugared(b.lggr), - } - sub.processQueueWorker = commonutils.NewSleeperTask( - commonutils.SleeperFuncTask(sub.processQueue, "SubscriptionQueueProcessor"), - ) - b.subscriptions[channel][sub] = struct{}{} - return sub, nil -} - -func (b *eventBroadcaster) removeSubscription(sub Subscription) { - b.subscriptionsMu.Lock() - defer b.subscriptionsMu.Unlock() - - // The following conditions can occur on shutdown when .Stop() is called - // before one or more subscriptions' .Close() methods are called - if b.subscriptions == nil { - return - } - subs, exists := b.subscriptions[sub.ChannelName()] - if !exists || subs == nil { - return - } - - delete(b.subscriptions[sub.ChannelName()], sub) - if len(b.subscriptions[sub.ChannelName()]) == 0 { - err := b.listener.Unlisten(sub.ChannelName()) - if err != nil { - b.lggr.Errorw("Postgres event broadcaster: failed to unsubscribe", "err", err) - } - delete(b.subscriptions, sub.ChannelName()) - } -} - -func (b *eventBroadcaster) broadcast(notification *pq.Notification) { - b.subscriptionsMu.RLock() - defer b.subscriptionsMu.RUnlock() - - event := Event{ - Channel: notification.Channel, - Payload: notification.Extra, - } - - var wg sync.WaitGroup - for sub := range b.subscriptions[event.Channel] { - if sub.InterestedIn(event) { - wg.Add(1) - go func(sub Subscription) { - defer wg.Done() - sub.Send(event) - }(sub) - } - } - wg.Wait() -} - -// Subscription represents a subscription to a Postgres event channel -type Subscription interface { - Events() <-chan Event - Close() - - ChannelName() string - InterestedIn(event Event) bool - Send(event Event) -} - -type subscription struct { - channel string - payloadFilter string - eventBroadcaster *eventBroadcaster - queue *utils.BoundedQueue[Event] - processQueueWorker *commonutils.SleeperTask - chEvents chan Event - chDone chan struct{} - lggr logger.SugaredLogger -} - -var _ Subscription = (*subscription)(nil) - -func (sub *subscription) InterestedIn(event Event) bool { - return sub.payloadFilter == event.Payload || sub.payloadFilter == "" -} - -func (sub *subscription) Send(event Event) { - sub.queue.Add(event) - sub.processQueueWorker.WakeUpIfStarted() -} - -const broadcastTimeout = 10 * time.Second - -func (sub *subscription) processQueue() { - deadline := time.Now().Add(broadcastTimeout) - for !sub.queue.Empty() { - event := sub.queue.Take() - select { - case sub.chEvents <- event: - case <-time.After(time.Until(deadline)): - sub.lggr.Warnf("Postgres event broadcaster: SLOW processQueue(), timed out after %s", broadcastTimeout) - return - case <-sub.chDone: - sub.lggr.Debugw("Postgres event broadcaster: request cancelled during processQueue()") - return - } - } -} - -func (sub *subscription) Events() <-chan Event { - return sub.chEvents -} - -func (sub *subscription) ChannelName() string { - return sub.channel -} - -func (sub *subscription) Close() { - sub.eventBroadcaster.removeSubscription(sub) - // Close chDone before stopping the SleeperTask to avoid deadlocks - close(sub.chDone) - err := sub.processQueueWorker.Stop() - if err != nil { - sub.lggr.Errorw("THIS NEVER RETURNS AN ERROR", "err", err) - } - close(sub.chEvents) -} - -// NullEventBroadcaster implements null pattern for event broadcaster -type NullEventBroadcaster struct { - Sub *NullSubscription -} - -func NewNullEventBroadcaster() *NullEventBroadcaster { - sub := &NullSubscription{make(chan (Event))} - return &NullEventBroadcaster{sub} -} - -var _ EventBroadcaster = &NullEventBroadcaster{} - -func (*NullEventBroadcaster) Name() string { return "NullEventBroadcaster" } - -// Start does no-op. -func (*NullEventBroadcaster) Start(context.Context) error { return nil } - -// Close does no-op. -func (*NullEventBroadcaster) Close() error { return nil } - -// Ready does no-op. -func (*NullEventBroadcaster) Ready() error { return nil } - -// HealthReport does no-op -func (*NullEventBroadcaster) HealthReport() map[string]error { return map[string]error{} } - -func (ne *NullEventBroadcaster) Subscribe(channel, payloadFilter string) (Subscription, error) { - return ne.Sub, nil -} -func (*NullEventBroadcaster) Notify(channel string, payload string) error { return nil } - -var _ Subscription = &NullSubscription{} - -type NullSubscription struct { - Ch chan (Event) -} - -func (ns *NullSubscription) Events() <-chan Event { return ns.Ch } -func (ns *NullSubscription) Close() {} -func (ns *NullSubscription) ChannelName() string { return "" } -func (ns *NullSubscription) InterestedIn(event Event) bool { return false } -func (ns *NullSubscription) Send(event Event) {} diff --git a/core/services/pg/event_broadcaster_test.go b/core/services/pg/event_broadcaster_test.go deleted file mode 100644 index e8a4a1086db..00000000000 --- a/core/services/pg/event_broadcaster_test.go +++ /dev/null @@ -1,239 +0,0 @@ -package pg_test - -import ( - "sync" - "testing" - "time" - - "github.com/google/uuid" - "github.com/onsi/gomega" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" -) - -func TestEventBroadcaster(t *testing.T) { - config, _ := heavyweight.FullTestDBNoFixturesV2(t, nil) - - eventBroadcaster := pg.NewEventBroadcaster(config.Database().URL(), 0, 0, logger.TestLogger(t), uuid.New()) - servicetest.Run(t, eventBroadcaster) - - t.Run("doesn't broadcast unrelated events (no payload filter)", func(t *testing.T) { - sub, err := eventBroadcaster.Subscribe("foo", "") - require.NoError(t, err) - defer sub.Close() - - go func() { - err := eventBroadcaster.Notify("bar", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("fooo", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("fo", "123") - require.NoError(t, err) - }() - - ch := sub.Events() - gomega.NewWithT(t).Consistently(ch).ShouldNot(gomega.Receive()) - }) - - t.Run("doesn't broadcast unrelated events (with payload filter)", func(t *testing.T) { - sub, err := eventBroadcaster.Subscribe("foo", "123") - require.NoError(t, err) - defer sub.Close() - - go func() { - err := eventBroadcaster.Notify("foo", "asdf") - require.NoError(t, err) - err = eventBroadcaster.Notify("bar", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("fooo", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("fo", "123") - require.NoError(t, err) - }() - - ch := sub.Events() - gomega.NewWithT(t).Consistently(ch).ShouldNot(gomega.Receive()) - }) - - t.Run("does broadcast related events (no payload filter)", func(t *testing.T) { - sub, err := eventBroadcaster.Subscribe("foo", "") - require.NoError(t, err) - defer sub.Close() - - go func() { - err := eventBroadcaster.Notify("foo", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("foo", "aslkdjslkdfj") - require.NoError(t, err) - err = eventBroadcaster.Notify("foo", "true") - require.NoError(t, err) - }() - - ch := sub.Events() - gomega.NewWithT(t).Eventually(ch).Should(gomega.Receive()) - gomega.NewWithT(t).Eventually(ch).Should(gomega.Receive()) - gomega.NewWithT(t).Eventually(ch).Should(gomega.Receive()) - }) - - t.Run("does broadcast related events (with payload filter)", func(t *testing.T) { - sub, err := eventBroadcaster.Subscribe("foo", "123") - require.NoError(t, err) - defer sub.Close() - - go func() { - err := eventBroadcaster.Notify("foo", "asdf") - require.NoError(t, err) - err = eventBroadcaster.Notify("foo", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("foo", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("foo", "true") - require.NoError(t, err) - }() - - ch := sub.Events() - gomega.NewWithT(t).Eventually(ch).Should(gomega.Receive()) - gomega.NewWithT(t).Eventually(ch).Should(gomega.Receive()) - gomega.NewWithT(t).Consistently(ch).ShouldNot(gomega.Receive()) - }) - - t.Run("broadcasts to the correct subscribers", func(t *testing.T) { - sub1, err := eventBroadcaster.Subscribe("foo", "") - require.NoError(t, err) - defer sub1.Close() - - sub2, err := eventBroadcaster.Subscribe("foo", "123") - require.NoError(t, err) - defer sub2.Close() - - sub3, err := eventBroadcaster.Subscribe("bar", "") - require.NoError(t, err) - defer sub3.Close() - - sub4, err := eventBroadcaster.Subscribe("bar", "asdf") - require.NoError(t, err) - defer sub4.Close() - - var wg sync.WaitGroup - wg.Add(5) - - recv := func(ch <-chan pg.Event) pg.Event { - select { - case e := <-ch: - return e - case <-time.After(5 * time.Second): - t.Fatal("did not receive") - } - return pg.Event{} - } - - go func() { - defer wg.Done() - err := eventBroadcaster.Notify("foo", "asdf") - require.NoError(t, err) - err = eventBroadcaster.Notify("foo", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("foo", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("foo", "true") - require.NoError(t, err) - - err = eventBroadcaster.Notify("bar", "asdf") - require.NoError(t, err) - err = eventBroadcaster.Notify("bar", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("bar", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("bar", "true") - require.NoError(t, err) - }() - - go func() { - defer wg.Done() - e := recv(sub1.Events()) - require.Equal(t, "foo", e.Channel) - require.Equal(t, "asdf", e.Payload) - - e = recv(sub1.Events()) - require.Equal(t, "foo", e.Channel) - require.Equal(t, "123", e.Payload) - - e = recv(sub1.Events()) - require.Equal(t, "foo", e.Channel) - require.Equal(t, "123", e.Payload) - - e = recv(sub1.Events()) - require.Equal(t, "foo", e.Channel) - require.Equal(t, "true", e.Payload) - - gomega.NewWithT(t).Consistently(sub1.Events()).ShouldNot(gomega.Receive()) - }() - - go func() { - defer wg.Done() - e := recv(sub2.Events()) - require.Equal(t, "foo", e.Channel) - require.Equal(t, "123", e.Payload) - - e = recv(sub2.Events()) - require.Equal(t, "foo", e.Channel) - require.Equal(t, "123", e.Payload) - - gomega.NewWithT(t).Consistently(sub2.Events()).ShouldNot(gomega.Receive()) - }() - - go func() { - defer wg.Done() - e := recv(sub3.Events()) - require.Equal(t, "bar", e.Channel) - require.Equal(t, "asdf", e.Payload) - - e = recv(sub3.Events()) - require.Equal(t, "bar", e.Channel) - require.Equal(t, "123", e.Payload) - - e = recv(sub3.Events()) - require.Equal(t, "bar", e.Channel) - require.Equal(t, "123", e.Payload) - - e = recv(sub3.Events()) - require.Equal(t, "bar", e.Channel) - require.Equal(t, "true", e.Payload) - - gomega.NewWithT(t).Consistently(sub3.Events()).ShouldNot(gomega.Receive()) - }() - - go func() { - defer wg.Done() - e := recv(sub4.Events()) - require.Equal(t, "bar", e.Channel) - require.Equal(t, "asdf", e.Payload) - - gomega.NewWithT(t).Consistently(sub4.Events()).ShouldNot(gomega.Receive()) - }() - - wg.Wait() - }) - - t.Run("closes events channel on subscription close", func(t *testing.T) { - sub, err := eventBroadcaster.Subscribe("foo", "") - require.NoError(t, err) - - chEvents := sub.Events() - - sub.Close() - - select { - case _, ok := <-chEvents: - if ok { - t.Fatal("expected chEvents to be closed") - } - default: - t.Fatal("expected chEvents to not block") - } - }) -} diff --git a/core/services/pg/locked_db_test.go b/core/services/pg/locked_db_test.go index a2aebcd57f4..ed0935c1411 100644 --- a/core/services/pg/locked_db_test.go +++ b/core/services/pg/locked_db_test.go @@ -5,12 +5,12 @@ import ( "testing" "time" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/stretchr/testify/require" ) @@ -18,8 +18,8 @@ import ( func lease(c *chainlink.Config, s *chainlink.Secrets) { t := true c.Database.Lock.Enabled = &t - c.Database.Lock.LeaseDuration = models.MustNewDuration(10 * time.Second) - c.Database.Lock.LeaseRefreshInterval = models.MustNewDuration(time.Second) + c.Database.Lock.LeaseDuration = commonconfig.MustNewDuration(10 * time.Second) + c.Database.Lock.LeaseRefreshInterval = commonconfig.MustNewDuration(time.Second) } func TestLockedDB_HappyPath(t *testing.T) { diff --git a/core/services/pg/mocks/event_broadcaster.go b/core/services/pg/mocks/event_broadcaster.go deleted file mode 100644 index 63f06db494b..00000000000 --- a/core/services/pg/mocks/event_broadcaster.go +++ /dev/null @@ -1,169 +0,0 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. - -package mocks - -import ( - context "context" - - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - mock "github.com/stretchr/testify/mock" -) - -// EventBroadcaster is an autogenerated mock type for the EventBroadcaster type -type EventBroadcaster struct { - mock.Mock -} - -// Close provides a mock function with given fields: -func (_m *EventBroadcaster) Close() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Close") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// HealthReport provides a mock function with given fields: -func (_m *EventBroadcaster) HealthReport() map[string]error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for HealthReport") - } - - var r0 map[string]error - if rf, ok := ret.Get(0).(func() map[string]error); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]error) - } - } - - return r0 -} - -// Name provides a mock function with given fields: -func (_m *EventBroadcaster) Name() string { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Name") - } - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// Notify provides a mock function with given fields: channel, payload -func (_m *EventBroadcaster) Notify(channel string, payload string) error { - ret := _m.Called(channel, payload) - - if len(ret) == 0 { - panic("no return value specified for Notify") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(channel, payload) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Ready provides a mock function with given fields: -func (_m *EventBroadcaster) Ready() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Ready") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Start provides a mock function with given fields: _a0 -func (_m *EventBroadcaster) Start(_a0 context.Context) error { - ret := _m.Called(_a0) - - if len(ret) == 0 { - panic("no return value specified for Start") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(_a0) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Subscribe provides a mock function with given fields: channel, payloadFilter -func (_m *EventBroadcaster) Subscribe(channel string, payloadFilter string) (pg.Subscription, error) { - ret := _m.Called(channel, payloadFilter) - - if len(ret) == 0 { - panic("no return value specified for Subscribe") - } - - var r0 pg.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(string, string) (pg.Subscription, error)); ok { - return rf(channel, payloadFilter) - } - if rf, ok := ret.Get(0).(func(string, string) pg.Subscription); ok { - r0 = rf(channel, payloadFilter) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(pg.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(string, string) error); ok { - r1 = rf(channel, payloadFilter) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NewEventBroadcaster creates a new instance of EventBroadcaster. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewEventBroadcaster(t interface { - mock.TestingT - Cleanup(func()) -}) *EventBroadcaster { - mock := &EventBroadcaster{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/pg/mocks/subscription.go b/core/services/pg/mocks/subscription.go deleted file mode 100644 index fcd194004de..00000000000 --- a/core/services/pg/mocks/subscription.go +++ /dev/null @@ -1,93 +0,0 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. - -package mocks - -import ( - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - mock "github.com/stretchr/testify/mock" -) - -// Subscription is an autogenerated mock type for the Subscription type -type Subscription struct { - mock.Mock -} - -// ChannelName provides a mock function with given fields: -func (_m *Subscription) ChannelName() string { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for ChannelName") - } - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// Close provides a mock function with given fields: -func (_m *Subscription) Close() { - _m.Called() -} - -// Events provides a mock function with given fields: -func (_m *Subscription) Events() <-chan pg.Event { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Events") - } - - var r0 <-chan pg.Event - if rf, ok := ret.Get(0).(func() <-chan pg.Event); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(<-chan pg.Event) - } - } - - return r0 -} - -// InterestedIn provides a mock function with given fields: event -func (_m *Subscription) InterestedIn(event pg.Event) bool { - ret := _m.Called(event) - - if len(ret) == 0 { - panic("no return value specified for InterestedIn") - } - - var r0 bool - if rf, ok := ret.Get(0).(func(pg.Event) bool); ok { - r0 = rf(event) - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// Send provides a mock function with given fields: event -func (_m *Subscription) Send(event pg.Event) { - _m.Called(event) -} - -// NewSubscription creates a new instance of Subscription. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewSubscription(t interface { - mock.TestingT - Cleanup(func()) -}) *Subscription { - mock := &Subscription{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/pg/q.go b/core/services/pg/q.go index e69e16ec48f..ba2627fa745 100644 --- a/core/services/pg/q.go +++ b/core/services/pg/q.go @@ -154,6 +154,7 @@ func PrepareQueryRowx(q Queryer, sql string, dest interface{}, arg interface{}) if err != nil { return errors.Wrap(err, "error preparing named statement") } + defer stmt.Close() return errors.Wrap(stmt.QueryRowx(arg).Scan(dest), "error querying row") } diff --git a/core/services/pipeline/common.go b/core/services/pipeline/common.go index 0e72bed4226..6efa7aa2148 100644 --- a/core/services/pipeline/common.go +++ b/core/services/pipeline/common.go @@ -20,29 +20,30 @@ import ( pkgerrors "github.com/pkg/errors" "gopkg.in/guregu/null.v4" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" cutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/logger" cnull "github.com/smartcontractkit/chainlink/v2/core/null" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) const ( + BlockHeaderFeederJobType string = "blockheaderfeeder" + BlockhashStoreJobType string = "blockhashstore" + BootstrapJobType string = "bootstrap" CronJobType string = "cron" DirectRequestJobType string = "directrequest" FluxMonitorJobType string = "fluxmonitor" - OffchainReportingJobType string = "offchainreporting" - OffchainReporting2JobType string = "offchainreporting2" - KeeperJobType string = "keeper" - VRFJobType string = "vrf" - BlockhashStoreJobType string = "blockhashstore" - BlockHeaderFeederJobType string = "blockheaderfeeder" - WebhookJobType string = "webhook" - BootstrapJobType string = "bootstrap" GatewayJobType string = "gateway" + KeeperJobType string = "keeper" LegacyGasStationServerJobType string = "legacygasstationserver" LegacyGasStationSidecarJobType string = "legacygasstationsidecar" + OffchainReporting2JobType string = "offchainreporting2" + OffchainReportingJobType string = "offchainreporting" + StreamJobType string = "stream" + VRFJobType string = "vrf" + WebhookJobType string = "webhook" ) //go:generate mockery --quiet --name Config --output ./mocks/ --case=underscore @@ -65,7 +66,7 @@ type ( Config interface { DefaultHTTPLimit() int64 - DefaultHTTPTimeout() models.Duration + DefaultHTTPTimeout() commonconfig.Duration MaxRunDuration() time.Duration ReaperInterval() time.Duration ReaperThreshold() time.Duration diff --git a/core/services/pipeline/mocks/config.go b/core/services/pipeline/mocks/config.go index 4cd6bc7a724..581a84dc049 100644 --- a/core/services/pipeline/mocks/config.go +++ b/core/services/pipeline/mocks/config.go @@ -3,7 +3,7 @@ package mocks import ( - models "github.com/smartcontractkit/chainlink/v2/core/store/models" + config "github.com/smartcontractkit/chainlink-common/pkg/config" mock "github.com/stretchr/testify/mock" time "time" @@ -33,18 +33,18 @@ func (_m *Config) DefaultHTTPLimit() int64 { } // DefaultHTTPTimeout provides a mock function with given fields: -func (_m *Config) DefaultHTTPTimeout() models.Duration { +func (_m *Config) DefaultHTTPTimeout() config.Duration { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for DefaultHTTPTimeout") } - var r0 models.Duration - if rf, ok := ret.Get(0).(func() models.Duration); ok { + var r0 config.Duration + if rf, ok := ret.Get(0).(func() config.Duration); ok { r0 = rf() } else { - r0 = ret.Get(0).(models.Duration) + r0 = ret.Get(0).(config.Duration) } return r0 diff --git a/core/services/pipeline/models.go b/core/services/pipeline/models.go index cfabae82772..d2c722f98b8 100644 --- a/core/services/pipeline/models.go +++ b/core/services/pipeline/models.go @@ -28,9 +28,18 @@ type Spec struct { JobID int32 `json:"-"` JobName string `json:"-"` JobType string `json:"-"` + + Pipeline *Pipeline `json:"-" db:"-"` // This may be nil, or may be populated manually as a cache. There is no locking on this, so be careful +} + +func (s *Spec) GetOrParsePipeline() (*Pipeline, error) { + if s.Pipeline != nil { + return s.Pipeline, nil + } + return s.ParsePipeline() } -func (s Spec) Pipeline() (*Pipeline, error) { +func (s *Spec) ParsePipeline() (*Pipeline, error) { return Parse(s.DotDagSource) } @@ -66,7 +75,7 @@ func (r *Run) SetID(value string) error { if err != nil { return err } - r.ID = int64(ID) + r.ID = ID return nil } diff --git a/core/services/pipeline/orm.go b/core/services/pipeline/orm.go index eb242e62765..70ff244ab3c 100644 --- a/core/services/pipeline/orm.go +++ b/core/services/pipeline/orm.go @@ -346,6 +346,7 @@ RETURNING id if errQ != nil { return errors.Wrap(errQ, "inserting finished pipeline runs") } + defer rows.Close() var runIDs []int64 for rows.Next() { diff --git a/core/services/pipeline/orm_test.go b/core/services/pipeline/orm_test.go index 638977863d6..5578bdcd4ca 100644 --- a/core/services/pipeline/orm_test.go +++ b/core/services/pipeline/orm_test.go @@ -291,7 +291,7 @@ func Test_PipelineORM_StoreRun_DetectsRestarts(t *testing.T) { ds1_id := uuid.New() // insert something for this pipeline_run to trigger an early resume while the pipeline is running - _, err = db.NamedQuery(` + rows, err := db.NamedQuery(` INSERT INTO pipeline_task_runs (pipeline_run_id, id, type, index, output, error, dot_id, created_at, finished_at) VALUES (:pipeline_run_id, :id, :type, :index, :output, :error, :dot_id, :created_at, :finished_at) `, pipeline.TaskRun{ @@ -304,6 +304,7 @@ func Test_PipelineORM_StoreRun_DetectsRestarts(t *testing.T) { FinishedAt: null.TimeFrom(now), }) require.NoError(t, err) + t.Cleanup(func() { assert.NoError(t, rows.Close()) }) run.PipelineTaskRuns = []pipeline.TaskRun{ // pending task diff --git a/core/services/pipeline/runner.go b/core/services/pipeline/runner.go index 3e5d77db5f2..a432d9fec11 100644 --- a/core/services/pipeline/runner.go +++ b/core/services/pipeline/runner.go @@ -243,26 +243,32 @@ func (r *runner) ExecuteRun( }) defer cancel() - run := NewRun(spec, vars) - - pipeline, err := r.initializePipeline(run) - if err != nil { - return run, nil, err + var pipeline *Pipeline + if spec.Pipeline != nil { + // assume if set that it has been pre-initialized + pipeline = spec.Pipeline + } else { + var err error + pipeline, err = r.InitializePipeline(spec) + if err != nil { + return nil, nil, err + } } + run := NewRun(spec, vars) taskRunResults := r.run(ctx, pipeline, run, vars, l) if run.Pending { - return run, nil, pkgerrors.Wrapf(err, "unexpected async run for spec ID %v, tried executing via ExecuteAndInsertFinishedRun", spec.ID) + return run, nil, fmt.Errorf("unexpected async run for spec ID %v, tried executing via ExecuteRun", spec.ID) } return run, taskRunResults, nil } -func (r *runner) initializePipeline(run *Run) (*Pipeline, error) { - pipeline, err := Parse(run.PipelineSpec.DotDagSource) +func (r *runner) InitializePipeline(spec Spec) (pipeline *Pipeline, err error) { + pipeline, err = spec.GetOrParsePipeline() if err != nil { - return nil, err + return } // initialize certain task params @@ -278,7 +284,7 @@ func (r *runner) initializePipeline(run *Run) (*Pipeline, error) { task.(*BridgeTask).config = r.config task.(*BridgeTask).bridgeConfig = r.bridgeConfig task.(*BridgeTask).orm = r.btORM - task.(*BridgeTask).specId = run.PipelineSpec.ID + task.(*BridgeTask).specId = spec.ID // URL is "safe" because it comes from the node's own database. We // must use the unrestrictedHTTPClient because some node operators // may run external adapters on their own hardware @@ -286,8 +292,8 @@ func (r *runner) initializePipeline(run *Run) (*Pipeline, error) { case TaskTypeETHCall: task.(*ETHCallTask).legacyChains = r.legacyEVMChains task.(*ETHCallTask).config = r.config - task.(*ETHCallTask).specGasLimit = run.PipelineSpec.GasLimit - task.(*ETHCallTask).jobType = run.PipelineSpec.JobType + task.(*ETHCallTask).specGasLimit = spec.GasLimit + task.(*ETHCallTask).jobType = spec.JobType case TaskTypeVRF: task.(*VRFTask).keyStore = r.vrfKeyStore case TaskTypeVRFV2: @@ -296,28 +302,18 @@ func (r *runner) initializePipeline(run *Run) (*Pipeline, error) { task.(*VRFTaskV2Plus).keyStore = r.vrfKeyStore case TaskTypeEstimateGasLimit: task.(*EstimateGasLimitTask).legacyChains = r.legacyEVMChains - task.(*EstimateGasLimitTask).specGasLimit = run.PipelineSpec.GasLimit - task.(*EstimateGasLimitTask).jobType = run.PipelineSpec.JobType + task.(*EstimateGasLimitTask).specGasLimit = spec.GasLimit + task.(*EstimateGasLimitTask).jobType = spec.JobType case TaskTypeETHTx: task.(*ETHTxTask).keyStore = r.ethKeyStore task.(*ETHTxTask).legacyChains = r.legacyEVMChains - task.(*ETHTxTask).specGasLimit = run.PipelineSpec.GasLimit - task.(*ETHTxTask).jobType = run.PipelineSpec.JobType - task.(*ETHTxTask).forwardingAllowed = run.PipelineSpec.ForwardingAllowed + task.(*ETHTxTask).specGasLimit = spec.GasLimit + task.(*ETHTxTask).jobType = spec.JobType + task.(*ETHTxTask).forwardingAllowed = spec.ForwardingAllowed default: } } - // retain old UUID values - for _, taskRun := range run.PipelineTaskRuns { - task := pipeline.ByDotID(taskRun.DotID) - if task != nil && task.Base() != nil { - task.Base().uuid = taskRun.ID - } else { - return nil, pkgerrors.Errorf("failed to match a pipeline task for dot ID: %v", taskRun.DotID) - } - } - return pipeline, nil } @@ -542,11 +538,21 @@ func (r *runner) ExecuteAndInsertFinishedRun(ctx context.Context, spec Spec, var } func (r *runner) Run(ctx context.Context, run *Run, l logger.Logger, saveSuccessfulTaskRuns bool, fn func(tx pg.Queryer) error) (incomplete bool, err error) { - pipeline, err := r.initializePipeline(run) + pipeline, err := r.InitializePipeline(run.PipelineSpec) if err != nil { return false, err } + // retain old UUID values + for _, taskRun := range run.PipelineTaskRuns { + task := pipeline.ByDotID(taskRun.DotID) + if task != nil && task.Base() != nil { + task.Base().uuid = taskRun.ID + } else { + return false, pkgerrors.Errorf("failed to match a pipeline task for dot ID: %v", taskRun.DotID) + } + } + preinsert := pipeline.RequiresPreInsert() q := r.orm.GetQ().WithOpts(pg.WithParentCtx(ctx)) diff --git a/core/services/pipeline/runner_test.go b/core/services/pipeline/runner_test.go index 695590e7bd0..5b4aaef7e88 100644 --- a/core/services/pipeline/runner_test.go +++ b/core/services/pipeline/runner_test.go @@ -942,3 +942,43 @@ en->de require.NoError(t, err) assert.Equal(t, inputBytes, result.Value) } + +func Test_PipelineRunner_ExecuteRun(t *testing.T) { + t.Run("uses cached *Pipeline if available", func(t *testing.T) { + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, KeyStore: ethKeyStore}) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) + lggr := logger.TestLogger(t) + r := pipeline.NewRunner(nil, nil, cfg.JobPipeline(), cfg.WebServer(), legacyChains, ethKeyStore, nil, lggr, nil, nil) + + template := ` +succeed [type=memo value=%d] +succeed; +` + + spec := pipeline.Spec{DotDagSource: fmt.Sprintf(template, 1)} + vars := pipeline.NewVarsFrom(nil) + + _, trrs, err := r.ExecuteRun(testutils.Context(t), spec, vars, lggr) + require.NoError(t, err) + require.Len(t, trrs, 1) + assert.Equal(t, "1", trrs[0].Result.Value.(pipeline.ObjectParam).DecimalValue.Decimal().String()) + + // does not automatically cache + require.Nil(t, spec.Pipeline) + + // initialize it + spec.Pipeline, err = spec.ParsePipeline() + require.NoError(t, err) + + // even though this is set to 2, it should use the cached version + spec.DotDagSource = fmt.Sprintf(template, 2) + + _, trrs, err = r.ExecuteRun(testutils.Context(t), spec, vars, lggr) + require.NoError(t, err) + require.Len(t, trrs, 1) + assert.Equal(t, "1", trrs[0].Result.Value.(pipeline.ObjectParam).DecimalValue.Decimal().String()) + }) +} diff --git a/core/services/pipeline/scheduler.go b/core/services/pipeline/scheduler.go index 7c6fd78d0c2..7663ed948ff 100644 --- a/core/services/pipeline/scheduler.go +++ b/core/services/pipeline/scheduler.go @@ -33,7 +33,7 @@ func (s *scheduler) newMemoryTaskRun(task Task, vars Vars) *memoryTaskRun { // if we're confident that indices are within range for _, i := range task.Inputs() { if i.PropagateResult { - inputs = append(inputs, input{index: int32(i.InputTask.OutputIndex()), result: s.results[i.InputTask.ID()].Result}) + inputs = append(inputs, input{index: i.InputTask.OutputIndex(), result: s.results[i.InputTask.ID()].Result}) } } sort.Slice(inputs, func(i, j int) bool { diff --git a/core/services/pipeline/task.bridge.go b/core/services/pipeline/task.bridge.go index fbf861857f5..f9490ea791d 100644 --- a/core/services/pipeline/task.bridge.go +++ b/core/services/pipeline/task.bridge.go @@ -74,7 +74,7 @@ var _ Task = (*BridgeTask)(nil) var zeroURL = new(url.URL) -const stalenessCap = time.Duration(30 * time.Minute) +const stalenessCap = 30 * time.Minute func (t *BridgeTask) Type() TaskType { return TaskTypeBridge @@ -166,7 +166,7 @@ func (t *BridgeTask) Run(ctx context.Context, lggr logger.Logger, vars Vars, inp } var cachedResponse bool - responseBytes, statusCode, headers, elapsed, err := makeHTTPRequest(requestCtx, lggr, "POST", URLParam(url), reqHeaders, requestData, t.httpClient, t.config.DefaultHTTPLimit()) + responseBytes, statusCode, headers, elapsed, err := makeHTTPRequest(requestCtx, lggr, "POST", url, reqHeaders, requestData, t.httpClient, t.config.DefaultHTTPLimit()) if err != nil { promBridgeErrors.WithLabelValues(t.Name).Inc() if cacheTTL == 0 { diff --git a/core/services/pipeline/task.bridge_test.go b/core/services/pipeline/task.bridge_test.go index 03a804c9c12..bf1e63d6314 100644 --- a/core/services/pipeline/task.bridge_test.go +++ b/core/services/pipeline/task.bridge_test.go @@ -21,6 +21,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -270,7 +271,7 @@ func TestBridgeTask_DoesNotReturnStaleResults(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.WebServer.BridgeCacheTTL = models.MustNewDuration(30 * time.Second) + c.WebServer.BridgeCacheTTL = commonconfig.MustNewDuration(30 * time.Second) }) queryer := pg.NewQ(db, logger.TestLogger(t), cfg.Database()) s1 := httptest.NewServer(fakeIntermittentlyFailingPriceResponder(t, utils.MustUnmarshalToMap(btcUSDPairing), decimal.NewFromInt(9700), "", nil)) @@ -336,7 +337,7 @@ func TestBridgeTask_DoesNotReturnStaleResults(t *testing.T) { require.Equal(t, string(big.NewInt(9700).Bytes()), result2.Value) cfg2 := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.WebServer.BridgeCacheTTL = models.MustNewDuration(0 * time.Second) + c.WebServer.BridgeCacheTTL = commonconfig.MustNewDuration(0 * time.Second) }) task.HelperSetDependencies(cfg2.JobPipeline(), cfg2.WebServer(), orm, specID, uuid.UUID{}, c) diff --git a/core/services/pipeline/task.vrfv2.go b/core/services/pipeline/task.vrfv2.go index a871e543496..2c2c85eaedf 100644 --- a/core/services/pipeline/task.vrfv2.go +++ b/core/services/pipeline/task.vrfv2.go @@ -39,7 +39,7 @@ func (t *VRFTaskV2) Type() TaskType { return TaskTypeVRFV2 } -func (t *VRFTaskV2) Run(_ context.Context, _ logger.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { +func (t *VRFTaskV2) Run(_ context.Context, lggr logger.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { if len(inputs) != 1 { return Result{Error: ErrWrongInputCardinality}, runInfo } @@ -134,7 +134,8 @@ func (t *VRFTaskV2) Run(_ context.Context, _ logger.Logger, vars Vars, inputs [] return Result{Error: err}, runInfo } results := make(map[string]interface{}) - results["output"] = hexutil.Encode(b) + output := hexutil.Encode(b) + results["output"] = output // RequestID needs to be a [32]byte for EvmTxMeta. results["requestID"] = hexutil.Encode(requestId.Bytes()) @@ -142,5 +143,7 @@ func (t *VRFTaskV2) Run(_ context.Context, _ logger.Logger, vars Vars, inputs [] results["proof"] = onChainProof results["requestCommitment"] = rc + lggr.Debugw("Completed VRF V2 task run", "reqID", requestId.String(), "output", output) + return Result{Value: results}, runInfo } diff --git a/core/services/pipeline/task.vrfv2plus.go b/core/services/pipeline/task.vrfv2plus.go index a596bfa3092..c029af68cbe 100644 --- a/core/services/pipeline/task.vrfv2plus.go +++ b/core/services/pipeline/task.vrfv2plus.go @@ -42,7 +42,7 @@ func (t *VRFTaskV2Plus) Type() TaskType { return TaskTypeVRFV2Plus } -func (t *VRFTaskV2Plus) Run(_ context.Context, _ logger.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { +func (t *VRFTaskV2Plus) Run(_ context.Context, lggr logger.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { if len(inputs) != 1 { return Result{Error: ErrWrongInputCardinality}, runInfo } @@ -142,7 +142,8 @@ func (t *VRFTaskV2Plus) Run(_ context.Context, _ logger.Logger, vars Vars, input return Result{Error: err}, runInfo } results := make(map[string]interface{}) - results["output"] = hexutil.Encode(b) + output := hexutil.Encode(b) + results["output"] = output // RequestID needs to be a [32]byte for EvmTxMeta. results["requestID"] = hexutil.Encode(requestId.Bytes()) @@ -150,5 +151,7 @@ func (t *VRFTaskV2Plus) Run(_ context.Context, _ logger.Logger, vars Vars, input results["proof"] = onChainProof results["requestCommitment"] = rc + lggr.Debugw("Completed VRF V2 task run", "reqID", requestId.String(), "output", output) + return Result{Value: results}, runInfo } diff --git a/core/services/pipeline/task_params.go b/core/services/pipeline/task_params.go index 261728fbe9e..72d0d619429 100644 --- a/core/services/pipeline/task_params.go +++ b/core/services/pipeline/task_params.go @@ -334,7 +334,7 @@ func (p *MaybeInt32Param) UnmarshalPipelineParam(val interface{}) error { case int16: n = int32(v) case int32: - n = int32(v) + n = v case int64: if v > math.MaxInt32 || v < math.MinInt32 { return errors.Wrap(ErrBadInput, "overflows int32") @@ -764,7 +764,7 @@ func (p *MaybeBigIntParam) UnmarshalPipelineParam(val interface{}) error { case int32: n = big.NewInt(int64(v)) case int64: - n = big.NewInt(int64(v)) + n = big.NewInt(v) case float64: // when decoding from db: JSON numbers are floats if v < math.MinInt64 || v > math.MaxUint64 { return errors.Wrapf(ErrBadInput, "cannot cast %v to u/int64", v) diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 9e3c20553ab..50a97618638 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -45,15 +45,14 @@ import ( var _ commontypes.Relayer = &Relayer{} //nolint:staticcheck type Relayer struct { - db *sqlx.DB - chain legacyevm.Chain - lggr logger.Logger - ks CSAETHKeystore - mercuryPool wsrpc.Pool - eventBroadcaster pg.EventBroadcaster - pgCfg pg.QConfig - chainReader commontypes.ChainReader - codec commontypes.Codec + db *sqlx.DB + chain legacyevm.Chain + lggr logger.Logger + ks CSAETHKeystore + mercuryPool wsrpc.Pool + pgCfg pg.QConfig + chainReader commontypes.ChainReader + codec commontypes.Codec } type CSAETHKeystore interface { @@ -65,7 +64,6 @@ type RelayerOpts struct { *sqlx.DB pg.QConfig CSAETHKeystore - pg.EventBroadcaster MercuryPool wsrpc.Pool } @@ -80,9 +78,6 @@ func (c RelayerOpts) Validate() error { if c.CSAETHKeystore == nil { err = errors.Join(err, errors.New("nil Keystore")) } - if c.EventBroadcaster == nil { - err = errors.Join(err, errors.New("nil Eventbroadcaster")) - } if err != nil { err = fmt.Errorf("invalid RelayerOpts: %w", err) @@ -97,13 +92,12 @@ func NewRelayer(lggr logger.Logger, chain legacyevm.Chain, opts RelayerOpts) (*R } lggr = lggr.Named("Relayer") return &Relayer{ - db: opts.DB, - chain: chain, - lggr: lggr, - ks: opts.CSAETHKeystore, - mercuryPool: opts.MercuryPool, - eventBroadcaster: opts.EventBroadcaster, - pgCfg: opts.QConfig, + db: opts.DB, + chain: chain, + lggr: lggr, + ks: opts.CSAETHKeystore, + mercuryPool: opts.MercuryPool, + pgCfg: opts.QConfig, }, nil } @@ -152,7 +146,7 @@ func (r *Relayer) NewMercuryProvider(rargs commontypes.RelayArgs, pargs commonty if relayConfig.ChainID.String() != r.chain.ID().String() { return nil, fmt.Errorf("internal error: chain id in spec does not match this relayer's chain: have %s expected %s", relayConfig.ChainID.String(), r.chain.ID().String()) } - cw, err := newConfigProvider(lggr, r.chain, relayOpts, r.eventBroadcaster) + cw, err := newConfigProvider(lggr, r.chain, relayOpts) if err != nil { return nil, pkgerrors.WithStack(err) } @@ -211,7 +205,7 @@ func (r *Relayer) NewConfigProvider(args commontypes.RelayArgs) (commontypes.Con return nil, fmt.Errorf("internal error: chain id in spec does not match this relayer's chain: have %s expected %s", relayConfig.ChainID.String(), r.chain.ID().String()) } - configProvider, err := newConfigProvider(lggr, r.chain, relayOpts, r.eventBroadcaster) + configProvider, err := newConfigProvider(lggr, r.chain, relayOpts) if err != nil { // Never return (*configProvider)(nil) return nil, err @@ -321,7 +315,7 @@ func (c *configWatcher) ContractConfigTracker() ocrtypes.ContractConfigTracker { return c.configPoller } -func newConfigProvider(lggr logger.Logger, chain legacyevm.Chain, opts *types.RelayOpts, eventBroadcaster pg.EventBroadcaster) (*configWatcher, error) { +func newConfigProvider(lggr logger.Logger, chain legacyevm.Chain, opts *types.RelayOpts) (*configWatcher, error) { if !common.IsHexAddress(opts.ContractID) { return nil, pkgerrors.Errorf("invalid contractID, expected hex address") } @@ -343,7 +337,6 @@ func newConfigProvider(lggr logger.Logger, chain legacyevm.Chain, opts *types.Re chain.LogPoller(), aggregatorAddress, *relayConfig.FeedID, - eventBroadcaster, // TODO: Does mercury need to support config contract? DF-19182 ) } else { @@ -466,7 +459,7 @@ func (r *Relayer) NewMedianProvider(rargs commontypes.RelayArgs, pargs commontyp } contractID := common.HexToAddress(relayOpts.ContractID) - configWatcher, err := newConfigProvider(lggr, r.chain, relayOpts, r.eventBroadcaster) + configWatcher, err := newConfigProvider(lggr, r.chain, relayOpts) if err != nil { return nil, err } diff --git a/core/services/relay/evm/evm_test.go b/core/services/relay/evm/evm_test.go index 8f49128ff2d..41e51a7ab8f 100644 --- a/core/services/relay/evm/evm_test.go +++ b/core/services/relay/evm/evm_test.go @@ -15,10 +15,9 @@ import ( func TestRelayerOpts_Validate(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) type fields struct { - DB *sqlx.DB - QConfig pg.QConfig - CSAETHKeystore evm.CSAETHKeystore - EventBroadcaster pg.EventBroadcaster + DB *sqlx.DB + QConfig pg.QConfig + CSAETHKeystore evm.CSAETHKeystore } tests := []struct { name string @@ -28,23 +27,19 @@ func TestRelayerOpts_Validate(t *testing.T) { { name: "all invalid", fields: fields{ - DB: nil, - QConfig: nil, - CSAETHKeystore: nil, - EventBroadcaster: nil, + DB: nil, + QConfig: nil, + CSAETHKeystore: nil, }, wantErrContains: `nil DB nil QConfig -nil Keystore -nil Eventbroadcaster`, +nil Keystore`, }, { name: "missing db, keystore", fields: fields{ - DB: nil, - QConfig: cfg.Database(), - CSAETHKeystore: nil, - EventBroadcaster: pg.NewNullEventBroadcaster(), + DB: nil, + QConfig: cfg.Database(), }, wantErrContains: `nil DB nil Keystore`, @@ -53,10 +48,9 @@ nil Keystore`, for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := evm.RelayerOpts{ - DB: tt.fields.DB, - QConfig: tt.fields.QConfig, - CSAETHKeystore: tt.fields.CSAETHKeystore, - EventBroadcaster: tt.fields.EventBroadcaster, + DB: tt.fields.DB, + QConfig: tt.fields.QConfig, + CSAETHKeystore: tt.fields.CSAETHKeystore, } err := c.Validate() if tt.wantErrContains != "" { diff --git a/core/services/relay/evm/mercury/config_digest_test.go b/core/services/relay/evm/mercury/config_digest_test.go index 3e94d075dce..fe718e92fe5 100644 --- a/core/services/relay/evm/mercury/config_digest_test.go +++ b/core/services/relay/evm/mercury/config_digest_test.go @@ -107,7 +107,7 @@ func GenHash(t *testing.T) gopter.Gen { array, ok := byteArray.(*gopter.GenResult).Retrieve() require.True(t, ok, "failed to retrieve gen result") for i, byteVal := range array.([]interface{}) { - rv[i] = byte(byteVal.(uint8)) + rv[i] = byteVal.(uint8) } return rv }, @@ -199,7 +199,7 @@ func GenBytes(t *testing.T) gopter.Gen { iArray := array.([]interface{}) rv := make([]byte, len(iArray)) for i, byteVal := range iArray { - rv[i] = byte(byteVal.(uint8)) + rv[i] = byteVal.(uint8) } return rv }, diff --git a/core/services/relay/evm/mercury/config_poller.go b/core/services/relay/evm/mercury/config_poller.go index 8964a283049..98ef78020c7 100644 --- a/core/services/relay/evm/mercury/config_poller.go +++ b/core/services/relay/evm/mercury/config_poller.go @@ -91,8 +91,6 @@ type ConfigPoller struct { destChainLogPoller logpoller.LogPoller addr common.Address feedId common.Hash - notifyCh chan struct{} - subscription pg.Subscription } func FilterName(addr common.Address, feedID common.Hash) string { @@ -100,43 +98,30 @@ func FilterName(addr common.Address, feedID common.Hash) string { } // NewConfigPoller creates a new Mercury ConfigPoller -func NewConfigPoller(lggr logger.Logger, destChainPoller logpoller.LogPoller, addr common.Address, feedId common.Hash, eventBroadcaster pg.EventBroadcaster) (*ConfigPoller, error) { +func NewConfigPoller(lggr logger.Logger, destChainPoller logpoller.LogPoller, addr common.Address, feedId common.Hash) (*ConfigPoller, error) { err := destChainPoller.RegisterFilter(logpoller.Filter{Name: FilterName(addr, feedId), EventSigs: []common.Hash{FeedScopedConfigSet}, Addresses: []common.Address{addr}}) if err != nil { return nil, err } - subscription, err := eventBroadcaster.Subscribe(pg.ChannelInsertOnEVMLogs, "") - if err != nil { - return nil, err - } - cp := &ConfigPoller{ lggr: lggr, destChainLogPoller: destChainPoller, addr: addr, feedId: feedId, - notifyCh: make(chan struct{}, 1), - subscription: subscription, } return cp, nil } -// Start the subscription to Postgres' notify events. -func (cp *ConfigPoller) Start() { - go cp.startLogSubscription() -} +func (cp *ConfigPoller) Start() {} -// Close the subscription to Postgres' notify events. func (cp *ConfigPoller) Close() error { - cp.subscription.Close() return nil } -// Notify abstracts the logpoller.LogPoller Notify() implementation func (cp *ConfigPoller) Notify() <-chan struct{} { - return cp.notifyCh + return nil // rely on libocr's builtin config polling } // Replay abstracts the logpoller.LogPoller Replay() implementation @@ -190,42 +175,3 @@ func (cp *ConfigPoller) LatestBlockHeight(ctx context.Context) (blockHeight uint } return uint64(latest.BlockNumber), nil } - -func (cp *ConfigPoller) startLogSubscription() { - // trim the leading 0x to make it comparable to pg's hex encoding. - addressPgHex := cp.addr.Hex()[2:] - feedIdPgHex := cp.feedId.Hex()[2:] - - for { - event, ok := <-cp.subscription.Events() - if !ok { - cp.lggr.Debug("eventBroadcaster subscription closed, exiting notify loop") - return - } - - // Event payload should look like: "
:," - addressTopicValues := strings.Split(event.Payload, ":") - if len(addressTopicValues) < 2 { - cp.lggr.Warnf("invalid event from %s channel: %s", pg.ChannelInsertOnEVMLogs, event.Payload) - continue - } - - address := addressTopicValues[0] - if address != addressPgHex { - continue - } - - topicValues := strings.Split(addressTopicValues[1], ",") - if len(topicValues) <= feedIdTopicIndex { - continue - } - if topicValues[feedIdTopicIndex] != feedIdPgHex { - continue - } - - select { - case cp.notifyCh <- struct{}{}: - default: - } - } -} diff --git a/core/services/relay/evm/mercury/config_poller_test.go b/core/services/relay/evm/mercury/config_poller_test.go index 71e88d41a22..f828938f954 100644 --- a/core/services/relay/evm/mercury/config_poller_test.go +++ b/core/services/relay/evm/mercury/config_poller_test.go @@ -6,7 +6,6 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/onsi/gomega" "github.com/pkg/errors" confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" @@ -18,7 +17,6 @@ import ( evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -27,7 +25,6 @@ func TestMercuryConfigPoller(t *testing.T) { feedIDBytes := [32]byte(feedID) th := SetupTH(t, feedID) - th.subscription.On("Events").Return(nil) notify := th.configPoller.Notify() assert.Empty(t, notify) @@ -115,54 +112,6 @@ func TestMercuryConfigPoller(t *testing.T) { assert.Equal(t, offchainConfig, newConfig.OffchainConfig) } -func TestNotify(t *testing.T) { - testutils.SkipFlakey(t, "https://smartcontract-it.atlassian.net/browse/BCF-2746") - feedIDStr := "8257737fdf4f79639585fd0ed01bea93c248a9ad940e98dd27f41c9b6230fed1" - feedIDBytes, err := hexutil.Decode("0x" + feedIDStr) - require.NoError(t, err) - feedID := common.BytesToHash(feedIDBytes) - - eventCh := make(chan pg.Event) - - th := SetupTH(t, feedID) - th.subscription.On("Events").Return((<-chan pg.Event)(eventCh)) - - addressPgHex := th.verifierAddress.Hex()[2:] - - notify := th.configPoller.Notify() - assert.Empty(t, notify) - - eventCh <- pg.Event{} // Empty event - assert.Empty(t, notify) - - eventCh <- pg.Event{Payload: addressPgHex} // missing topic values - assert.Empty(t, notify) - - eventCh <- pg.Event{Payload: addressPgHex + ":val1"} // missing feedId topic value - assert.Empty(t, notify) - - eventCh <- pg.Event{Payload: addressPgHex + ":8257737fdf4f79639585fd0ed01bea93c248a9ad940e98dd27f41c9b6230fed1,val2"} // wrong index - assert.Empty(t, notify) - - eventCh <- pg.Event{Payload: addressPgHex + ":val1,val2,8257737fdf4f79639585fd0ed01bea93c248a9ad940e98dd27f41c9b6230fed1"} // wrong index - assert.Empty(t, notify) - - eventCh <- pg.Event{Payload: addressPgHex + ":val1,0x8257737fdf4f79639585fd0ed01bea93c248a9ad940e98dd27f41c9b6230fed1"} // 0x prefix - assert.Empty(t, notify) - - eventCh <- pg.Event{Payload: "wrong_address:val1,8257737fdf4f79639585fd0ed01bea93c248a9ad940e98dd27f41c9b6230fed1"} // wrong address - assert.Empty(t, notify) - - eventCh <- pg.Event{Payload: addressPgHex + ":val1,8257737fdf4f79639585fd0ed01bea93c248a9ad940e98dd27f41c9b6230fed1"} // expected event to notify on - assert.Eventually(t, func() bool { <-notify; return true }, time.Second, 10*time.Millisecond) - - eventCh <- pg.Event{Payload: addressPgHex + ":val1,8257737fdf4f79639585fd0ed01bea93c248a9ad940e98dd27f41c9b6230fed1"} // try second time - assert.Eventually(t, func() bool { <-notify; return true }, time.Second, 10*time.Millisecond) - - eventCh <- pg.Event{Payload: addressPgHex + ":val1,8257737fdf4f79639585fd0ed01bea93c248a9ad940e98dd27f41c9b6230fed1:additional"} // additional colon separated parts - assert.Eventually(t, func() bool { <-notify; return true }, time.Second, 10*time.Millisecond) -} - func onchainPublicKeyToAddress(publicKeys []types.OnchainPublicKey) (addresses []common.Address, err error) { for _, signer := range publicKeys { if len(signer) != 20 { diff --git a/core/services/relay/evm/mercury/helpers_test.go b/core/services/relay/evm/mercury/helpers_test.go index 0703f878eed..f1686ee00c8 100644 --- a/core/services/relay/evm/mercury/helpers_test.go +++ b/core/services/relay/evm/mercury/helpers_test.go @@ -18,6 +18,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" @@ -26,7 +27,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" - pgmocks "github.com/smartcontractkit/chainlink/v2/core/services/pg/mocks" reportcodecv1 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v1/reportcodec" reportcodecv2 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v2/reportcodec" reportcodecv3 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v3/reportcodec" @@ -143,8 +143,6 @@ type TestHarness struct { verifierAddress common.Address verifierContract *verifier.Verifier logPoller logpoller.LogPoller - eventBroadcaster *pgmocks.EventBroadcaster - subscription *pgmocks.Subscription } func SetupTH(t *testing.T, feedID common.Hash) TestHarness { @@ -170,13 +168,9 @@ func SetupTH(t *testing.T, feedID common.Hash) TestHarness { lggr := logger.TestLogger(t) lorm := logpoller.NewORM(big.NewInt(1337), db, lggr, cfg) lp := logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, false, 1, 2, 2, 1000) - eventBroadcaster := pgmocks.NewEventBroadcaster(t) - subscription := pgmocks.NewSubscription(t) servicetest.Run(t, lp) - eventBroadcaster.On("Subscribe", "evm.insert_on_logs", "").Return(subscription, nil) - - configPoller, err := NewConfigPoller(lggr, lp, verifierAddress, feedID, eventBroadcaster) + configPoller, err := NewConfigPoller(lggr, lp, verifierAddress, feedID) require.NoError(t, err) configPoller.Start() @@ -188,7 +182,5 @@ func SetupTH(t *testing.T, feedID common.Hash) TestHarness { verifierAddress: verifierAddress, verifierContract: verifierContract, logPoller: lp, - eventBroadcaster: eventBroadcaster, - subscription: subscription, } } diff --git a/core/services/relay/evm/mercury/wsrpc/cache/cache.go b/core/services/relay/evm/mercury/wsrpc/cache/cache.go index 181900bc15c..712e62e5c0e 100644 --- a/core/services/relay/evm/mercury/wsrpc/cache/cache.go +++ b/core/services/relay/evm/mercury/wsrpc/cache/cache.go @@ -237,7 +237,7 @@ func (m *memCache) LatestReport(ctx context.Context, req *pb.LatestReportRequest // CACHE HIT promCacheHitCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() m.lggr.Tracew("LatestReport CACHE HIT (cold path)", "feedID", feedIDHex) - defer v.RUnlock() + defer v.Unlock() return v.val, nil } else if v.fetching { // CACHE WAIT diff --git a/core/services/relay/evm/request_round_db.go b/core/services/relay/evm/request_round_db.go index 331d663918a..b3a5b01bc2c 100644 --- a/core/services/relay/evm/request_round_db.go +++ b/core/services/relay/evm/request_round_db.go @@ -61,6 +61,7 @@ LIMIT 1 if err != nil { return rr, errors.Wrap(err, "LoadLatestRoundRequested failed to query rows") } + defer rows.Close() for rows.Next() { var configDigest []byte diff --git a/core/services/relay/relay.go b/core/services/relay/relay.go index 118d5935851..826c3d17a44 100644 --- a/core/services/relay/relay.go +++ b/core/services/relay/relay.go @@ -12,19 +12,20 @@ import ( type Network = string type ChainID = string -var ( - EVM Network = "evm" - Cosmos Network = "cosmos" - Solana Network = "solana" - StarkNet Network = "starknet" - SupportedRelays = map[Network]struct{}{ - EVM: {}, - Cosmos: {}, - Solana: {}, - StarkNet: {}, - } +const ( + EVM = "evm" + Cosmos = "cosmos" + Solana = "solana" + StarkNet = "starknet" ) +var SupportedRelays = map[Network]struct{}{ + EVM: {}, + Cosmos: {}, + Solana: {}, + StarkNet: {}, +} + // ID uniquely identifies a relayer by network and chain id type ID struct { Network Network @@ -54,9 +55,9 @@ func (i *ID) UnmarshalString(s string) error { // ignore the `.` in the match by dropping last rune network := s[idxs[0] : idxs[1]-1] chainID := s[idxs[1]:] - newID := &ID{ChainID: ChainID(chainID)} + newID := &ID{ChainID: chainID} for n := range SupportedRelays { - if Network(network) == n { + if network == n { newID.Network = n break } diff --git a/core/services/s4/storage_test.go b/core/services/s4/storage_test.go index 86161f298e4..199e3e6924b 100644 --- a/core/services/s4/storage_test.go +++ b/core/services/s4/storage_test.go @@ -52,7 +52,7 @@ func TestStorage_Errors(t *testing.T) { SlotId: 1, Version: 0, } - ormMock.On("Get", big.New(key.Address.Big()), uint(key.SlotId), mock.Anything).Return(nil, s4.ErrNotFound) + ormMock.On("Get", big.New(key.Address.Big()), key.SlotId, mock.Anything).Return(nil, s4.ErrNotFound) _, _, err := storage.Get(testutils.Context(t), key) assert.ErrorIs(t, err, s4.ErrNotFound) }) diff --git a/core/services/signatures/secp256k1/field.go b/core/services/signatures/secp256k1/field.go index 1ff0d062f3c..bf9652e5dbd 100644 --- a/core/services/signatures/secp256k1/field.go +++ b/core/services/signatures/secp256k1/field.go @@ -49,7 +49,7 @@ func (f *fieldElt) modQ() *fieldElt { func fieldEltFromBigInt(v *big.Int) *fieldElt { return (*fieldElt)(v).modQ() } func fieldEltFromInt(v int64) *fieldElt { - return fieldEltFromBigInt(big.NewInt(int64(v))).modQ() + return fieldEltFromBigInt(big.NewInt(v)).modQ() } var fieldZero = fieldEltFromInt(0) diff --git a/core/services/streams/delegate.go b/core/services/streams/delegate.go new file mode 100644 index 00000000000..b62ceb9857b --- /dev/null +++ b/core/services/streams/delegate.go @@ -0,0 +1,110 @@ +package streams + +import ( + "context" + "fmt" + "strings" + + "github.com/google/uuid" + "github.com/pelletier/go-toml/v2" + "github.com/pkg/errors" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" +) + +type DelegateConfig interface { + MaxSuccessfulRuns() uint64 + ResultWriteQueueDepth() uint64 +} + +type Delegate struct { + lggr logger.Logger + registry Registry + runner ocrcommon.Runner + cfg DelegateConfig +} + +var _ job.Delegate = (*Delegate)(nil) + +func NewDelegate(lggr logger.Logger, registry Registry, runner ocrcommon.Runner, cfg DelegateConfig) *Delegate { + return &Delegate{lggr, registry, runner, cfg} +} + +func (d *Delegate) JobType() job.Type { + return job.Stream +} + +func (d *Delegate) BeforeJobCreated(jb job.Job) {} +func (d *Delegate) AfterJobCreated(jb job.Job) {} +func (d *Delegate) BeforeJobDeleted(jb job.Job) {} +func (d *Delegate) OnDeleteJob(jb job.Job, q pg.Queryer) error { return nil } + +func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err error) { + if !jb.Name.Valid { + return nil, errors.New("job name is required to be present for stream specs") + } + id := jb.Name.String + lggr := d.lggr.Named(id).With("streamID", id) + + rrs := ocrcommon.NewResultRunSaver(d.runner, lggr, d.cfg.MaxSuccessfulRuns(), d.cfg.ResultWriteQueueDepth()) + services = append(services, rrs, &StreamService{ + d.registry, + id, + jb.PipelineSpec, + lggr, + rrs, + }) + return services, nil +} + +type ResultRunSaver interface { + Save(run *pipeline.Run) +} + +type StreamService struct { + registry Registry + id StreamID + spec *pipeline.Spec + lggr logger.Logger + rrs ResultRunSaver +} + +func (s *StreamService) Start(_ context.Context) error { + if s.spec == nil { + return fmt.Errorf("pipeline spec unexpectedly missing for stream %q", s.id) + } + s.lggr.Debugf("Starting stream %q", s.id) + return s.registry.Register(s.id, *s.spec, s.rrs) +} + +func (s *StreamService) Close() error { + s.lggr.Debugf("Stopping stream %q", s.id) + s.registry.Unregister(s.id) + return nil +} + +func ValidatedStreamSpec(tomlString string) (job.Job, error) { + var jb = job.Job{ExternalJobID: uuid.New()} + + r := strings.NewReader(tomlString) + d := toml.NewDecoder(r) + d.DisallowUnknownFields() + err := d.Decode(&jb) + if err != nil { + return jb, errors.Wrap(err, "toml unmarshal error on job") + } + + if jb.Type != job.Stream { + return jb, errors.Errorf("unsupported type: %q", jb.Type) + } + + if !jb.Name.Valid { + return jb, errors.New("jobs of type 'stream' require a non-blank name as stream ID") + } + + return jb, nil +} diff --git a/core/services/streams/delegate_test.go b/core/services/streams/delegate_test.go new file mode 100644 index 00000000000..77b10260375 --- /dev/null +++ b/core/services/streams/delegate_test.go @@ -0,0 +1,161 @@ +package streams + +import ( + "testing" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/guregu/null.v4" +) + +type mockRegistry struct{} + +func (m *mockRegistry) Get(streamID StreamID) (strm Stream, exists bool) { return } +func (m *mockRegistry) Register(streamID StreamID, spec pipeline.Spec, rrs ResultRunSaver) error { + return nil +} +func (m *mockRegistry) Unregister(streamID StreamID) {} + +type mockDelegateConfig struct{} + +func (m *mockDelegateConfig) MaxSuccessfulRuns() uint64 { return 0 } +func (m *mockDelegateConfig) ResultWriteQueueDepth() uint64 { return 0 } + +func Test_Delegate(t *testing.T) { + lggr := logger.TestLogger(t) + registry := &mockRegistry{} + runner := &mockRunner{} + cfg := &mockDelegateConfig{} + d := NewDelegate(lggr, registry, runner, cfg) + + t.Run("ServicesForSpec", func(t *testing.T) { + jb := job.Job{PipelineSpec: &pipeline.Spec{ID: 1}} + t.Run("errors if job is missing name", func(t *testing.T) { + _, err := d.ServicesForSpec(jb) + assert.EqualError(t, err, "job name is required to be present for stream specs") + }) + jb.Name = null.StringFrom("jobname") + t.Run("returns services", func(t *testing.T) { + srvs, err := d.ServicesForSpec(jb) + require.NoError(t, err) + + assert.Len(t, srvs, 2) + assert.IsType(t, &ocrcommon.RunResultSaver{}, srvs[0]) + + strmSrv := srvs[1].(*StreamService) + assert.Equal(t, registry, strmSrv.registry) + assert.Equal(t, StreamID("jobname"), strmSrv.id) + assert.Equal(t, jb.PipelineSpec, strmSrv.spec) + assert.NotNil(t, strmSrv.lggr) + assert.Equal(t, srvs[0], strmSrv.rrs) + }) + }) +} + +func Test_ValidatedStreamSpec(t *testing.T) { + var tt = []struct { + name string + toml string + assertion func(t *testing.T, os job.Job, err error) + }{ + { + name: "minimal stream spec", + toml: ` +type = "stream" +name = "voter-turnout" +schemaVersion = 1 +observationSource = """ +ds1 [type=bridge name=voter_turnout]; +ds1_parse [type=jsonparse path="one,two"]; +ds1_multiply [type=multiply times=1.23]; +ds1 -> ds1_parse -> ds1_multiply -> answer1; +answer1 [type=median index=0]; +""" +`, + assertion: func(t *testing.T, jb job.Job, err error) { + require.NoError(t, err) + assert.Equal(t, job.Type("stream"), jb.Type) + assert.Equal(t, uint32(1), jb.SchemaVersion) + assert.True(t, jb.Name.Valid) + assert.Equal(t, "voter-turnout", jb.Name.String) + }, + }, + { + name: "unparseable toml", + toml: `not toml`, + assertion: func(t *testing.T, jb job.Job, err error) { + assert.EqualError(t, err, "toml unmarshal error on job: toml: expected character =") + }, + }, + { + name: "invalid field type", + toml: ` +type = "stream" +name = "voter-turnout" +schemaVersion = "should be integer" +`, + assertion: func(t *testing.T, jb job.Job, err error) { + assert.EqualError(t, err, "toml unmarshal error on job: toml: cannot decode TOML string into struct field job.Job.SchemaVersion of type uint32") + }, + }, + { + name: "invalid fields", + toml: ` +type = "stream" +name = "voter-turnout" +notAValidField = "some value" +schemaVersion = 1 +`, + assertion: func(t *testing.T, jb job.Job, err error) { + assert.EqualError(t, err, "toml unmarshal error on job: strict mode: fields in the document are missing in the target struct") + }, + }, + { + name: "wrong type", + toml: ` +type = "not a valid type" +name = "voter-turnout" +schemaVersion = 1 +observationSource = """ +ds1 [type=bridge name=voter_turnout]; +ds1_parse [type=jsonparse path="one,two"]; +ds1_multiply [type=multiply times=1.23]; +ds1 -> ds1_parse -> ds1_multiply -> answer1; +answer1 [type=median index=0]; +""" +`, + assertion: func(t *testing.T, jb job.Job, err error) { + assert.EqualError(t, err, "unsupported type: \"not a valid type\"") + }, + }, + { + name: "error if missing name", + toml: ` +type = "stream" +schemaVersion = 1 +observationSource = """ +ds1 [type=bridge name=voter_turnout]; +ds1_parse [type=jsonparse path="one,two"]; +ds1_multiply [type=multiply times=1.23]; +ds1 -> ds1_parse -> ds1_multiply -> answer1; +answer1 [type=median index=0]; +""" +`, + assertion: func(t *testing.T, jb job.Job, err error) { + assert.EqualError(t, err, "jobs of type 'stream' require a non-blank name as stream ID") + }, + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + s, err := ValidatedStreamSpec(tc.toml) + tc.assertion(t, s, err) + }) + } +} diff --git a/core/services/streams/stream.go b/core/services/streams/stream.go new file mode 100644 index 00000000000..51535a0cb86 --- /dev/null +++ b/core/services/streams/stream.go @@ -0,0 +1,133 @@ +package streams + +import ( + "context" + "fmt" + "math/big" + "sync" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +type Runner interface { + ExecuteRun(ctx context.Context, spec pipeline.Spec, vars pipeline.Vars, l logger.Logger) (run *pipeline.Run, trrs pipeline.TaskRunResults, err error) + InitializePipeline(spec pipeline.Spec) (*pipeline.Pipeline, error) +} + +type RunResultSaver interface { + Save(run *pipeline.Run) +} + +type Stream interface { + Run(ctx context.Context) (*pipeline.Run, pipeline.TaskRunResults, error) +} + +type stream struct { + sync.RWMutex + id StreamID + lggr logger.Logger + spec *pipeline.Spec + runner Runner + rrs RunResultSaver +} + +func NewStream(lggr logger.Logger, id StreamID, spec pipeline.Spec, runner Runner, rrs RunResultSaver) Stream { + return newStream(lggr, id, spec, runner, rrs) +} + +func newStream(lggr logger.Logger, id StreamID, spec pipeline.Spec, runner Runner, rrs RunResultSaver) *stream { + return &stream{sync.RWMutex{}, id, lggr.Named("Stream").With("streamID", id), &spec, runner, rrs} +} + +func (s *stream) Run(ctx context.Context) (run *pipeline.Run, trrs pipeline.TaskRunResults, err error) { + run, trrs, err = s.executeRun(ctx) + + if err != nil { + return nil, nil, fmt.Errorf("Run failed: %w", err) + } + if s.rrs != nil { + s.rrs.Save(run) + } + + return +} + +// The context passed in here has a timeout of (ObservationTimeout + ObservationGracePeriod). +// Upon context cancellation, its expected that we return any usable values within ObservationGracePeriod. +func (s *stream) executeRun(ctx context.Context) (*pipeline.Run, pipeline.TaskRunResults, error) { + // the hot path here is to avoid parsing and use the pre-parsed, cached, pipeline + s.RLock() + initialize := s.spec.Pipeline == nil + s.RUnlock() + if initialize { + pipeline, err := s.spec.ParsePipeline() + if err != nil { + return nil, nil, fmt.Errorf("Run failed due to unparseable pipeline: %w", err) + } + + s.Lock() + if s.spec.Pipeline == nil { + s.spec.Pipeline = pipeline + // initialize it for the given runner + if _, err := s.runner.InitializePipeline(*s.spec); err != nil { + return nil, nil, fmt.Errorf("Run failed due to error while initializing pipeline: %w", err) + } + } + s.Unlock() + } + + vars := pipeline.NewVarsFrom(map[string]interface{}{ + "pipelineSpec": map[string]interface{}{ + "id": s.spec.ID, + }, + "stream": map[string]interface{}{ + "id": s.id, + }, + }) + + run, trrs, err := s.runner.ExecuteRun(ctx, *s.spec, vars, s.lggr) + if err != nil { + return nil, nil, fmt.Errorf("error executing run for spec ID %v: %w", s.spec.ID, err) + } + + return run, trrs, err +} + +// ExtractBigInt returns a result of a pipeline run that returns one single +// decimal result, as a *big.Int. +// This acts as a reference/example method, other methods can be implemented to +// extract any desired type that matches a particular pipeline run output. +// Returns error on parse errors: if results are wrong type +func ExtractBigInt(trrs pipeline.TaskRunResults) (*big.Int, error) { + var finaltrrs []pipeline.TaskRunResult + // pipeline.TaskRunResults comes ordered asc by index, this is guaranteed + // by the pipeline executor + for _, trr := range trrs { + if trr.IsTerminal() { + finaltrrs = append(finaltrrs, trr) + } + } + + if len(finaltrrs) != 1 { + return nil, fmt.Errorf("invalid number of results, expected: 1, got: %d", len(finaltrrs)) + } + res := finaltrrs[0].Result + if res.Error != nil { + return nil, res.Error + } + val, err := toBigInt(res.Value) + if err != nil { + return nil, fmt.Errorf("failed to parse BenchmarkPrice: %w", err) + } + return val, nil +} + +func toBigInt(val interface{}) (*big.Int, error) { + dec, err := utils.ToDecimal(val) + if err != nil { + return nil, err + } + return dec.BigInt(), nil +} diff --git a/core/services/streams/stream_registry.go b/core/services/streams/stream_registry.go new file mode 100644 index 00000000000..c79c6c4e043 --- /dev/null +++ b/core/services/streams/stream_registry.go @@ -0,0 +1,60 @@ +package streams + +import ( + "fmt" + "sync" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" +) + +type StreamID = string + +type Registry interface { + Get(streamID StreamID) (strm Stream, exists bool) + Register(streamID StreamID, spec pipeline.Spec, rrs ResultRunSaver) error + Unregister(streamID StreamID) +} + +type streamRegistry struct { + sync.RWMutex + lggr logger.Logger + runner Runner + streams map[StreamID]Stream +} + +func NewRegistry(lggr logger.Logger, runner Runner) Registry { + return newRegistry(lggr, runner) +} + +func newRegistry(lggr logger.Logger, runner Runner) *streamRegistry { + return &streamRegistry{ + sync.RWMutex{}, + lggr.Named("Registry"), + runner, + make(map[StreamID]Stream), + } +} + +func (s *streamRegistry) Get(streamID StreamID) (strm Stream, exists bool) { + s.RLock() + defer s.RUnlock() + strm, exists = s.streams[streamID] + return +} + +func (s *streamRegistry) Register(streamID StreamID, spec pipeline.Spec, rrs ResultRunSaver) error { + s.Lock() + defer s.Unlock() + if _, exists := s.streams[streamID]; exists { + return fmt.Errorf("stream already registered for id: %q", streamID) + } + s.streams[streamID] = NewStream(s.lggr, streamID, spec, s.runner, rrs) + return nil +} + +func (s *streamRegistry) Unregister(streamID StreamID) { + s.Lock() + defer s.Unlock() + delete(s.streams, streamID) +} diff --git a/core/services/streams/stream_registry_test.go b/core/services/streams/stream_registry_test.go new file mode 100644 index 00000000000..2c7c2bd6ecc --- /dev/null +++ b/core/services/streams/stream_registry_test.go @@ -0,0 +1,107 @@ +package streams + +import ( + "context" + "testing" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type mockStream struct { + run *pipeline.Run + trrs pipeline.TaskRunResults + err error +} + +func (m *mockStream) Run(ctx context.Context) (*pipeline.Run, pipeline.TaskRunResults, error) { + return m.run, m.trrs, m.err +} + +func Test_Registry(t *testing.T) { + lggr := logger.TestLogger(t) + runner := &mockRunner{} + + t.Run("Get", func(t *testing.T) { + sr := newRegistry(lggr, runner) + + sr.streams["foo"] = &mockStream{run: &pipeline.Run{ID: 1}} + sr.streams["bar"] = &mockStream{run: &pipeline.Run{ID: 2}} + sr.streams["baz"] = &mockStream{run: &pipeline.Run{ID: 3}} + + v, exists := sr.Get("foo") + assert.True(t, exists) + assert.Equal(t, sr.streams["foo"], v) + + v, exists = sr.Get("bar") + assert.True(t, exists) + assert.Equal(t, sr.streams["bar"], v) + + v, exists = sr.Get("baz") + assert.True(t, exists) + assert.Equal(t, sr.streams["baz"], v) + + v, exists = sr.Get("qux") + assert.Nil(t, v) + assert.False(t, exists) + }) + t.Run("Register", func(t *testing.T) { + sr := newRegistry(lggr, runner) + + t.Run("registers new stream", func(t *testing.T) { + assert.Len(t, sr.streams, 0) + err := sr.Register("foo", pipeline.Spec{ID: 32, DotDagSource: "source"}, nil) + require.NoError(t, err) + assert.Len(t, sr.streams, 1) + + v, exists := sr.Get("foo") + require.True(t, exists) + strm := v.(*stream) + assert.Equal(t, StreamID("foo"), strm.id) + assert.Equal(t, int32(32), strm.spec.ID) + }) + + t.Run("errors when attempt to re-register a stream with an existing ID", func(t *testing.T) { + assert.Len(t, sr.streams, 1) + err := sr.Register("foo", pipeline.Spec{ID: 33, DotDagSource: "source"}, nil) + require.Error(t, err) + assert.Len(t, sr.streams, 1) + assert.EqualError(t, err, "stream already registered for id: \"foo\"") + + v, exists := sr.Get("foo") + require.True(t, exists) + strm := v.(*stream) + assert.Equal(t, StreamID("foo"), strm.id) + assert.Equal(t, int32(32), strm.spec.ID) + }) + }) + t.Run("Unregister", func(t *testing.T) { + sr := newRegistry(lggr, runner) + + sr.streams["foo"] = &mockStream{run: &pipeline.Run{ID: 1}} + sr.streams["bar"] = &mockStream{run: &pipeline.Run{ID: 2}} + sr.streams["baz"] = &mockStream{run: &pipeline.Run{ID: 3}} + + t.Run("unregisters a stream", func(t *testing.T) { + assert.Len(t, sr.streams, 3) + + sr.Unregister("foo") + + assert.Len(t, sr.streams, 2) + _, exists := sr.streams["foo"] + assert.False(t, exists) + }) + t.Run("no effect when unregistering a non-existent stream", func(t *testing.T) { + assert.Len(t, sr.streams, 2) + + sr.Unregister("foo") + + assert.Len(t, sr.streams, 2) + _, exists := sr.streams["foo"] + assert.False(t, exists) + }) + }) +} diff --git a/core/services/streams/stream_test.go b/core/services/streams/stream_test.go new file mode 100644 index 00000000000..3a556411bc6 --- /dev/null +++ b/core/services/streams/stream_test.go @@ -0,0 +1,133 @@ +package streams + +import ( + "context" + "math/big" + "testing" + "time" + + "github.com/google/uuid" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" +) + +var UUID = uuid.New() + +type mockRunner struct { + p *pipeline.Pipeline + run *pipeline.Run + trrs pipeline.TaskRunResults + err error +} + +func (m *mockRunner) ExecuteRun(ctx context.Context, spec pipeline.Spec, vars pipeline.Vars, l logger.Logger) (run *pipeline.Run, trrs pipeline.TaskRunResults, err error) { + return m.run, m.trrs, m.err +} +func (m *mockRunner) InitializePipeline(spec pipeline.Spec) (p *pipeline.Pipeline, err error) { + return m.p, m.err +} +func (m *mockRunner) InsertFinishedRun(run *pipeline.Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) error { + return m.err +} + +type MockTask struct { + result pipeline.Result +} + +func (m *MockTask) Type() pipeline.TaskType { return "MockTask" } +func (m *MockTask) ID() int { return 0 } +func (m *MockTask) DotID() string { return "" } +func (m *MockTask) Run(ctx context.Context, lggr logger.Logger, vars pipeline.Vars, inputs []pipeline.Result) (pipeline.Result, pipeline.RunInfo) { + return m.result, pipeline.RunInfo{} +} +func (m *MockTask) Base() *pipeline.BaseTask { return nil } +func (m *MockTask) Outputs() []pipeline.Task { return nil } +func (m *MockTask) Inputs() []pipeline.TaskDependency { return nil } +func (m *MockTask) OutputIndex() int32 { return 0 } +func (m *MockTask) TaskTimeout() (time.Duration, bool) { return 0, false } +func (m *MockTask) TaskRetries() uint32 { return 0 } +func (m *MockTask) TaskMinBackoff() time.Duration { return 0 } +func (m *MockTask) TaskMaxBackoff() time.Duration { return 0 } + +func Test_Stream(t *testing.T) { + lggr := logger.TestLogger(t) + runner := &mockRunner{} + spec := pipeline.Spec{} + id := StreamID("stream-id-foo") + ctx := testutils.Context(t) + + t.Run("Run", func(t *testing.T) { + strm := newStream(lggr, id, spec, runner, nil) + + t.Run("errors with empty pipeline", func(t *testing.T) { + _, _, err := strm.Run(ctx) + assert.EqualError(t, err, "Run failed: Run failed due to unparseable pipeline: empty pipeline") + }) + + spec.DotDagSource = ` +succeed [type=memo value=42] +succeed; +` + + strm = newStream(lggr, id, spec, runner, nil) + + t.Run("executes the pipeline (success)", func(t *testing.T) { + runner.run = &pipeline.Run{ID: 42} + runner.trrs = []pipeline.TaskRunResult{pipeline.TaskRunResult{ID: UUID}} + runner.err = nil + + run, trrs, err := strm.Run(ctx) + assert.NoError(t, err) + + assert.Equal(t, int64(42), run.ID) + require.Len(t, trrs, 1) + assert.Equal(t, UUID, trrs[0].ID) + }) + t.Run("executes the pipeline (failure)", func(t *testing.T) { + runner.err = errors.New("something exploded") + + _, _, err := strm.Run(ctx) + require.Error(t, err) + + assert.EqualError(t, err, "Run failed: error executing run for spec ID 0: something exploded") + }) + }) +} + +func Test_ExtractBigInt(t *testing.T) { + t.Run("wrong number of inputs", func(t *testing.T) { + trrs := []pipeline.TaskRunResult{} + + _, err := ExtractBigInt(trrs) + assert.EqualError(t, err, "invalid number of results, expected: 1, got: 0") + }) + t.Run("wrong type", func(t *testing.T) { + trrs := []pipeline.TaskRunResult{ + { + Result: pipeline.Result{Value: []byte{1, 2, 3}}, + Task: &MockTask{}, + }, + } + + _, err := ExtractBigInt(trrs) + assert.EqualError(t, err, "failed to parse BenchmarkPrice: type []uint8 cannot be converted to decimal.Decimal ([1 2 3])") + }) + t.Run("correct inputs", func(t *testing.T) { + trrs := []pipeline.TaskRunResult{ + { + Result: pipeline.Result{Value: "122.345"}, + Task: &MockTask{}, + }, + } + + val, err := ExtractBigInt(trrs) + require.NoError(t, err) + assert.Equal(t, big.NewInt(122), val) + }) +} diff --git a/core/services/telemetry/manager_test.go b/core/services/telemetry/manager_test.go index 8564be8466f..23752151cd0 100644 --- a/core/services/telemetry/manager_test.go +++ b/core/services/telemetry/manager_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -22,7 +23,6 @@ import ( mocks3 "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" mocks2 "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/mocks" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func setupMockConfig(t *testing.T, useBatchSend bool) *mocks.TelemetryIngress { @@ -291,7 +291,7 @@ func TestCorrectEndpointRouting(t *testing.T) { func TestLegacyMode(t *testing.T) { tic := setupMockConfig(t, true) tic.On("Endpoints").Return(nil) - url, err := models.ParseURL("test.test") + url, err := commonconfig.ParseURL("test.test") require.NoError(t, err) tic.On("URL").Return(url.URL()) tic.On("ServerPubKey").Return("some-pub-key") diff --git a/core/services/vrf/delegate.go b/core/services/vrf/delegate.go index ba28e83bf3f..ecabbc09c71 100644 --- a/core/services/vrf/delegate.go +++ b/core/services/vrf/delegate.go @@ -76,7 +76,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { if jb.VRFSpec == nil || jb.PipelineSpec == nil { return nil, errors.Errorf("vrf.Delegate expects a VRFSpec and PipelineSpec to be present, got %+v", jb) } - pl, err := jb.PipelineSpec.Pipeline() + pl, err := jb.PipelineSpec.ParsePipeline() if err != nil { return nil, err } diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index 591ca3e9508..8ad88d7b73b 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -693,7 +693,7 @@ func Test_VRFV2PlusServiceFailsWhenVRFOwnerProvided(t *testing.T) { vs := testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{ VRFVersion: vrfcommon.V2Plus, PublicKey: vuni.vrfkey.PublicKey.String(), - FromAddresses: []string{string(vuni.submitter.Hex())}, + FromAddresses: []string{vuni.submitter.Hex()}, GasLanePrice: chain.Config().EVM().GasEstimator().PriceMax(), }) toml := "vrfOwnerAddress=\"0xF62fEFb54a0af9D32CDF0Db21C52710844c7eddb\"\n" + vs.Toml() diff --git a/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface.go b/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface.go index 3603230fea0..24639af2f0d 100644 --- a/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface.go +++ b/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface.go @@ -35,7 +35,7 @@ func toGethLog(log types.Log) types.Log { return types.Log{ Address: log.Address, Topics: log.Topics, - Data: []byte(log.Data), + Data: log.Data, BlockNumber: log.BlockNumber, TxHash: log.TxHash, TxIndex: log.TxIndex, diff --git a/core/services/vrf/v1/integration_test.go b/core/services/vrf/v1/integration_test.go index 3e9cfbe0870..b10ca160858 100644 --- a/core/services/vrf/v1/integration_test.go +++ b/core/services/vrf/v1/integration_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" @@ -28,7 +29,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrftesthelpers" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" ) @@ -133,7 +133,7 @@ func TestIntegration_VRF_WithBHS(t *testing.T) { c.EVM[0].BlockBackfillDepth = ptr[uint32](500) c.Feature.LogPoller = ptr(true) c.EVM[0].FinalityDepth = ptr[uint32](2) - c.EVM[0].LogPollInterval = models.MustNewDuration(time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(time.Second) c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) key := cltest.MustGenerateRandomKey(t) diff --git a/core/services/vrf/v2/bhs_feeder_test.go b/core/services/vrf/v2/bhs_feeder_test.go index 31a4ff815a9..a02eea75757 100644 --- a/core/services/vrf/v2/bhs_feeder_test.go +++ b/core/services/vrf/v2/bhs_feeder_test.go @@ -4,6 +4,9 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -11,9 +14,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrftesthelpers" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - - "github.com/stretchr/testify/require" ) func TestStartHeartbeats(t *testing.T) { @@ -56,7 +56,7 @@ func TestStartHeartbeats(t *testing.T) { c.Feature.LogPoller = ptr(true) c.EVM[0].FinalityDepth = ptr[uint32](2) c.EVM[0].GasEstimator.LimitDefault = ptr(uint32(gasLimit)) - c.EVM[0].LogPollInterval = models.MustNewDuration(time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(time.Second) }) heartbeatPeriod := 5 * time.Second diff --git a/core/services/vrf/v2/integration_helpers_test.go b/core/services/vrf/v2/integration_helpers_test.go index b5f6a095cff..47d0089ade6 100644 --- a/core/services/vrf/v2/integration_helpers_test.go +++ b/core/services/vrf/v2/integration_helpers_test.go @@ -16,6 +16,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" @@ -35,7 +36,6 @@ import ( v22 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrftesthelpers" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -74,7 +74,7 @@ func testSingleConsumerHappyPath( })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1, key2) @@ -208,7 +208,7 @@ func testMultipleConsumersNeedBHS( simulatedOverrides(t, assets.GWei(10), keySpecificOverrides...)(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) c.EVM[0].FinalityDepth = ptr[uint32](2) }) keys = append(keys, ownerKey, vrfKey) @@ -356,7 +356,7 @@ func testMultipleConsumersNeedTrustedBHS( c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.EVM[0].GasEstimator.LimitDefault = ptr(uint32(5_000_000)) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) c.EVM[0].FinalityDepth = ptr[uint32](2) }) keys = append(keys, ownerKey, vrfKey) @@ -543,7 +543,7 @@ func testSingleConsumerHappyPathBatchFulfillment( c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1) @@ -647,7 +647,7 @@ func testSingleConsumerNeedsTopUp( })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key) @@ -753,7 +753,7 @@ func testBlockHeaderFeeder( })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) c.EVM[0].FinalityDepth = ptr[uint32](2) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, vrfKey, bhfKey) @@ -912,7 +912,7 @@ func testSingleConsumerForcedFulfillment( })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1, key2) @@ -1075,7 +1075,7 @@ func testSingleConsumerEIP150( c.EVM[0].GasEstimator.LimitDefault = ptr(uint32(3.5e6)) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1) consumer := uni.vrfConsumers[0] @@ -1145,7 +1145,7 @@ func testSingleConsumerEIP150Revert( c.EVM[0].GasEstimator.LimitDefault = ptr(uint32(gasLimit)) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1) consumer := uni.vrfConsumers[0] @@ -1210,7 +1210,7 @@ func testSingleConsumerBigGasCallbackSandwich( c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](5_000_000) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1) consumer := uni.vrfConsumers[0] @@ -1332,7 +1332,7 @@ func testSingleConsumerMultipleGasLanes( c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](5_000_000) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, cheapKey, expensiveKey) @@ -1449,7 +1449,7 @@ func testSingleConsumerAlwaysRevertingCallbackStillFulfilled( })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key) consumer := uni.reverter @@ -1522,7 +1522,7 @@ func testConsumerProxyHappyPath( })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1, key2) consumerOwner := uni.neil @@ -1648,7 +1648,7 @@ func testMaliciousConsumer( c.EVM[0].GasEstimator.FeeCapDefault = assets.GWei(1) c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) carol := uni.vrfConsumers[0] diff --git a/core/services/vrf/v2/integration_v2_plus_test.go b/core/services/vrf/v2/integration_v2_plus_test.go index fb47d84ed7a..e5eed6f09bc 100644 --- a/core/services/vrf/v2/integration_v2_plus_test.go +++ b/core/services/vrf/v2/integration_v2_plus_test.go @@ -16,6 +16,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -50,7 +51,6 @@ import ( v22 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrftesthelpers" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) type coordinatorV2PlusUniverse struct { @@ -1147,7 +1147,7 @@ func TestVRFV2PlusIntegration_Migration(t *testing.T) { c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](5_000_000) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1) diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index dee69c9abef..d415793ede4 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -30,6 +30,7 @@ import ( "github.com/jmoiron/sqlx" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" @@ -82,7 +83,6 @@ import ( v22 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrftesthelpers" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -1227,7 +1227,7 @@ func TestVRFV2Integration_Wrapper_High_Gas(t *testing.T) { c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](3_500_000) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) ownerKey := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2Universe(t, ownerKey, 1) @@ -1466,13 +1466,13 @@ func simulatedOverrides(t *testing.T, defaultGasPrice *assets.Wei, ks ...toml.Ke c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](3_500_000) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) c.EVM[0].HeadTracker.MaxBufferSize = ptr[uint32](100) - c.EVM[0].HeadTracker.SamplingInterval = models.MustNewDuration(0) // Head sampling disabled + c.EVM[0].HeadTracker.SamplingInterval = commonconfig.MustNewDuration(0) // Head sampling disabled - c.EVM[0].Transactions.ResendAfterThreshold = models.MustNewDuration(0) - c.EVM[0].Transactions.ReaperThreshold = models.MustNewDuration(100 * time.Millisecond) + c.EVM[0].Transactions.ResendAfterThreshold = commonconfig.MustNewDuration(0) + c.EVM[0].Transactions.ReaperThreshold = commonconfig.MustNewDuration(100 * time.Millisecond) c.EVM[0].FinalityDepth = ptr[uint32](15) c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) diff --git a/core/services/webhook/delegate.go b/core/services/webhook/delegate.go index 237245b81c9..7e6aab0bb07 100644 --- a/core/services/webhook/delegate.go +++ b/core/services/webhook/delegate.go @@ -21,6 +21,7 @@ type ( webhookJobRunner *webhookJobRunner externalInitiatorManager ExternalInitiatorManager lggr logger.Logger + stopCh services.StopChan } JobRunner interface { @@ -36,6 +37,7 @@ func NewDelegate(runner pipeline.Runner, externalInitiatorManager ExternalInitia externalInitiatorManager: externalInitiatorManager, webhookJobRunner: newWebhookJobRunner(runner, lggr), lggr: lggr, + stopCh: make(services.StopChan), } } @@ -49,7 +51,9 @@ func (d *Delegate) JobType() job.Type { func (d *Delegate) BeforeJobCreated(spec job.Job) {} func (d *Delegate) AfterJobCreated(jb job.Job) { - err := d.externalInitiatorManager.Notify(*jb.WebhookSpecID) + ctx, cancel := d.stopCh.NewCtx() + defer cancel() + err := d.externalInitiatorManager.Notify(ctx, *jb.WebhookSpecID) if err != nil { d.lggr.Errorw("Webhook delegate AfterJobCreated errored", "err", err, @@ -59,7 +63,9 @@ func (d *Delegate) AfterJobCreated(jb job.Job) { } func (d *Delegate) BeforeJobDeleted(spec job.Job) { - err := d.externalInitiatorManager.DeleteJob(*spec.WebhookSpecID) + ctx, cancel := d.stopCh.NewCtx() + defer cancel() + err := d.externalInitiatorManager.DeleteJob(ctx, *spec.WebhookSpecID) if err != nil { d.lggr.Errorw("Webhook delegate OnDeleteJob errored", "err", err, diff --git a/core/services/webhook/external_initiator_manager.go b/core/services/webhook/external_initiator_manager.go index 01edf82b114..0c035abde7a 100644 --- a/core/services/webhook/external_initiator_manager.go +++ b/core/services/webhook/external_initiator_manager.go @@ -2,6 +2,7 @@ package webhook import ( "bytes" + "context" "encoding/json" "fmt" "net/http" @@ -24,8 +25,8 @@ import ( // ExternalInitiatorManager manages HTTP requests to remote external initiators type ExternalInitiatorManager interface { - Notify(webhookSpecID int32) error - DeleteJob(webhookSpecID int32) error + Notify(ctx context.Context, webhookSpecID int32) error + DeleteJob(ctx context.Context, webhookSpecID int32) error FindExternalInitiatorByName(name string) (bridges.ExternalInitiator, error) } @@ -52,7 +53,7 @@ func NewExternalInitiatorManager(db *sqlx.DB, httpclient HTTPClient, lggr logger // Notify sends a POST notification to the External Initiator // responsible for initiating the Job Spec. -func (m externalInitiatorManager) Notify(webhookSpecID int32) error { +func (m externalInitiatorManager) Notify(ctx context.Context, webhookSpecID int32) error { eiWebhookSpecs, jobID, err := m.Load(webhookSpecID) if err != nil { return err @@ -71,7 +72,7 @@ func (m externalInitiatorManager) Notify(webhookSpecID int32) error { if err != nil { return errors.Wrap(err, "new Job Spec notification") } - req, err := newNotifyHTTPRequest(buf, ei) + req, err := newNotifyHTTPRequest(ctx, buf, ei) if err != nil { return errors.Wrap(err, "creating notify HTTP request") } @@ -136,7 +137,7 @@ func (m externalInitiatorManager) eagerLoadExternalInitiator(q pg.Queryer, txs [ return nil } -func (m externalInitiatorManager) DeleteJob(webhookSpecID int32) error { +func (m externalInitiatorManager) DeleteJob(ctx context.Context, webhookSpecID int32) error { eiWebhookSpecs, jobID, err := m.Load(webhookSpecID) if err != nil { return err @@ -147,7 +148,7 @@ func (m externalInitiatorManager) DeleteJob(webhookSpecID int32) error { continue } - req, err := newDeleteJobFromExternalInitiatorHTTPRequest(ei, jobID) + req, err := newDeleteJobFromExternalInitiatorHTTPRequest(ctx, ei, jobID) if err != nil { return errors.Wrap(err, "creating delete HTTP request") } @@ -178,8 +179,8 @@ type JobSpecNotice struct { Params models.JSON `json:"params,omitempty"` } -func newNotifyHTTPRequest(buf []byte, ei bridges.ExternalInitiator) (*http.Request, error) { - req, err := http.NewRequest(http.MethodPost, ei.URL.String(), bytes.NewBuffer(buf)) +func newNotifyHTTPRequest(ctx context.Context, buf []byte, ei bridges.ExternalInitiator) (*http.Request, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodPost, ei.URL.String(), bytes.NewBuffer(buf)) if err != nil { return nil, err } @@ -187,10 +188,10 @@ func newNotifyHTTPRequest(buf []byte, ei bridges.ExternalInitiator) (*http.Reque return req, nil } -func newDeleteJobFromExternalInitiatorHTTPRequest(ei bridges.ExternalInitiator, jobID uuid.UUID) (*http.Request, error) { +func newDeleteJobFromExternalInitiatorHTTPRequest(ctx context.Context, ei bridges.ExternalInitiator, jobID uuid.UUID) (*http.Request, error) { url := fmt.Sprintf("%s/%s", ei.URL.String(), jobID) - req, err := http.NewRequest(http.MethodDelete, url, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodDelete, url, nil) if err != nil { return nil, err } @@ -208,8 +209,8 @@ type NullExternalInitiatorManager struct{} var _ ExternalInitiatorManager = (*NullExternalInitiatorManager)(nil) -func (NullExternalInitiatorManager) Notify(int32) error { return nil } -func (NullExternalInitiatorManager) DeleteJob(int32) error { return nil } +func (NullExternalInitiatorManager) Notify(context.Context, int32) error { return nil } +func (NullExternalInitiatorManager) DeleteJob(context.Context, int32) error { return nil } func (NullExternalInitiatorManager) FindExternalInitiatorByName(name string) (bridges.ExternalInitiator, error) { return bridges.ExternalInitiator{}, nil } diff --git a/core/services/webhook/external_initiator_manager_test.go b/core/services/webhook/external_initiator_manager_test.go index 568008c2117..553455ebe63 100644 --- a/core/services/webhook/external_initiator_manager_test.go +++ b/core/services/webhook/external_initiator_manager_test.go @@ -12,7 +12,9 @@ import ( "github.com/stretchr/testify/require" "github.com/tidwall/gjson" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" _ "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -57,6 +59,7 @@ func Test_ExternalInitiatorManager_Load(t *testing.T) { } func Test_ExternalInitiatorManager_Notify(t *testing.T) { + ctx := tests.Context(t) db := pgtest.NewSqlxDB(t) cfg := pgtest.NewQConfig(true) borm := newBridgeORM(t, db, cfg) @@ -78,7 +81,7 @@ func Test_ExternalInitiatorManager_Notify(t *testing.T) { eim := webhook.NewExternalInitiatorManager(db, client, logger.TestLogger(t), cfg) // Does nothing with no EI - require.NoError(t, eim.Notify(webhookSpecNoEIs.ID)) + require.NoError(t, eim.Notify(ctx, webhookSpecNoEIs.ID)) client.On("Do", mock.MatchedBy(func(r *http.Request) bool { body, err := r.GetBody() @@ -92,10 +95,11 @@ func Test_ExternalInitiatorManager_Notify(t *testing.T) { return r.Method == "POST" && r.URL.String() == eiWithURL.URL.String() && r.Header["Content-Type"][0] == "application/json" && r.Header["X-Chainlink-Ea-Accesskey"][0] == "token" && r.Header["X-Chainlink-Ea-Secret"][0] == "secret" })).Once().Return(&http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(""))}, nil) - require.NoError(t, eim.Notify(webhookSpecTwoEIs.ID)) + require.NoError(t, eim.Notify(ctx, webhookSpecTwoEIs.ID)) } func Test_ExternalInitiatorManager_DeleteJob(t *testing.T) { + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := pgtest.NewQConfig(true) borm := newBridgeORM(t, db, cfg) @@ -117,11 +121,11 @@ func Test_ExternalInitiatorManager_DeleteJob(t *testing.T) { eim := webhook.NewExternalInitiatorManager(db, client, logger.TestLogger(t), cfg) // Does nothing with no EI - require.NoError(t, eim.DeleteJob(webhookSpecNoEIs.ID)) + require.NoError(t, eim.DeleteJob(ctx, webhookSpecNoEIs.ID)) client.On("Do", mock.MatchedBy(func(r *http.Request) bool { expectedURL := fmt.Sprintf("%s/%s", eiWithURL.URL.String(), jb.ExternalJobID.String()) return r.Method == "DELETE" && r.URL.String() == expectedURL && r.Header["Content-Type"][0] == "application/json" && r.Header["X-Chainlink-Ea-Accesskey"][0] == "token" && r.Header["X-Chainlink-Ea-Secret"][0] == "secret" })).Once().Return(&http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(""))}, nil) - require.NoError(t, eim.DeleteJob(webhookSpecTwoEIs.ID)) + require.NoError(t, eim.DeleteJob(ctx, webhookSpecTwoEIs.ID)) } diff --git a/core/services/webhook/mocks/external_initiator_manager.go b/core/services/webhook/mocks/external_initiator_manager.go index 6c061f5412d..010b6f8db0a 100644 --- a/core/services/webhook/mocks/external_initiator_manager.go +++ b/core/services/webhook/mocks/external_initiator_manager.go @@ -3,7 +3,10 @@ package mocks import ( + context "context" + bridges "github.com/smartcontractkit/chainlink/v2/core/bridges" + mock "github.com/stretchr/testify/mock" ) @@ -12,17 +15,17 @@ type ExternalInitiatorManager struct { mock.Mock } -// DeleteJob provides a mock function with given fields: webhookSpecID -func (_m *ExternalInitiatorManager) DeleteJob(webhookSpecID int32) error { - ret := _m.Called(webhookSpecID) +// DeleteJob provides a mock function with given fields: ctx, webhookSpecID +func (_m *ExternalInitiatorManager) DeleteJob(ctx context.Context, webhookSpecID int32) error { + ret := _m.Called(ctx, webhookSpecID) if len(ret) == 0 { panic("no return value specified for DeleteJob") } var r0 error - if rf, ok := ret.Get(0).(func(int32) error); ok { - r0 = rf(webhookSpecID) + if rf, ok := ret.Get(0).(func(context.Context, int32) error); ok { + r0 = rf(ctx, webhookSpecID) } else { r0 = ret.Error(0) } @@ -58,17 +61,17 @@ func (_m *ExternalInitiatorManager) FindExternalInitiatorByName(name string) (br return r0, r1 } -// Notify provides a mock function with given fields: webhookSpecID -func (_m *ExternalInitiatorManager) Notify(webhookSpecID int32) error { - ret := _m.Called(webhookSpecID) +// Notify provides a mock function with given fields: ctx, webhookSpecID +func (_m *ExternalInitiatorManager) Notify(ctx context.Context, webhookSpecID int32) error { + ret := _m.Called(ctx, webhookSpecID) if len(ret) == 0 { panic("no return value specified for Notify") } var r0 error - if rf, ok := ret.Get(0).(func(int32) error); ok { - r0 = rf(webhookSpecID) + if rf, ok := ret.Get(0).(func(context.Context, int32) error); ok { + r0 = rf(ctx, webhookSpecID) } else { r0 = ret.Error(0) } diff --git a/core/sessions/ldapauth/helpers_test.go b/core/sessions/ldapauth/helpers_test.go index 3566ea84380..5c19afd17d3 100644 --- a/core/sessions/ldapauth/helpers_test.go +++ b/core/sessions/ldapauth/helpers_test.go @@ -5,11 +5,11 @@ import ( "github.com/jmoiron/sqlx" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) // Returns an instantiated ldapAuthenticator struct without validation for testing @@ -66,16 +66,16 @@ func (t *TestConfig) ServerTLS() bool { return false } -func (t *TestConfig) SessionTimeout() models.Duration { - return models.MustMakeDuration(time.Duration(0)) +func (t *TestConfig) SessionTimeout() commonconfig.Duration { + return *commonconfig.MustNewDuration(time.Duration(0)) } func (t *TestConfig) QueryTimeout() time.Duration { return time.Duration(0) } -func (t *TestConfig) UserAPITokenDuration() models.Duration { - return models.MustMakeDuration(time.Duration(0)) +func (t *TestConfig) UserAPITokenDuration() commonconfig.Duration { + return *commonconfig.MustNewDuration(time.Duration(0)) } func (t *TestConfig) BaseUserAttr() string { @@ -122,10 +122,10 @@ func (t *TestConfig) UserApiTokenEnabled() bool { return true } -func (t *TestConfig) UpstreamSyncInterval() models.Duration { - return models.MustMakeDuration(time.Duration(0)) +func (t *TestConfig) UpstreamSyncInterval() commonconfig.Duration { + return *commonconfig.MustNewDuration(time.Duration(0)) } -func (t *TestConfig) UpstreamSyncRateLimit() models.Duration { - return models.MustMakeDuration(time.Duration(0)) +func (t *TestConfig) UpstreamSyncRateLimit() commonconfig.Duration { + return *commonconfig.MustNewDuration(time.Duration(0)) } diff --git a/core/sessions/localauth/reaper.go b/core/sessions/localauth/reaper.go index 48112456418..eef884367aa 100644 --- a/core/sessions/localauth/reaper.go +++ b/core/sessions/localauth/reaper.go @@ -4,9 +4,9 @@ import ( "database/sql" "time" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) type sessionReaper struct { @@ -16,8 +16,8 @@ type sessionReaper struct { } type SessionReaperConfig interface { - SessionTimeout() models.Duration - SessionReaperExpiration() models.Duration + SessionTimeout() commonconfig.Duration + SessionReaperExpiration() commonconfig.Duration } // NewSessionReaper creates a reaper that cleans stale sessions from the store. diff --git a/core/sessions/localauth/reaper_test.go b/core/sessions/localauth/reaper_test.go index 43a263d0321..fa9d882f743 100644 --- a/core/sessions/localauth/reaper_test.go +++ b/core/sessions/localauth/reaper_test.go @@ -4,27 +4,28 @@ import ( "testing" "time" + "github.com/onsi/gomega" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/sessions" "github.com/smartcontractkit/chainlink/v2/core/sessions/localauth" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - - "github.com/onsi/gomega" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) type sessionReaperConfig struct{} -func (c sessionReaperConfig) SessionTimeout() models.Duration { - return models.MustMakeDuration(42 * time.Second) +func (c sessionReaperConfig) SessionTimeout() commonconfig.Duration { + return *commonconfig.MustNewDuration(42 * time.Second) } -func (c sessionReaperConfig) SessionReaperExpiration() models.Duration { - return models.MustMakeDuration(142 * time.Second) +func (c sessionReaperConfig) SessionReaperExpiration() commonconfig.Duration { + return *commonconfig.MustNewDuration(142 * time.Second) } func TestSessionReaper_ReapSessions(t *testing.T) { diff --git a/core/store/migrate/migrate_test.go b/core/store/migrate/migrate_test.go index 10c698e96fd..56d1fe41eb5 100644 --- a/core/store/migrate/migrate_test.go +++ b/core/store/migrate/migrate_test.go @@ -516,6 +516,31 @@ func TestDatabaseBackFillWithMigration202(t *testing.T) { } } +func TestNoTriggers(t *testing.T) { + _, db := heavyweight.FullTestDBEmptyV2(t, nil) + + assert_num_triggers := func(expected int) { + + row := db.DB.QueryRow("select count(*) from information_schema.triggers") + var count int + err := row.Scan(&count) + + require.NoError(t, err) + require.Equal(t, expected, count) + } + + // if you find yourself here and are tempted to add a trigger, something has gone wrong + // and you should talk to the foundations team before proceeding + assert_num_triggers(0) + + // version prior to removal of all triggers + v := 217 + err := goose.UpTo(db.DB, migrationDir, int64(v)) + require.NoError(t, err) + assert_num_triggers(1) + +} + func BenchmarkBackfillingRecordsWithMigration202(b *testing.B) { previousMigration := int64(201) backfillMigration := int64(202) diff --git a/core/store/migrate/migrations/0216_drop_terra_state_transition_trigger.sql b/core/store/migrate/migrations/0216_drop_terra_state_transition_trigger.sql new file mode 100644 index 00000000000..77a7c04a4f6 --- /dev/null +++ b/core/store/migrate/migrations/0216_drop_terra_state_transition_trigger.sql @@ -0,0 +1,27 @@ +-- +goose Up + +-- +goose StatementBegin +DROP FUNCTION IF EXISTS PUBLIC.check_terra_msg_state_transition; +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin + +CREATE OR REPLACE FUNCTION PUBLIC.check_terra_msg_state_transition() RETURNS TRIGGER AS $$ +DECLARE +state_transition_map jsonb := json_build_object( + 'unstarted', json_build_object('errored', true, 'started', true), + 'started', json_build_object('errored', true, 'broadcasted', true), + 'broadcasted', json_build_object('errored', true, 'confirmed', true)); +BEGIN + IF NOT state_transition_map ? OLD.state THEN + RAISE EXCEPTION 'Invalid from state %. Valid from states %', OLD.state, state_transition_map; +END IF; + IF NOT state_transition_map->OLD.state ? NEW.state THEN + RAISE EXCEPTION 'Invalid state transition from % to %. Valid to states %', OLD.state, NEW.state, state_transition_map->OLD.state; +END IF; +RETURN NEW; +END +$$ LANGUAGE plpgsql; + +-- +goose StatementEnd \ No newline at end of file diff --git a/core/store/migrate/migrations/0217_drop_unused_job_triggers.sql b/core/store/migrate/migrations/0217_drop_unused_job_triggers.sql new file mode 100644 index 00000000000..a59e5d5b225 --- /dev/null +++ b/core/store/migrate/migrations/0217_drop_unused_job_triggers.sql @@ -0,0 +1,48 @@ +-- +goose Up +-- +goose StatementBegin +DROP TRIGGER IF EXISTS notify_job_created ON PUBLIC.jobs; +DROP FUNCTION IF EXISTS PUBLIC.notifyjobcreated(); + +DROP TRIGGER IF EXISTS notify_job_deleted ON PUBLIC.jobs; +DROP FUNCTION IF EXISTS PUBLIC.notifyjobdeleted(); + +DROP TRIGGER IF EXISTS notify_pipeline_run_started ON PUBLIC.pipeline_runs; +DROP FUNCTION IF EXISTS PUBLIC.notifypipelinerunstarted(); +-- +goose StatementEnd + + +-- +goose Down +-- +goose StatementBegin +CREATE FUNCTION PUBLIC.notifyjobcreated() RETURNS trigger + LANGUAGE plpgsql + AS $$ + BEGIN + PERFORM pg_notify('insert_on_jobs', NEW.id::text); + RETURN NEW; + END + $$; +CREATE TRIGGER notify_job_created AFTER INSERT ON PUBLIC.jobs FOR EACH ROW EXECUTE PROCEDURE PUBLIC.notifyjobcreated(); + +CREATE FUNCTION PUBLIC.notifyjobdeleted() RETURNS trigger + LANGUAGE plpgsql + AS $$ + BEGIN + PERFORM pg_notify('delete_from_jobs', OLD.id::text); + RETURN OLD; + END + $$; +CREATE TRIGGER notify_job_deleted AFTER DELETE ON PUBLIC.jobs FOR EACH ROW EXECUTE PROCEDURE PUBLIC.notifyjobdeleted(); + +CREATE FUNCTION PUBLIC.notifypipelinerunstarted() RETURNS trigger + LANGUAGE plpgsql + AS $$ + BEGIN + IF NEW.finished_at IS NULL THEN + PERFORM pg_notify('pipeline_run_started', NEW.id::text); + END IF; + RETURN NEW; + END + $$; +CREATE TRIGGER notify_pipeline_run_started AFTER INSERT ON PUBLIC.pipeline_runs FOR EACH ROW EXECUTE PROCEDURE PUBLIC.notifypipelinerunstarted(); + +-- +goose StatementEnd diff --git a/core/store/migrate/migrations/0218_drop_log_topic_trigger.sql b/core/store/migrate/migrations/0218_drop_log_topic_trigger.sql new file mode 100644 index 00000000000..ea80cccd2b5 --- /dev/null +++ b/core/store/migrate/migrations/0218_drop_log_topic_trigger.sql @@ -0,0 +1,27 @@ +-- +goose Up +-- +goose StatementBegin +DROP TRIGGER IF EXISTS notify_insert_on_logs_topics ON EVM.logs; +DROP FUNCTION IF EXISTS evm.notifysavedlogtopics(); + +-- +goose StatementEnd + + +-- +goose Down +-- +goose StatementBegin + +CREATE FUNCTION evm.notifysavedlogtopics() RETURNS trigger + LANGUAGE plpgsql +AS $$ +BEGIN + PERFORM pg_notify( + 'evm.insert_on_logs'::text, + -- hex encoded address plus comma separated list of hex encoded topic values + -- e.g. "
:," + encode(NEW.address, 'hex') || ':' || array_to_string(array(SELECT encode(unnest(NEW.topics), 'hex')), ',') + ); + RETURN NULL; +END +$$; + +CREATE TRIGGER notify_insert_on_logs_topics AFTER INSERT ON evm.logs FOR EACH ROW EXECUTE PROCEDURE evm.notifysavedlogtopics(); +-- +goose StatementEnd diff --git a/core/store/migrate/migrations/0219_drop_notifytxinsertion.sql b/core/store/migrate/migrations/0219_drop_notifytxinsertion.sql new file mode 100644 index 00000000000..9569fa48728 --- /dev/null +++ b/core/store/migrate/migrations/0219_drop_notifytxinsertion.sql @@ -0,0 +1,16 @@ +-- +goose Up +-- +goose StatementBegin +DROP FUNCTION IF EXISTS evm.notifytxinsertion(); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +CREATE OR REPLACE FUNCTION evm.notifytxinsertion() RETURNS trigger + LANGUAGE plpgsql + AS $$ + BEGIN + PERFORM pg_notify('evm.insert_on_txes'::text, encode(NEW.from_address, 'hex')); + RETURN NULL; + END + $$; +-- +goose StatementEnd diff --git a/core/store/migrate/migrations/0220_stream_specs.sql b/core/store/migrate/migrations/0220_stream_specs.sql new file mode 100644 index 00000000000..f446928702c --- /dev/null +++ b/core/store/migrate/migrations/0220_stream_specs.sql @@ -0,0 +1,40 @@ +-- +goose Up +ALTER TABLE + jobs +DROP + CONSTRAINT chk_only_one_spec, +ADD + CONSTRAINT chk_specs CHECK ( + num_nonnulls( + ocr_oracle_spec_id, ocr2_oracle_spec_id, + direct_request_spec_id, flux_monitor_spec_id, + keeper_spec_id, cron_spec_id, webhook_spec_id, + vrf_spec_id, blockhash_store_spec_id, + block_header_feeder_spec_id, bootstrap_spec_id, + gateway_spec_id, + legacy_gas_station_server_spec_id, + legacy_gas_station_sidecar_spec_id, + eal_spec_id, + CASE "type" WHEN 'stream' THEN 1 ELSE NULL END -- 'stream' type lacks a spec but should not cause validation to fail + ) = 1 + ); + +-- +goose Down +ALTER TABLE + jobs +DROP + CONSTRAINT chk_specs, +ADD + CONSTRAINT chk_only_one_spec CHECK ( + num_nonnulls( + ocr_oracle_spec_id, ocr2_oracle_spec_id, + direct_request_spec_id, flux_monitor_spec_id, + keeper_spec_id, cron_spec_id, webhook_spec_id, + vrf_spec_id, blockhash_store_spec_id, + block_header_feeder_spec_id, bootstrap_spec_id, + gateway_spec_id, + legacy_gas_station_server_spec_id, + legacy_gas_station_sidecar_spec_id, + eal_spec_id + ) = 1 + ); diff --git a/core/store/models/common.go b/core/store/models/common.go index 93cc708fe0b..e446481ff64 100644 --- a/core/store/models/common.go +++ b/core/store/models/common.go @@ -197,119 +197,6 @@ func (c Cron) String() string { return string(c) } -// Duration is a non-negative time duration. -type Duration struct{ d time.Duration } - -func MakeDuration(d time.Duration) (Duration, error) { - if d < time.Duration(0) { - return Duration{}, fmt.Errorf("cannot make negative time duration: %s", d) - } - return Duration{d: d}, nil -} - -func ParseDuration(s string) (Duration, error) { - d, err := time.ParseDuration(s) - if err != nil { - return Duration{}, err - } - - return MakeDuration(d) -} - -func MustMakeDuration(d time.Duration) Duration { - rv, err := MakeDuration(d) - if err != nil { - panic(err) - } - return rv -} - -func MustNewDuration(d time.Duration) *Duration { - rv := MustMakeDuration(d) - return &rv -} - -// Duration returns the value as the standard time.Duration value. -func (d Duration) Duration() time.Duration { - return d.d -} - -// Before returns the time d units before time t -func (d Duration) Before(t time.Time) time.Time { - return t.Add(-d.Duration()) -} - -// Shorter returns true if and only if d is shorter than od. -func (d Duration) Shorter(od Duration) bool { return d.d < od.d } - -// IsInstant is true if and only if d is of duration 0 -func (d Duration) IsInstant() bool { return d.d == 0 } - -// String returns a string representing the duration in the form "72h3m0.5s". -// Leading zero units are omitted. As a special case, durations less than one -// second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure -// that the leading digit is non-zero. The zero duration formats as 0s. -func (d Duration) String() string { - return d.Duration().String() -} - -// MarshalJSON implements the json.Marshaler interface. -func (d Duration) MarshalJSON() ([]byte, error) { - return json.Marshal(d.String()) -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -func (d *Duration) UnmarshalJSON(input []byte) error { - var txt string - err := json.Unmarshal(input, &txt) - if err != nil { - return err - } - v, err := time.ParseDuration(string(txt)) - if err != nil { - return err - } - *d, err = MakeDuration(v) - if err != nil { - return err - } - return nil -} - -func (d *Duration) Scan(v interface{}) (err error) { - switch tv := v.(type) { - case int64: - *d, err = MakeDuration(time.Duration(tv)) - return err - default: - return errors.Errorf(`don't know how to parse "%s" of type %T as a `+ - `models.Duration`, tv, tv) - } -} - -func (d Duration) Value() (driver.Value, error) { - return int64(d.d), nil -} - -// MarshalText implements the text.Marshaler interface. -func (d Duration) MarshalText() ([]byte, error) { - return []byte(d.d.String()), nil -} - -// UnmarshalText implements the text.Unmarshaler interface. -func (d *Duration) UnmarshalText(input []byte) error { - v, err := time.ParseDuration(string(input)) - if err != nil { - return err - } - pd, err := MakeDuration(v) - if err != nil { - return err - } - *d = pd - return nil -} - // Interval represents a time.Duration stored as a Postgres interval type type Interval time.Duration @@ -513,60 +400,6 @@ func (s Sha256Hash) Value() (driver.Value, error) { return b, nil } -// URL extends url.URL to implement encoding.TextMarshaler. -type URL url.URL - -func ParseURL(s string) (*URL, error) { - u, err := url.Parse(s) - if err != nil { - return nil, err - } - return (*URL)(u), nil -} - -func MustParseURL(s string) *URL { - u, err := ParseURL(s) - if err != nil { - panic(err) - } - return u -} - -func (u *URL) String() string { - return (*url.URL)(u).String() -} - -// URL returns a copy of u as a *url.URL -func (u *URL) URL() *url.URL { - if u == nil { - return nil - } - // defensive copy - r := url.URL(*u) - if u.User != nil { - r.User = new(url.Userinfo) - *r.User = *u.User - } - return &r -} - -func (u *URL) IsZero() bool { - return (url.URL)(*u) == url.URL{} -} - -func (u *URL) MarshalText() ([]byte, error) { - return []byte(u.String()), nil -} - -func (u *URL) UnmarshalText(input []byte) error { - v, err := url.Parse(string(input)) - if err != nil { - return err - } - *u = URL(*v) - return nil -} - // ServiceHeader is an HTTP header to include in POST to log service. type ServiceHeader struct { Header string diff --git a/core/store/models/common_test.go b/core/store/models/common_test.go index 57b7ca73c6b..eca703d5f3a 100644 --- a/core/store/models/common_test.go +++ b/core/store/models/common_test.go @@ -189,27 +189,6 @@ func TestWebURL_String_HasNilURL(t *testing.T) { assert.Equal(t, "", w.String()) } -func TestDuration_MarshalJSON(t *testing.T) { - tests := []struct { - name string - input models.Duration - want string - }{ - {"zero", models.MustMakeDuration(0), `"0s"`}, - {"one second", models.MustMakeDuration(time.Second), `"1s"`}, - {"one minute", models.MustMakeDuration(time.Minute), `"1m0s"`}, - {"one hour", models.MustMakeDuration(time.Hour), `"1h0m0s"`}, - {"one hour thirty minutes", models.MustMakeDuration(time.Hour + 30*time.Minute), `"1h30m0s"`}, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - b, err := json.Marshal(test.input) - assert.NoError(t, err) - assert.Equal(t, test.want, string(b)) - }) - } -} - func TestCron_UnmarshalJSON_Success(t *testing.T) { t.Parallel() @@ -385,49 +364,6 @@ func TestInterval_MarshalText_UnmarshalText(t *testing.T) { require.Equal(t, i, iNew) } -func TestDuration_Scan_Value(t *testing.T) { - t.Parallel() - - d := models.MustMakeDuration(100) - require.NotNil(t, d) - - val, err := d.Value() - require.NoError(t, err) - - dNew := models.MustMakeDuration(0) - err = dNew.Scan(val) - require.NoError(t, err) - - require.Equal(t, d, dNew) -} - -func TestDuration_MarshalJSON_UnmarshalJSON(t *testing.T) { - t.Parallel() - - d := models.MustMakeDuration(100) - require.NotNil(t, d) - - json, err := d.MarshalJSON() - require.NoError(t, err) - - dNew := models.MustMakeDuration(0) - err = dNew.UnmarshalJSON(json) - require.NoError(t, err) - - require.Equal(t, d, dNew) -} - -func TestDuration_MakeDurationFromString(t *testing.T) { - t.Parallel() - - d, err := models.ParseDuration("1s") - require.NoError(t, err) - require.Equal(t, 1*time.Second, d.Duration()) - - _, err = models.ParseDuration("xyz") - require.Error(t, err) -} - func TestWebURL_Scan_Value(t *testing.T) { t.Parallel() diff --git a/core/store/models/secrets.go b/core/store/models/secrets.go index a7afc95b6cc..ac5cac01734 100644 --- a/core/store/models/secrets.go +++ b/core/store/models/secrets.go @@ -4,6 +4,8 @@ import ( "encoding" "fmt" "net/url" + + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" ) const redacted = "xxxxx" @@ -33,22 +35,22 @@ var ( ) // SecretURL is a URL that formats and encodes redacted, as "xxxxx". -type SecretURL URL +type SecretURL commonconfig.URL -func NewSecretURL(u *URL) *SecretURL { return (*SecretURL)(u) } +func NewSecretURL(u *commonconfig.URL) *SecretURL { return (*SecretURL)(u) } -func MustSecretURL(u string) *SecretURL { return NewSecretURL(MustParseURL(u)) } +func MustSecretURL(u string) *SecretURL { return NewSecretURL(commonconfig.MustParseURL(u)) } func (s *SecretURL) String() string { return redacted } func (s *SecretURL) GoString() string { return redacted } -func (s *SecretURL) URL() *url.URL { return (*URL)(s).URL() } +func (s *SecretURL) URL() *url.URL { return (*commonconfig.URL)(s).URL() } func (s *SecretURL) MarshalText() ([]byte, error) { return []byte(redacted), nil } func (s *SecretURL) UnmarshalText(text []byte) error { - if err := (*URL)(s).UnmarshalText(text); err != nil { + if err := (*commonconfig.URL)(s).UnmarshalText(text); err != nil { //opt: if errors.Is(url.Error), just redact the err.URL field? return fmt.Errorf("failed to parse url: %s", redacted) } diff --git a/core/testdata/testspecs/v2_specs.go b/core/testdata/testspecs/v2_specs.go index f2a40ff332a..e66971a7a11 100644 --- a/core/testdata/testspecs/v2_specs.go +++ b/core/testdata/testspecs/v2_specs.go @@ -828,3 +828,34 @@ storeBlockhashesBatchSize = %d return BlockHeaderFeederSpec{BlockHeaderFeederSpecParams: params, toml: toml} } + +type StreamSpecParams struct { + Name string +} + +type StreamSpec struct { + StreamSpecParams + toml string +} + +// Toml returns the BlockhashStoreSpec in TOML string form. +func (b StreamSpec) Toml() string { + return b.toml +} + +func GenerateStreamSpec(params StreamSpecParams) StreamSpec { + template := ` +type = "stream" +schemaVersion = 1 +name = "%s" +observationSource = """ +ds [type=http method=GET url="https://chain.link/ETH-USD"]; +ds_parse [type=jsonparse path="data,price"]; +ds_multiply [type=multiply times=100]; +ds -> ds_parse -> ds_multiply; +""" +` + + toml := fmt.Sprintf(template, params.Name) + return StreamSpec{StreamSpecParams: params, toml: toml} +} diff --git a/core/utils/http/http_test.go b/core/utils/http/http_test.go index db7a593a8cd..7ef2f1523ab 100644 --- a/core/utils/http/http_test.go +++ b/core/utils/http/http_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/assert" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils/http" ) @@ -20,7 +21,7 @@ func TestUnrestrictedHTTPClient(t *testing.T) { assert.True(t, client.Transport.(*netHttp.Transport).DisableCompression) client.Transport = newMockTransport() - netReq, err := netHttp.NewRequest("GET", "http://localhost", bytes.NewReader([]byte{})) + netReq, err := netHttp.NewRequestWithContext(testutils.Context(t), "GET", "http://localhost", bytes.NewReader([]byte{})) assert.NoError(t, err) req := &http.HTTPRequest{ diff --git a/core/web/auth/auth_test.go b/core/web/auth/auth_test.go index f0b4e5068fb..2ac6473ed2e 100644 --- a/core/web/auth/auth_test.go +++ b/core/web/auth/auth_test.go @@ -2,6 +2,7 @@ package auth_test import ( "fmt" + "io" "net/http" "net/http/httptest" "testing" @@ -75,7 +76,7 @@ func TestAuthenticateByToken_Success(t *testing.T) { }) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) req.Header.Set(webauth.APIKey, key) req.Header.Set(webauth.APISecret, secret) router.ServeHTTP(w, req) @@ -96,7 +97,7 @@ func TestAuthenticateByToken_AuthFailed(t *testing.T) { }) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) req.Header.Set(webauth.APIKey, "bad-key") req.Header.Set(webauth.APISecret, "bad-secret") router.ServeHTTP(w, req) @@ -122,7 +123,7 @@ func TestAuthenticateByToken_RejectsBlankAccessKey(t *testing.T) { }) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) req.Header.Set(webauth.APIKey, key) req.Header.Set(webauth.APISecret, secret) router.ServeHTTP(w, req) @@ -143,7 +144,7 @@ func TestRequireAuth_NoneRequired(t *testing.T) { }) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) router.ServeHTTP(w, req) assert.True(t, called) @@ -161,7 +162,7 @@ func TestRequireAuth_AuthFailed(t *testing.T) { }) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) router.ServeHTTP(w, req) assert.False(t, called) @@ -179,7 +180,7 @@ func TestRequireAuth_LastAuthSuccess(t *testing.T) { }) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) router.ServeHTTP(w, req) assert.True(t, called) @@ -197,7 +198,7 @@ func TestRequireAuth_Error(t *testing.T) { }) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) router.ServeHTTP(w, req) assert.False(t, called) @@ -504,3 +505,10 @@ func TestRBAC_Routemap_ViewOnly(t *testing.T) { }) } } + +func mustRequest(t *testing.T, method, url string, body io.Reader) *http.Request { + ctx := testutils.Context(t) + req, err := http.NewRequestWithContext(ctx, method, url, body) + require.NoError(t, err) + return req +} diff --git a/core/web/auth/gql_test.go b/core/web/auth/gql_test.go index 4f3f8e27baf..f3d085c71f8 100644 --- a/core/web/auth/gql_test.go +++ b/core/web/auth/gql_test.go @@ -37,7 +37,7 @@ func Test_AuthenticateGQL_Unauthenticated(t *testing.T) { }) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) r.ServeHTTP(w, req) } @@ -63,7 +63,7 @@ func Test_AuthenticateGQL_Authenticated(t *testing.T) { sessionORM.On("AuthorizedUserWithSession", sessionID).Return(clsessions.User{Email: cltest.APIEmailAdmin, Role: clsessions.UserRoleAdmin}, nil) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) cookie := cltest.MustGenerateSessionCookie(t, sessionID) req.AddCookie(cookie) diff --git a/core/web/build_info_controller_test.go b/core/web/build_info_controller_test.go index e2d2cb0e631..5a2b88fa0dc 100644 --- a/core/web/build_info_controller_test.go +++ b/core/web/build_info_controller_test.go @@ -32,12 +32,15 @@ func TestBuildInfoController_Show_APICredentials(t *testing.T) { func TestBuildInfoController_Show_NoCredentials(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := clhttptest.NewTestLocalOnlyHTTPClient() url := app.Server.URL + "/v2/build_info" - resp, err := client.Get(url) + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + require.NoError(t, err) + resp, err := client.Do(req) require.NoError(t, err) require.Equal(t, http.StatusUnauthorized, resp.StatusCode) } diff --git a/core/web/chains_controller.go b/core/web/chains_controller.go index e547cf0150e..61c8d1dc84d 100644 --- a/core/web/chains_controller.go +++ b/core/web/chains_controller.go @@ -45,7 +45,7 @@ func newChainsController[R jsonapi.EntityNamer](network relay.Network, chainStat newResource func(types.ChainStatus) R, lggr logger.Logger, auditLogger audit.AuditLogger) *chainsController[R] { return &chainsController[R]{ network: network, - resourceName: string(network) + "_chain", + resourceName: network + "_chain", chainStats: chainStats, errNotEnabled: errNotEnabled, newResource: newResource, @@ -79,7 +79,7 @@ func (cc *chainsController[R]) Show(c *gin.Context) { jsonAPIError(c, http.StatusBadRequest, cc.errNotEnabled) return } - relayID := relay.ID{Network: cc.network, ChainID: relay.ChainID(c.Param("ID"))} + relayID := relay.ID{Network: cc.network, ChainID: c.Param("ID")} chain, err := cc.chainStats.ChainStatus(c, relayID) if err != nil { jsonAPIError(c, http.StatusBadRequest, err) diff --git a/core/web/evm_transfer_controller_test.go b/core/web/evm_transfer_controller_test.go index cff996dd21c..86d6b4618aa 100644 --- a/core/web/evm_transfer_controller_test.go +++ b/core/web/evm_transfer_controller_test.go @@ -12,6 +12,7 @@ import ( "github.com/jmoiron/sqlx" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -295,7 +296,7 @@ func TestTransfersController_CreateSuccess_eip1559(t *testing.T) { c.EVM[0].ChainID = (*ubig.Big)(testutils.FixtureChainID) // NOTE: FallbackPollInterval is used in this test to quickly create TxAttempts // Testing triggers requires committing transactions and does not work with transactional tests - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(time.Second) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(time.Second) }) app := cltest.NewApplicationWithConfigAndKey(t, config, ethClient, key) diff --git a/core/web/gui_assets_test.go b/core/web/gui_assets_test.go index 137b1231984..810aa40ca05 100644 --- a/core/web/gui_assets_test.go +++ b/core/web/gui_assets_test.go @@ -44,7 +44,9 @@ func TestGuiAssets_DefaultIndexHtml_OK(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Parallel() - resp, err := client.Get(app.Server.URL + tc.path) + req, err := http.NewRequestWithContext(testutils.Context(t), "GET", app.Server.URL+tc.path, nil) + require.NoError(t, err) + resp, err := client.Do(req) require.NoError(t, err) cltest.AssertServerResponse(t, resp, http.StatusOK) }) @@ -75,7 +77,9 @@ func TestGuiAssets_DefaultIndexHtml_NotFound(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Parallel() - resp, err := client.Get(app.Server.URL + tc.path) + req, err := http.NewRequestWithContext(testutils.Context(t), "GET", app.Server.URL+tc.path, nil) + require.NoError(t, err) + resp, err := client.Do(req) require.NoError(t, err) cltest.AssertServerResponse(t, resp, http.StatusNotFound) }) @@ -94,13 +98,17 @@ func TestGuiAssets_DefaultIndexHtml_RateLimited(t *testing.T) { // Make calls equal to the rate limit rateLimit := 20 for i := 0; i < rateLimit; i++ { - resp, err := client.Get(app.Server.URL + "/") + req, err := http.NewRequestWithContext(testutils.Context(t), "GET", app.Server.URL+"/", nil) + require.NoError(t, err) + resp, err := client.Do(req) require.NoError(t, err) cltest.AssertServerResponse(t, resp, http.StatusOK) } // Last request fails - resp, err := client.Get(app.Server.URL + "/") + req, err := http.NewRequestWithContext(testutils.Context(t), "GET", app.Server.URL+"/", nil) + require.NoError(t, err) + resp, err := client.Do(req) require.NoError(t, err) assert.Equal(t, http.StatusTooManyRequests, resp.StatusCode) } @@ -115,7 +123,7 @@ func TestGuiAssets_AssetsFS(t *testing.T) { recorder := httptest.NewRecorder() c, _ := gin.CreateTestContext(recorder) var err error - c.Request, err = http.NewRequest("GET", "http://localhost:6688/fixtures/operator_ui/assets/main.js", nil) + c.Request, err = http.NewRequestWithContext(c, "GET", "http://localhost:6688/fixtures/operator_ui/assets/main.js", nil) require.NoError(t, err) handler(c) @@ -123,7 +131,7 @@ func TestGuiAssets_AssetsFS(t *testing.T) { recorder = httptest.NewRecorder() c, _ = gin.CreateTestContext(recorder) - c.Request, err = http.NewRequest("GET", "http://localhost:6688/fixtures/operator_ui/assets/kinda_main.js", nil) + c.Request, err = http.NewRequestWithContext(c, "GET", "http://localhost:6688/fixtures/operator_ui/assets/kinda_main.js", nil) require.NoError(t, err) handler(c) @@ -134,7 +142,7 @@ func TestGuiAssets_AssetsFS(t *testing.T) { recorder := httptest.NewRecorder() c, _ := gin.CreateTestContext(recorder) var err error - c.Request, err = http.NewRequest("GET", "http://localhost:6688/fixtures/operator_ui/assets/main.js", nil) + c.Request, err = http.NewRequestWithContext(c, "GET", "http://localhost:6688/fixtures/operator_ui/assets/main.js", nil) require.NoError(t, err) c.Request.Header.Set("Accept-Encoding", "gzip") handler(c) @@ -144,7 +152,7 @@ func TestGuiAssets_AssetsFS(t *testing.T) { recorder = httptest.NewRecorder() c, _ = gin.CreateTestContext(recorder) - c.Request, err = http.NewRequest("GET", "http://localhost:6688/fixtures/operator_ui/assets/kinda_main.js", nil) + c.Request, err = http.NewRequestWithContext(c, "GET", "http://localhost:6688/fixtures/operator_ui/assets/kinda_main.js", nil) require.NoError(t, err) c.Request.Header.Set("Accept-Encoding", "gzip") handler(c) diff --git a/core/web/jobs_controller.go b/core/web/jobs_controller.go index 0f97e0b53d3..4e11f68097d 100644 --- a/core/web/jobs_controller.go +++ b/core/web/jobs_controller.go @@ -27,6 +27,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/services/streams" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -250,6 +251,8 @@ func (jc *JobsController) validateJobSpec(tomlString string) (jb job.Job, status jb, err = ocrbootstrap.ValidatedBootstrapSpecToml(tomlString) case job.Gateway: jb, err = gateway.ValidatedGatewaySpec(tomlString) + case job.Stream: + jb, err = streams.ValidatedStreamSpec(tomlString) default: return jb, http.StatusUnprocessableEntity, errors.Errorf("unknown job type: %s", jobType) } diff --git a/core/web/jobs_controller_test.go b/core/web/jobs_controller_test.go index 0a40c8a9c71..eec58c30571 100644 --- a/core/web/jobs_controller_test.go +++ b/core/web/jobs_controller_test.go @@ -36,6 +36,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/keystore/keys/p2pkey" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/core/utils/tomlutils" @@ -139,12 +140,17 @@ func TestJobController_Create_HappyPath(t *testing.T) { app, client := setupJobsControllerTests(t) b1, b2 := setupBridges(t, app.GetSqlxDB(), app.GetConfig().Database()) require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) - pks, err := app.KeyStore.VRF().GetAll() - require.NoError(t, err) - require.Len(t, pks, 1) - k, err := app.KeyStore.P2P().GetAll() - require.NoError(t, err) - require.Len(t, k, 1) + var pks []vrfkey.KeyV2 + var k []p2pkey.KeyV2 + { + var err error + pks, err = app.KeyStore.VRF().GetAll() + require.NoError(t, err) + require.Len(t, pks, 1) + k, err = app.KeyStore.P2P().GetAll() + require.NoError(t, err) + require.Len(t, k, 1) + } jorm := app.JobORM() var tt = []struct { @@ -360,6 +366,26 @@ func TestJobController_Create_HappyPath(t *testing.T) { assert.Equal(t, jb.VRFSpec.CoordinatorAddress.Hex(), resource.VRFSpec.CoordinatorAddress.Hex()) }, }, + { + name: "stream", + tomlTemplate: func(_ string) string { + return testspecs.GenerateStreamSpec(testspecs.StreamSpecParams{Name: "ETH/USD"}).Toml() + }, + assertion: func(t *testing.T, nameAndExternalJobID string, r *http.Response) { + require.Equal(t, http.StatusOK, r.StatusCode) + resp := cltest.ParseResponseBody(t, r) + resource := presenters.JobResource{} + err := web.ParseJSONAPIResponse(resp, &resource) + require.NoError(t, err) + + jb, err := jorm.FindJob(testutils.Context(t), mustInt32FromString(t, resource.ID)) + require.NoError(t, err) + require.NotNil(t, jb.PipelineSpec) + + assert.NotNil(t, resource.PipelineSpec.DotDAGSource) + assert.Equal(t, jb.Name.ValueOrZero(), resource.Name) + }, + }, } for _, tc := range tt { c := tc @@ -574,6 +600,7 @@ func TestJobsController_Update_HappyPath(t *testing.T) { } func TestJobsController_Update_NonExistentID(t *testing.T) { + ctx := testutils.Context(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.OCR.Enabled = ptr(true) c.P2P.V2.Enabled = ptr(true) @@ -583,7 +610,7 @@ func TestJobsController_Update_NonExistentID(t *testing.T) { app := cltest.NewApplicationWithConfigAndKey(t, cfg, cltest.DefaultP2PKey) require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) _, bridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) _, bridge2 := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) @@ -603,7 +630,7 @@ func TestJobsController_Update_NonExistentID(t *testing.T) { require.NoError(t, err) jb.OCROracleSpec = &ocrSpec jb.OCROracleSpec.TransmitterAddress = &app.Keys[0].EIP55Address - err = app.AddJobV2(testutils.Context(t), &jb) + err = app.AddJobV2(ctx, &jb) require.NoError(t, err) // test Calling update on the job id with changed values should succeed. @@ -686,6 +713,7 @@ func setupEthClientForControllerTests(t *testing.T) *evmclimocks.Client { } func setupJobSpecsControllerTestsWithJobs(t *testing.T) (*cltest.TestApplication, cltest.HTTPClientCleaner, job.Job, int32, job.Job, int32) { + ctx := testutils.Context(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.OCR.Enabled = ptr(true) c.P2P.V2.Enabled = ptr(true) @@ -695,7 +723,7 @@ func setupJobSpecsControllerTestsWithJobs(t *testing.T) (*cltest.TestApplication app := cltest.NewApplicationWithConfigAndKey(t, cfg, cltest.DefaultP2PKey) require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) _, bridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) _, bridge2 := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) @@ -711,7 +739,7 @@ func setupJobSpecsControllerTestsWithJobs(t *testing.T) (*cltest.TestApplication require.NoError(t, err) jb.OCROracleSpec = &ocrSpec jb.OCROracleSpec.TransmitterAddress = &app.Keys[0].EIP55Address - err = app.AddJobV2(testutils.Context(t), &jb) + err = app.AddJobV2(ctx, &jb) require.NoError(t, err) drSpec := fmt.Sprintf(` @@ -732,7 +760,7 @@ func setupJobSpecsControllerTestsWithJobs(t *testing.T) (*cltest.TestApplication erejb, err := directrequest.ValidatedDirectRequestSpec(drSpec) require.NoError(t, err) - err = app.AddJobV2(testutils.Context(t), &erejb) + err = app.AddJobV2(ctx, &erejb) require.NoError(t, err) return app, client, jb, jb.ID, erejb, erejb.ID diff --git a/core/web/loader/chain.go b/core/web/loader/chain.go index c91c2f02a3b..a12fef3d590 100644 --- a/core/web/loader/chain.go +++ b/core/web/loader/chain.go @@ -20,7 +20,7 @@ func (b *chainBatcher) loadByIDs(_ context.Context, keys dataloader.Keys) []*dat // Collect the keys to search for var chainIDs []relay.ChainID for ix, key := range keys { - chainIDs = append(chainIDs, relay.ChainID(key.String())) + chainIDs = append(chainIDs, key.String()) keyOrder[key.String()] = ix } diff --git a/core/web/loader/node.go b/core/web/loader/node.go index ef8e363d9f3..3d229813101 100644 --- a/core/web/loader/node.go +++ b/core/web/loader/node.go @@ -23,7 +23,7 @@ func (b *nodeBatcher) loadByChainIDs(ctx context.Context, keys dataloader.Keys) evmrelayIDs := make([]relay.ID, 0, len(keys)) for ix, key := range keys { - rid := relay.ID{Network: relay.EVM, ChainID: relay.ChainID(key.String())} + rid := relay.ID{Network: relay.EVM, ChainID: key.String()} evmrelayIDs = append(evmrelayIDs, rid) keyOrder[key.String()] = ix } diff --git a/core/web/log_controller_test.go b/core/web/log_controller_test.go index dbb95361b98..28c54b72450 100644 --- a/core/web/log_controller_test.go +++ b/core/web/log_controller_test.go @@ -43,8 +43,8 @@ func TestLogController_GetLogConfig(t *testing.T) { client := app.NewHTTPClient(nil) - resp, err := client.HTTPClient.Get("/v2/log") - require.NoError(t, err) + resp, clean := client.Get("/v2/log") + t.Cleanup(clean) svcLogConfig := presenters.ServiceLogConfigResource{} cltest.AssertServerResponse(t, resp, http.StatusOK) diff --git a/core/web/ping_controller_test.go b/core/web/ping_controller_test.go index 8e1862cd8c7..aa528ced534 100644 --- a/core/web/ping_controller_test.go +++ b/core/web/ping_controller_test.go @@ -55,7 +55,7 @@ func TestPingController_Show_ExternalInitiatorCredentials(t *testing.T) { require.NoError(t, err) url := app.Server.URL + "/v2/ping" - request, err := http.NewRequest("GET", url, nil) + request, err := http.NewRequestWithContext(testutils.Context(t), "GET", url, nil) require.NoError(t, err) request.Header.Set("Content-Type", web.MediaType) request.Header.Set("X-Chainlink-EA-AccessKey", eia.AccessKey) @@ -74,12 +74,15 @@ func TestPingController_Show_ExternalInitiatorCredentials(t *testing.T) { func TestPingController_Show_NoCredentials(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := clhttptest.NewTestLocalOnlyHTTPClient() url := app.Server.URL + "/v2/ping" - resp, err := client.Get(url) + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + require.NoError(t, err) + resp, err := client.Do(req) require.NoError(t, err) require.Equal(t, http.StatusUnauthorized, resp.StatusCode) } diff --git a/core/web/pipeline_runs_controller_test.go b/core/web/pipeline_runs_controller_test.go index 6c45c1eb319..3c57847d187 100644 --- a/core/web/pipeline_runs_controller_test.go +++ b/core/web/pipeline_runs_controller_test.go @@ -18,13 +18,13 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -35,8 +35,8 @@ func TestPipelineRunsController_CreateWithBody_HappyPath(t *testing.T) { ethClient := cltest.NewEthMocksWithStartupAssertions(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(2 * time.Second) - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(10 * time.Millisecond) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(2 * time.Second) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(10 * time.Millisecond) }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient) @@ -90,8 +90,8 @@ func TestPipelineRunsController_CreateNoBody_HappyPath(t *testing.T) { ethClient := cltest.NewEthMocksWithStartupAssertions(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(2 * time.Second) - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(10 * time.Millisecond) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(2 * time.Second) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(10 * time.Millisecond) }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient) diff --git a/core/web/presenters/job.go b/core/web/presenters/job.go index e9b63c73615..d0a6cfb5ca9 100644 --- a/core/web/presenters/job.go +++ b/core/web/presenters/job.go @@ -8,6 +8,7 @@ import ( "gopkg.in/guregu/null.v4" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" clnull "github.com/smartcontractkit/chainlink/v2/core/null" @@ -272,15 +273,15 @@ type VRFSpec struct { CoordinatorAddress ethkey.EIP55Address `json:"coordinatorAddress"` PublicKey secp256k1.PublicKey `json:"publicKey"` FromAddresses []ethkey.EIP55Address `json:"fromAddresses"` - PollPeriod models.Duration `json:"pollPeriod"` + PollPeriod commonconfig.Duration `json:"pollPeriod"` MinIncomingConfirmations uint32 `json:"confirmations"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` EVMChainID *big.Big `json:"evmChainID"` ChunkSize uint32 `json:"chunkSize"` - RequestTimeout models.Duration `json:"requestTimeout"` - BackoffInitialDelay models.Duration `json:"backoffInitialDelay"` - BackoffMaxDelay models.Duration `json:"backoffMaxDelay"` + RequestTimeout commonconfig.Duration `json:"requestTimeout"` + BackoffInitialDelay commonconfig.Duration `json:"backoffInitialDelay"` + BackoffMaxDelay commonconfig.Duration `json:"backoffMaxDelay"` GasLanePrice *assets.Wei `json:"gasLanePrice"` RequestedConfsDelay int64 `json:"requestedConfsDelay"` VRFOwnerAddress *ethkey.EIP55Address `json:"vrfOwnerAddress,omitempty"` @@ -295,15 +296,15 @@ func NewVRFSpec(spec *job.VRFSpec) *VRFSpec { CoordinatorAddress: spec.CoordinatorAddress, PublicKey: spec.PublicKey, FromAddresses: spec.FromAddresses, - PollPeriod: models.MustMakeDuration(spec.PollPeriod), + PollPeriod: *commonconfig.MustNewDuration(spec.PollPeriod), MinIncomingConfirmations: spec.MinIncomingConfirmations, CreatedAt: spec.CreatedAt, UpdatedAt: spec.UpdatedAt, EVMChainID: spec.EVMChainID, ChunkSize: spec.ChunkSize, - RequestTimeout: models.MustMakeDuration(spec.RequestTimeout), - BackoffInitialDelay: models.MustMakeDuration(spec.BackoffInitialDelay), - BackoffMaxDelay: models.MustMakeDuration(spec.BackoffMaxDelay), + RequestTimeout: *commonconfig.MustNewDuration(spec.RequestTimeout), + BackoffInitialDelay: *commonconfig.MustNewDuration(spec.BackoffInitialDelay), + BackoffMaxDelay: *commonconfig.MustNewDuration(spec.BackoffMaxDelay), GasLanePrice: spec.GasLanePrice, RequestedConfsDelay: spec.RequestedConfsDelay, VRFOwnerAddress: spec.VRFOwnerAddress, @@ -512,6 +513,8 @@ func NewJobResource(j job.Job) *JobResource { resource.BootstrapSpec = NewBootstrapSpec(j.BootstrapSpec) case job.Gateway: resource.GatewaySpec = NewGatewaySpec(j.GatewaySpec) + case job.Stream: + // no spec; nothing to do case job.LegacyGasStationServer, job.LegacyGasStationSidecar: // unsupported } diff --git a/core/web/presenters/user.go b/core/web/presenters/user.go index 19ccff960ac..7598c8864be 100644 --- a/core/web/presenters/user.go +++ b/core/web/presenters/user.go @@ -32,7 +32,7 @@ func NewUserResource(u sessions.User) *UserResource { return &UserResource{ JAID: NewJAID(u.Email), Email: u.Email, - Role: sessions.UserRole(u.Role), + Role: u.Role, HasActiveApiToken: hasToken, CreatedAt: u.CreatedAt, UpdatedAt: u.UpdatedAt, diff --git a/core/web/resolver/node_test.go b/core/web/resolver/node_test.go index a209a60fc3c..7f4e69ac4ae 100644 --- a/core/web/resolver/node_test.go +++ b/core/web/resolver/node_test.go @@ -6,11 +6,11 @@ import ( gqlerrors "github.com/graph-gophers/graphql-go/errors" "github.com/pkg/errors" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func TestResolver_Nodes(t *testing.T) { @@ -124,8 +124,8 @@ func Test_NodeQuery(t *testing.T) { f.App.On("EVMORM").Return(f.Mocks.evmORM) f.Mocks.evmORM.PutChains(toml.EVMConfig{Nodes: []*toml.Node{{ Name: &name, - WSURL: models.MustParseURL("ws://some-url"), - HTTPURL: models.MustParseURL("http://some-url"), + WSURL: commonconfig.MustParseURL("ws://some-url"), + HTTPURL: commonconfig.MustParseURL("http://some-url"), Order: ptr(int32(11)), }}}) }, diff --git a/core/web/resolver/spec.go b/core/web/resolver/spec.go index 5e8937dbb96..b1cb32783f9 100644 --- a/core/web/resolver/spec.go +++ b/core/web/resolver/spec.go @@ -521,7 +521,7 @@ func (r *OCR2SpecResolver) P2PV2Bootstrappers() *[]string { // Relay resolves the spec's relay func (r *OCR2SpecResolver) Relay() string { - return string(r.spec.Relay) + return r.spec.Relay } // RelayConfig resolves the spec's relay config @@ -899,7 +899,7 @@ func (r *BootstrapSpecResolver) ContractID() string { // Relay resolves the spec's relay func (r *BootstrapSpecResolver) Relay() string { - return string(r.spec.Relay) + return r.spec.Relay } // RelayConfig resolves the spec's relay config diff --git a/core/web/resolver/spec_test.go b/core/web/resolver/spec_test.go index a4fb9cdb338..828e8538071 100644 --- a/core/web/resolver/spec_test.go +++ b/core/web/resolver/spec_test.go @@ -163,10 +163,10 @@ func TestResolver_FluxMonitorSpec(t *testing.T) { EVMChainID: ubig.NewI(42), DrumbeatEnabled: false, IdleTimerDisabled: false, - IdleTimerPeriod: time.Duration(1 * time.Hour), + IdleTimerPeriod: 1 * time.Hour, MinPayment: commonassets.NewLinkFromJuels(1000), PollTimerDisabled: false, - PollTimerPeriod: time.Duration(1 * time.Minute), + PollTimerPeriod: 1 * time.Minute, }, }, nil) }, @@ -229,13 +229,13 @@ func TestResolver_FluxMonitorSpec(t *testing.T) { CreatedAt: f.Timestamp(), EVMChainID: ubig.NewI(42), DrumbeatEnabled: true, - DrumbeatRandomDelay: time.Duration(1 * time.Second), + DrumbeatRandomDelay: 1 * time.Second, DrumbeatSchedule: "CRON_TZ=UTC 0 0 1 1 *", IdleTimerDisabled: true, - IdleTimerPeriod: time.Duration(1 * time.Hour), + IdleTimerPeriod: 1 * time.Hour, MinPayment: commonassets.NewLinkFromJuels(1000), PollTimerDisabled: true, - PollTimerPeriod: time.Duration(1 * time.Minute), + PollTimerPeriod: 1 * time.Minute, }, }, nil) }, diff --git a/core/web/resolver/testdata/config-empty-effective.toml b/core/web/resolver/testdata/config-empty-effective.toml index 9efad05c03a..cc4dddcf8af 100644 --- a/core/web/resolver/testdata/config-empty-effective.toml +++ b/core/web/resolver/testdata/config-empty-effective.toml @@ -227,3 +227,6 @@ TLSCertPath = '' LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' + +[Mercury.TLS] +CertFile = '' diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index 45504d62596..957ffdc968e 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -238,6 +238,9 @@ LatestReportTTL = '1m40s' MaxStaleAge = '1m41s' LatestReportDeadline = '1m42s' +[Mercury.TLS] +CertFile = '' + [[EVM]] ChainID = '1' Enabled = false diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index 40c18f28eb9..d5352a685c4 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -228,6 +228,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/core/web/router_test.go b/core/web/router_test.go index 18177a1ac28..bb371318468 100644 --- a/core/web/router_test.go +++ b/core/web/router_test.go @@ -20,14 +20,18 @@ import ( ) func TestTokenAuthRequired_NoCredentials(t *testing.T) { + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) router := web.Router(t, app, nil) ts := httptest.NewServer(router) defer ts.Close() - resp, err := http.Post(ts.URL+"/v2/jobs/", web.MediaType, bytes.NewBufferString("{}")) + req, err := http.NewRequestWithContext(ctx, "POST", ts.URL+"/v2/jobs/", bytes.NewBufferString("{}")) + require.NoError(t, err) + req.Header.Set("Content-Type", web.MediaType) + resp, err := http.DefaultClient.Do(req) require.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) @@ -49,8 +53,9 @@ func TestTokenAuthRequired_SessionCredentials(t *testing.T) { } func TestTokenAuthRequired_TokenCredentials(t *testing.T) { + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) router := web.Router(t, app, nil) ts := httptest.NewServer(router) @@ -67,7 +72,7 @@ func TestTokenAuthRequired_TokenCredentials(t *testing.T) { err = app.BridgeORM().CreateExternalInitiator(ea) require.NoError(t, err) - request, err := http.NewRequest("GET", ts.URL+"/v2/ping/", bytes.NewBufferString("{}")) + request, err := http.NewRequestWithContext(ctx, "GET", ts.URL+"/v2/ping/", bytes.NewBufferString("{}")) require.NoError(t, err) request.Header.Set("Content-Type", web.MediaType) request.Header.Set("X-Chainlink-EA-AccessKey", eia.AccessKey) @@ -81,8 +86,9 @@ func TestTokenAuthRequired_TokenCredentials(t *testing.T) { } func TestTokenAuthRequired_BadTokenCredentials(t *testing.T) { + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) router := web.Router(t, app, nil) ts := httptest.NewServer(router) @@ -99,7 +105,7 @@ func TestTokenAuthRequired_BadTokenCredentials(t *testing.T) { err = app.BridgeORM().CreateExternalInitiator(ea) require.NoError(t, err) - request, err := http.NewRequest("GET", ts.URL+"/v2/ping/", bytes.NewBufferString("{}")) + request, err := http.NewRequestWithContext(ctx, "GET", ts.URL+"/v2/ping/", bytes.NewBufferString("{}")) require.NoError(t, err) request.Header.Set("Content-Type", web.MediaType) request.Header.Set("X-Chainlink-EA-AccessKey", eia.AccessKey) @@ -113,8 +119,9 @@ func TestTokenAuthRequired_BadTokenCredentials(t *testing.T) { } func TestSessions_RateLimited(t *testing.T) { + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) router := web.Router(t, app, nil) ts := httptest.NewServer(router) @@ -124,7 +131,7 @@ func TestSessions_RateLimited(t *testing.T) { input := `{"email":"brute@force.com", "password": "wrongpassword"}` for i := 0; i < 5; i++ { - request, err := http.NewRequest("POST", ts.URL+"/sessions", bytes.NewBufferString(input)) + request, err := http.NewRequestWithContext(ctx, "POST", ts.URL+"/sessions", bytes.NewBufferString(input)) require.NoError(t, err) resp, err := client.Do(request) @@ -132,7 +139,7 @@ func TestSessions_RateLimited(t *testing.T) { assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) } - request, err := http.NewRequest("POST", ts.URL+"/sessions", bytes.NewBufferString(input)) + request, err := http.NewRequestWithContext(ctx, "POST", ts.URL+"/sessions", bytes.NewBufferString(input)) require.NoError(t, err) resp, err := client.Do(request) @@ -141,8 +148,9 @@ func TestSessions_RateLimited(t *testing.T) { } func TestRouter_LargePOSTBody(t *testing.T) { + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) router := web.Router(t, app, nil) ts := httptest.NewServer(router) @@ -151,7 +159,7 @@ func TestRouter_LargePOSTBody(t *testing.T) { client := clhttptest.NewTestLocalOnlyHTTPClient() body := string(make([]byte, 70000)) - request, err := http.NewRequest("POST", ts.URL+"/sessions", bytes.NewBufferString(body)) + request, err := http.NewRequestWithContext(ctx, "POST", ts.URL+"/sessions", bytes.NewBufferString(body)) require.NoError(t, err) resp, err := client.Do(request) @@ -160,13 +168,16 @@ func TestRouter_LargePOSTBody(t *testing.T) { } func TestRouter_GinHelmetHeaders(t *testing.T) { + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) router := web.Router(t, app, nil) ts := httptest.NewServer(router) defer ts.Close() - res, err := http.Get(ts.URL) + req, err := http.NewRequestWithContext(ctx, "GET", ts.URL, nil) + require.NoError(t, err) + res, err := http.DefaultClient.Do(req) require.NoError(t, err) for _, tt := range []struct { HelmetName string diff --git a/core/web/sessions_controller_test.go b/core/web/sessions_controller_test.go index c2950caf3d1..9f883ef54b8 100644 --- a/core/web/sessions_controller_test.go +++ b/core/web/sessions_controller_test.go @@ -22,6 +22,7 @@ import ( func TestSessionsController_Create(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) @@ -44,7 +45,7 @@ func TestSessionsController_Create(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { body := fmt.Sprintf(`{"email":"%s","password":"%s"}`, test.email, test.password) - request, err := http.NewRequest("POST", app.Server.URL+"/sessions", bytes.NewBufferString(body)) + request, err := http.NewRequestWithContext(ctx, "POST", app.Server.URL+"/sessions", bytes.NewBufferString(body)) assert.NoError(t, err) resp, err := client.Do(request) assert.NoError(t, err) @@ -86,8 +87,9 @@ func mustInsertSession(t *testing.T, q pg.Q, session *sessions.Session) { func TestSessionsController_Create_ReapSessions(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) user := cltest.MustRandomUser(t) require.NoError(t, app.AuthenticationProvider().CreateUser(&user)) @@ -99,7 +101,10 @@ func TestSessionsController_Create_ReapSessions(t *testing.T) { mustInsertSession(t, q, &staleSession) body := fmt.Sprintf(`{"email":"%s","password":"%s"}`, user.Email, cltest.Password) - resp, err := http.Post(app.Server.URL+"/sessions", "application/json", bytes.NewBufferString(body)) + req, err := http.NewRequestWithContext(ctx, "POST", app.Server.URL+"/sessions", bytes.NewBufferString(body)) + assert.NoError(t, err) + req.Header.Set("Content-Type", "application/json") + resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer func() { assert.NoError(t, resp.Body.Close()) }() @@ -119,6 +124,7 @@ func TestSessionsController_Create_ReapSessions(t *testing.T) { func TestSessionsController_Destroy(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) @@ -143,7 +149,7 @@ func TestSessionsController_Destroy(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { cookie := cltest.MustGenerateSessionCookie(t, test.sessionID) - request, err := http.NewRequest("DELETE", app.Server.URL+"/sessions", nil) + request, err := http.NewRequestWithContext(ctx, "DELETE", app.Server.URL+"/sessions", nil) assert.NoError(t, err) request.AddCookie(cookie) @@ -163,6 +169,7 @@ func TestSessionsController_Destroy(t *testing.T) { func TestSessionsController_Destroy_ReapSessions(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) client := clhttptest.NewTestLocalOnlyHTTPClient() app := cltest.NewApplicationEVMDisabled(t) @@ -183,7 +190,7 @@ func TestSessionsController_Destroy_ReapSessions(t *testing.T) { staleSession.LastUsed = time.Now().Add(-cltest.MustParseDuration(t, "241h")) mustInsertSession(t, q, &staleSession) - request, err := http.NewRequest("DELETE", app.Server.URL+"/sessions", nil) + request, err := http.NewRequestWithContext(ctx, "DELETE", app.Server.URL+"/sessions", nil) assert.NoError(t, err) request.AddCookie(cookie) diff --git a/core/web/solana_transfer_controller.go b/core/web/solana_transfer_controller.go index f9a2c627932..70218080a87 100644 --- a/core/web/solana_transfer_controller.go +++ b/core/web/solana_transfer_controller.go @@ -48,7 +48,7 @@ func (tc *SolanaTransfersController) Create(c *gin.Context) { } amount := new(big.Int).SetUint64(tr.Amount) - relayerID := relay.ID{Network: relay.Solana, ChainID: relay.ChainID(tr.SolanaChainID)} + relayerID := relay.ID{Network: relay.Solana, ChainID: tr.SolanaChainID} relayer, err := relayers.Get(relayerID) if err != nil { if errors.Is(err, chainlink.ErrNoSuchRelayer) { diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 36ee68412ca..6b70fd51c63 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `chainlink health` CLI command and HTML `/health` endpoint, to provide human-readable views of the underlying JSON health data. +- New job type `stream` to represent streamspecs. This job type is not yet used anywhere but will be required for Data Streams V1. ### Fixed @@ -64,7 +65,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Two new prom metrics for mercury, nops should consider adding alerting on these: - `mercury_insufficient_blocks_count` - `mercury_zero_blocks_count` - +- Added new `Mercury.TLS` TOML config field `CertFile` for configuring transport credentials when the node acts as a client and initiates a TLS handshake. + ### Changed - `PromReporter` no longer directly reads txm related status from the db, and instead uses the txStore API. diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 2bb32b58252..421b0ea9dad 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -1589,6 +1589,19 @@ LatestReportDeadline = "5s" # Default LatestReportDeadline controls how long to wait for a response from the mercury server before retrying. Setting this to zero will wait indefinitely. +## Mercury.TLS +```toml +[Mercury.TLS] +CertFile = "/path/to/client/certs.pem" # Example +``` +Mercury.TLS controls client settings for when the node talks to traditional web servers or load balancers. + +### CertFile +```toml +CertFile = "/path/to/client/certs.pem" # Example +``` +CertFile is the path to a PEM file of trusted root certificate authority certificates + ## EVM EVM defaults depend on ChainID: diff --git a/docs/Mercury.md b/docs/Mercury.md index 610605ddbc6..82835c9519a 100644 --- a/docs/Mercury.md +++ b/docs/Mercury.md @@ -1,162 +1,63 @@ # Mercury Documentation -## Contracts +## Useful Links -Use this tool to configure contracts: +[Configuration Builder](https://github.com/smartcontractkit/the-most-amazing-mercury-contract-configuration-tool) -https://github.com/smartcontractkit/the-most-amazing-mercury-contract-configuration-tool +[Contracts](https://github.com/smartcontractkit/chainlink/contracts/src/v0.8/llo-feeds) -TODO: updated process here @Austin Born +[OCR3 Config Documentation](https://github.com/smartcontractkit/libocr/blob/master/offchainreporting2plus/internal/config/ocr3config/public_config.go) -[Reference contract](https://github.com/smartcontractkit/reference-data-directory/blob/master/ethereum-testnet-goerli-arbitrum-1/contracts/0x535051166466D159da8742167c9CA1eFe9e82613.json) -[OCR2 config documentation](https://github.com/smartcontractkit/libocr/blob/master/offchainreporting2/internal/config/public_config.go) -**🚨 Important config** -`s` - transmission schedule. This should be set to the number of oracles on the feed - meaning that every oracle will attempt to transmit to the mercury server in the first stage of transmission. eg `[4]` if there are 4 node in the DON, excluding the bootstrap node. - -`f` - set this to `n//3` (where `//` denotes integer division), e.g. if you have 16 oracles, set `f` to 5. - -`deltaRound` - report generation frequency. This determines how frequently a new round should be started at most (if rounds take longer than this due to network latency, there will be fewer rounds per second than this parameter would suggest). `100ms` is a good starting point (10 rounds/s). - -`reportingPluginConfig.alphaAccept` - set this to `0`, because our mercury ContractTransmitter doesn't know the latest report that's been sent to the mercury server and we therefore always have a "pending" report which we compare against before accepting a report for transmission. - -`reportingPluginConfig.deltaC` - set this to `0` so every round will result in a report. - -
Example `verifier/<0xaddress>.json` +### Example Feed Configuration ```json { - "contractVersion": 1001, - "digests": { - "0x0006c67c0374ab0dcfa45c63b37df2ea8d16fb903c043caa98065033e9c15666": { - "feedId": "0x14e044f932bb959cc2aa8dc1ba110c09224e639aae00264c1ffc2a0830904a3c", - "proxyEnabled": true, - "status": "active" - } - }, - "feeds": { - "0x14e044f932bb959cc2aa8dc1ba110c09224e639aae00264c1ffc2a0830904a3c": { - "digests": [ - "0x0006c67c0374ab0dcfa45c63b37df2ea8d16fb903c043caa98065033e9c15666" - ], - "docs": { - "assetName": "Chainlink", - "feedCategory": "verified", - "feedType": "Crypto", - "hidden": true - }, - "externalAdapterRequestParams": { - "endpoint": "cryptolwba", - "from": "LINK", - "to": "USD" - }, - "feedId": "0x14e044f932bb959cc2aa8dc1ba110c09224e639aae00264c1ffc2a0830904a3c", - "latestConfig": { - "offchainConfig": { - "deltaGrace": "0", - "deltaProgress": "2s", - "deltaResend": "20s", - "deltaRound": "250ms", - "deltaStage": "60s", - "f": 1, - "maxDurationObservation": "250ms", - "maxDurationQuery": "0s", - "maxDurationReport": "250ms", - "maxDurationShouldAcceptFinalizedReport": "250ms", - "maxDurationShouldTransmitAcceptedReport": "250ms", - "rMax": 100, - "reportingPluginConfig": { - "alphaAcceptInfinite": false, - "alphaAcceptPpb": "0", - "alphaReportInfinite": false, - "alphaReportPpb": "0", - "deltaC": "0s" - }, - "s": [ - 4 - ] - }, - "offchainConfigVersion": 30, - "onchainConfig": { - "max": "99999999999999999999999999999", - "min": "1" - }, - "onchainConfigVersion": 1, - "oracles": [ - { - "api": [ - "coinmetrics", - "ncfx", - "tiingo-test" - ], - "operator": "clc-ocr-mercury-arbitrum-goerli-nodes-0" - }, - { - "api": [ - "coinmetrics", - "ncfx", - "tiingo-test" - ], - "operator": "clc-ocr-mercury-arbitrum-goerli-nodes-1" - }, - { - "api": [ - "coinmetrics", - "ncfx", - "tiingo-test" - ], - "operator": "clc-ocr-mercury-arbitrum-goerli-nodes-2" - }, - { - "api": [ - "coinmetrics", - "ncfx", - "tiingo-test" - ], - "operator": "clc-ocr-mercury-arbitrum-goerli-nodes-3" - } - ] - }, - "marketing": { - "category": "crypto", - "history": true, - "pair": [ - "LINK", - "USD" - ], - "path": "link-usd-verifier" - }, - "name": "LINK/USD-RefPricePlus-ArbitrumGoerli-002", - "reportFields": { - "ask": { - "decimals": 8, - "maxSubmissionValue": "99999999999999999999999999999", - "minSubmissionValue": "1", - "resultPath": "data,ask" - }, - "bid": { - "decimals": 8, - "maxSubmissionValue": "99999999999999999999999999999", - "minSubmissionValue": "1", - "resultPath": "data,bid" - }, - "median": { - "decimals": 8, - "maxSubmissionValue": "99999999999999999999999999999", - "minSubmissionValue": "1", - "resultPath": "data,mid" - } - }, - "status": "testing" - } - }, - "name": "Mercury v0.2 - Production Testnet Verifier (v1.0.0)", - "status": "testing" + "feedId": "0x14e044f932bb959cc2aa8dc1ba110c09224e639aae00264c1ffc2a0830904a3c", + "chainId": 42161, // source chain id + "contractAddress": "0x14e044f932bb959cc2aa8dc1ba110c09224e639a", // verifier contract address + "configCount": 1, // the index of this config + "signers": [ + "0x000....01", + "0x000....02", + "0x000....03", + "0x000....04" + ], // NOP signing addresses, + "transmitters": [ + "0x000....11", + "0x000....12", + "0x000....13", + "0x000....14" + ], // NOP transmitter addresses + "offchainConfig": { + "baseUSDFee": "0.1", // 10c base fee to verify the report + "deltaCertifiedCommitRequest": "1s", + "deltaGrace": "0s", + "deltaInitial": "600ms", + "deltaProgress": "2s", + "deltaResend": "10s", + "deltaRound": "250ms", + "deltaStage": "0s", + "expirationWindow": "86400", //window in in which a report can be verified in seconds + "f": 3, + "maxDurationObservation": "250ms", + "maxDurationQuery": "50ms", + "maxDurationShouldAcceptAttestedReport": "50ms", + "maxDurationShouldTransmitAcceptedReport": "50ms", + "rMax": "25", + "s": [ + 4 + ] + }, + "offchainConfigVersion": 30, + "onchainConfig": { + "max": "99999999999999999999999999999", + "min": "1" + } } ``` -
## Jobs diff --git a/go.mod b/go.mod index 46fb17f34d2..6195257b835 100644 --- a/go.mod +++ b/go.mod @@ -65,10 +65,10 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240110155415-407896b07206 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240113162114-77e747a4ef17 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231222201016-da3f0a763f71 github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 - github.com/smartcontractkit/chainlink-feeds v0.0.0-20240112193433-af835dc4b1a3 + github.com/smartcontractkit/chainlink-feeds v0.0.0-20240113162230-9b808fd915ee github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231222220348-c7d81beaf8fd github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231221191127-1f32389044ea github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 diff --git a/go.sum b/go.sum index 324f4e7100c..6eaf670525b 100644 --- a/go.sum +++ b/go.sum @@ -1150,14 +1150,14 @@ github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumv github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= github.com/smartcontractkit/chainlink-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240110155415-407896b07206 h1:CfKu1c/DBx5qi1lFC9e/aVWwO0IyWKw2poBQR2VflnA= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240110155415-407896b07206/go.mod h1:f+0ei9N4PlTJHu7pbGzEjTnBUr45syPdGFu5+31lS5Q= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240113162114-77e747a4ef17 h1:/2FBQi0y48AwRq0Rr34JKsINAf7WHcaHr8XdbVXDt54= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240113162114-77e747a4ef17/go.mod h1:f+0ei9N4PlTJHu7pbGzEjTnBUr45syPdGFu5+31lS5Q= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231222201016-da3f0a763f71 h1:Ju0cxdrzGFwHGDPp16IzkOyX87LZ/kKDFG1A+VSEJHY= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231222201016-da3f0a763f71/go.mod h1:Ppv5X8MTUkkpKdb270dLefjio724vMkCWmSSaWo7CzI= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20240112193433-af835dc4b1a3 h1:w18bLofojboL74efMvH9iePjBa3KwlpvxR0FL/DN9Wc= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20240112193433-af835dc4b1a3/go.mod h1:L2b9/3wYVUqPAeKG/SLG/T0VsMOJtg+ygw8vTmRDMGE= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240113162230-9b808fd915ee h1:EC8tcNKx3f6qYln5WD+xVhzz60PKPH+sgrbjzAm3xcw= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240113162230-9b808fd915ee/go.mod h1:kXeFFq7kA+pmeG/A27wMi3geIRGn7G+r61v787ZyJtU= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231222220348-c7d81beaf8fd h1:9xSwDgRJDIfDw6171PQEyn5IQ1JKpaJnG5NX6KfCaHQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231222220348-c7d81beaf8fd/go.mod h1:kY435jBtHbyzhe+ImAxZ6G229uHbB0ablA+A0tJkDn8= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231221191127-1f32389044ea h1:WzMa0O6DEauMYMIjzS/T1JF8zvFDt4aG6EUTDlStaZo= diff --git a/integration-tests/Makefile b/integration-tests/Makefile index 5e34b059b68..d1e9bdd89ef 100644 --- a/integration-tests/Makefile +++ b/integration-tests/Makefile @@ -74,12 +74,12 @@ build_test_image: #Build a chainlink docker image for local testing and push to k3d registry .PHONY: build_push_docker_image build_push_docker_image: - docker build -f ../core/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t localhost:5000/chainlink:develop ../ ; docker push localhost:5000/chainlink:develop + docker build -f ../core/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t 127.0.0.1:5000/chainlink:develop ../ ; docker push 127.0.0.1:5000/chainlink:develop #Build a chainlink docker image in plugin mode for local testing and push to k3d registry .PHONY: build_push_plugin_docker_image build_push_plugin_docker_image: - docker build -f ../plugins/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t localhost:5000/chainlink:develop ../ ; docker push localhost:5000/chainlink:develop + docker build -f ../plugins/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t 127.0.0.1:5000/chainlink:develop ../ ; docker push 127.0.0.1:5000/chainlink:develop # Spins up containers needed to collect traces for local testing .PHONY: run_tracing @@ -197,7 +197,7 @@ build_docker_image: # example usage: make build_docker_image image=chainlink tag=latest .PHONY: build_plugin_docker_image build_plugin_docker_image: - docker build -f ../plugins/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t localhost:5000/chainlink:develop ../ + docker build -f ../plugins/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t 127.0.0.1:5000/chainlink:develop ../ # image: the name for the chainlink image being built, example: image=chainlink # tag: the tag for the chainlink image being built, example: tag=latest diff --git a/integration-tests/actions/ocr_helpers.go b/integration-tests/actions/ocr_helpers.go index 17e536ec839..dd0e6606e43 100644 --- a/integration-tests/actions/ocr_helpers.go +++ b/integration-tests/actions/ocr_helpers.go @@ -343,6 +343,25 @@ func StartNewRound( return nil } +// WatchNewRound watches for a new OCR round, similarly to StartNewRound, but it does not explicitly request a new +// round from the contract, as this can cause some odd behavior in some cases +func WatchNewRound( + roundNumber int64, + ocrInstances []contracts.OffchainAggregator, + client blockchain.EVMClient, + logger zerolog.Logger, +) error { + for i := 0; i < len(ocrInstances); i++ { + ocrRound := contracts.NewOffchainAggregatorRoundConfirmer(ocrInstances[i], big.NewInt(roundNumber), client.GetNetworkConfig().Timeout.Duration, logger) + client.AddHeaderEventSubscription(ocrInstances[i].Address(), ocrRound) + err := client.WaitForEvents() + if err != nil { + return fmt.Errorf("failed to wait for event subscriptions of OCR instance %d: %w", i+1, err) + } + } + return nil +} + // SetAdapterResponse sets a single adapter response that correlates with an ocr contract and a chainlink node func SetAdapterResponse( response int, diff --git a/integration-tests/actions/vrfv2_actions/vrfv2_models.go b/integration-tests/actions/vrfv2_actions/vrfv2_models.go index 0576d6f7d6e..aa594a753dd 100644 --- a/integration-tests/actions/vrfv2_actions/vrfv2_models.go +++ b/integration-tests/actions/vrfv2_actions/vrfv2_models.go @@ -23,6 +23,11 @@ type VRFV2Contracts struct { LoadTestConsumers []contracts.VRFv2LoadTestConsumer } +type VRFV2WrapperContracts struct { + VRFV2Wrapper contracts.VRFV2Wrapper + LoadTestConsumers []contracts.VRFv2WrapperLoadTestConsumer +} + // VRFV2PlusKeyData defines a jobs into and proving key info type VRFV2KeyData struct { VRFKey *client.VRFKey diff --git a/integration-tests/actions/vrfv2_actions/vrfv2_steps.go b/integration-tests/actions/vrfv2_actions/vrfv2_steps.go index 17c3948b340..d6288e58bf6 100644 --- a/integration-tests/actions/vrfv2_actions/vrfv2_steps.go +++ b/integration-tests/actions/vrfv2_actions/vrfv2_steps.go @@ -55,6 +55,7 @@ var ( ErrWaitRandomWordsRequestedEvent = "error waiting for RandomWordsRequested event" ErrWaitRandomWordsFulfilledEvent = "error waiting for RandomWordsFulfilled event" + ErrDeployWrapper = "error deploying VRFV2PlusWrapper" ) func DeployVRFV2Contracts( @@ -103,6 +104,46 @@ func DeployVRFV2Consumers(contractDeployer contracts.ContractDeployer, coordinat return consumers, nil } +func DeployVRFV2WrapperConsumers(contractDeployer contracts.ContractDeployer, linkTokenAddress string, vrfV2Wrapper contracts.VRFV2Wrapper, consumerContractsAmount int) ([]contracts.VRFv2WrapperLoadTestConsumer, error) { + var consumers []contracts.VRFv2WrapperLoadTestConsumer + for i := 1; i <= consumerContractsAmount; i++ { + loadTestConsumer, err := contractDeployer.DeployVRFV2WrapperLoadTestConsumer(linkTokenAddress, vrfV2Wrapper.Address()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) + } + consumers = append(consumers, loadTestConsumer) + } + return consumers, nil +} + +func DeployVRFV2DirectFundingContracts( + contractDeployer contracts.ContractDeployer, + chainClient blockchain.EVMClient, + linkTokenAddress string, + linkEthFeedAddress string, + coordinator contracts.VRFCoordinatorV2, + consumerContractsAmount int, +) (*VRFV2WrapperContracts, error) { + vrfv2Wrapper, err := contractDeployer.DeployVRFV2Wrapper(linkTokenAddress, linkEthFeedAddress, coordinator.Address()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrDeployWrapper, err) + } + err = chainClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + consumers, err := DeployVRFV2WrapperConsumers(contractDeployer, linkTokenAddress, vrfv2Wrapper, consumerContractsAmount) + if err != nil { + return nil, err + } + err = chainClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + return &VRFV2WrapperContracts{vrfv2Wrapper, consumers}, nil +} + func CreateVRFV2Job( chainlinkNode *client.ChainlinkClient, coordinatorAddress string, @@ -213,7 +254,7 @@ func SetupVRFV2Environment( l.Info().Str("Coordinator", vrfv2Contracts.Coordinator.Address()).Msg("Setting Coordinator Config") err = vrfv2Contracts.Coordinator.SetConfig( vrfv2Config.MinimumConfirmations, - vrfv2Config.CallbackGasLimit, + vrfv2Config.MaxGasLimitCoordinatorConfig, vrfv2Config.StalenessSeconds, vrfv2Config.GasAfterPaymentCalculation, big.NewInt(vrfv2Config.LinkNativeFeedResponse), @@ -308,6 +349,80 @@ func SetupVRFV2Environment( return vrfv2Contracts, subIDs, &data, nil } +func SetupVRFV2WrapperEnvironment( + env *test_env.CLClusterTestEnv, + vrfv2Config vrfv2_config.VRFV2Config, + linkToken contracts.LinkToken, + mockNativeLINKFeed contracts.MockETHLINKFeed, + coordinator contracts.VRFCoordinatorV2, + keyHash [32]byte, + wrapperConsumerContractsAmount int, +) (*VRFV2WrapperContracts, *uint64, error) { + // Deploy VRF v2 direct funding contracts + wrapperContracts, err := DeployVRFV2DirectFundingContracts( + env.ContractDeployer, + env.EVMClient, + linkToken.Address(), + mockNativeLINKFeed.Address(), + coordinator, + wrapperConsumerContractsAmount, + ) + if err != nil { + return nil, nil, err + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + // Configure VRF v2 wrapper contract + err = wrapperContracts.VRFV2Wrapper.SetConfig( + vrfv2Config.WrapperGasOverhead, + vrfv2Config.CoordinatorGasOverhead, + vrfv2Config.WrapperPremiumPercentage, + keyHash, + vrfv2Config.WrapperMaxNumberOfWords, + ) + if err != nil { + return nil, nil, err + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + // Fetch wrapper subscription ID + wrapperSubID, err := wrapperContracts.VRFV2Wrapper.GetSubID(context.Background()) + if err != nil { + return nil, nil, err + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + // Fund wrapper subscription + err = FundSubscriptions(env, vrfv2Config, linkToken, coordinator, []uint64{wrapperSubID}) + if err != nil { + return nil, nil, err + } + + // Fund consumer with LINK + err = linkToken.Transfer( + wrapperContracts.LoadTestConsumers[0].Address(), + big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(vrfv2Config.WrapperConsumerFundingAmountLink)), + ) + if err != nil { + return nil, nil, err + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + return wrapperContracts, &wrapperSubID, nil +} + func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, vrfv2Config vrfv2_config.VRFV2Config, numberOfNativeTokenAddressesToCreate int, chainID *big.Int) ([]string, error) { var newNativeTokenKeyAddresses []string for i := 0; i < numberOfNativeTokenAddressesToCreate; i++ { @@ -458,6 +573,41 @@ func FundSubscriptions( return nil } +func DirectFundingRequestRandomnessAndWaitForFulfillment( + consumer contracts.VRFv2WrapperLoadTestConsumer, + coordinator contracts.VRFCoordinatorV2, + vrfv2Data *VRFV2Data, + subID uint64, + randomnessRequestCountPerRequest uint16, + vrfv2Config vrfv2_config.VRFV2Config, + randomWordsFulfilledEventTimeout time.Duration, + l zerolog.Logger, +) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { + logRandRequest(consumer.Address(), coordinator.Address(), subID, vrfv2Config, l) + _, err := consumer.RequestRandomness( + vrfv2Config.MinimumConfirmations, + vrfv2Config.CallbackGasLimit, + vrfv2Config.NumberOfWords, + randomnessRequestCountPerRequest, + ) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrRequestRandomness, err) + } + wrapperAddress, err := consumer.GetWrapper(context.Background()) + if err != nil { + return nil, fmt.Errorf("error getting wrapper address, err: %w", err) + } + fulfillmentEvents, err := WaitForRequestAndFulfillmentEvents( + wrapperAddress.String(), + coordinator, + vrfv2Data, + subID, + randomWordsFulfilledEventTimeout, + l, + ) + return fulfillmentEvents, err +} + func RequestRandomnessAndWaitForFulfillment( consumer contracts.VRFv2LoadTestConsumer, coordinator contracts.VRFCoordinatorV2, diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index ef1eb34e4ea..40694aa5e4e 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -116,12 +116,14 @@ type ContractDeployer interface { DeployVRFConsumerV2(linkAddr string, coordinatorAddr string) (VRFConsumerV2, error) DeployVRFv2Consumer(coordinatorAddr string) (VRFv2Consumer, error) DeployVRFv2LoadTestConsumer(coordinatorAddr string) (VRFv2LoadTestConsumer, error) + DeployVRFV2WrapperLoadTestConsumer(linkAddr string, vrfV2WrapperAddr string) (VRFv2WrapperLoadTestConsumer, error) DeployVRFv2PlusLoadTestConsumer(coordinatorAddr string) (VRFv2PlusLoadTestConsumer, error) DeployVRFV2PlusWrapperLoadTestConsumer(linkAddr string, vrfV2PlusWrapperAddr string) (VRFv2PlusWrapperLoadTestConsumer, error) DeployVRFCoordinator(linkAddr string, bhsAddr string) (VRFCoordinator, error) DeployVRFCoordinatorV2(linkAddr string, bhsAddr string, linkEthFeedAddr string) (VRFCoordinatorV2, error) DeployVRFCoordinatorV2_5(bhsAddr string) (VRFCoordinatorV2_5, error) DeployVRFCoordinatorV2PlusUpgradedVersion(bhsAddr string) (VRFCoordinatorV2PlusUpgradedVersion, error) + DeployVRFV2Wrapper(linkAddr string, linkEthFeedAddr string, coordinatorAddr string) (VRFV2Wrapper, error) DeployVRFV2PlusWrapper(linkAddr string, linkEthFeedAddr string, coordinatorAddr string) (VRFV2PlusWrapper, error) DeployDKG() (DKG, error) DeployOCR2VRFCoordinator(beaconPeriodBlocksCount *big.Int, linkAddr string) (VRFCoordinatorV3, error) diff --git a/integration-tests/contracts/contract_vrf_models.go b/integration-tests/contracts/contract_vrf_models.go index 898abb521b3..44bc3ec2a2c 100644 --- a/integration-tests/contracts/contract_vrf_models.go +++ b/integration-tests/contracts/contract_vrf_models.go @@ -14,6 +14,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2_consumer_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2_wrapper_load_test_consumer" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/dkg" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" @@ -36,6 +37,7 @@ type VRFCoordinator interface { } type VRFCoordinatorV2 interface { + GetRequestConfig(ctx context.Context) (GetRequestConfig, error) SetConfig( minimumRequestConfirmations uint16, maxGasLimit uint32, @@ -136,6 +138,12 @@ type VRFCoordinatorV2PlusUpgradedVersion interface { WaitForRandomWordsRequestedEvent(keyHash [][32]byte, subID []*big.Int, sender []common.Address, timeout time.Duration) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsRequested, error) } +type VRFV2Wrapper interface { + Address() string + SetConfig(wrapperGasOverhead uint32, coordinatorGasOverhead uint32, wrapperPremiumPercentage uint8, keyHash [32]byte, maxNumWords uint8) error + GetSubID(ctx context.Context) (uint64, error) +} + type VRFV2PlusWrapper interface { Address() string SetConfig(wrapperGasOverhead uint32, coordinatorGasOverhead uint32, wrapperPremiumPercentage uint8, keyHash [32]byte, maxNumWords uint8, stalenessSeconds uint32, fallbackWeiPerUnitLink *big.Int, fulfillmentFlatFeeLinkPPM uint32, fulfillmentFlatFeeNativePPM uint32) error @@ -178,6 +186,16 @@ type VRFv2LoadTestConsumer interface { ResetMetrics() error } +type VRFv2WrapperLoadTestConsumer interface { + Address() string + Fund(ethAmount *big.Float) error + RequestRandomness(requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16) (*types.Transaction, error) + GetRequestStatus(ctx context.Context, requestID *big.Int) (vrfv2_wrapper_load_test_consumer.GetRequestStatus, error) + GetLastRequestId(ctx context.Context) (*big.Int, error) + GetWrapper(ctx context.Context) (common.Address, error) + GetLoadTestMetrics(ctx context.Context) (*VRFLoadTestMetrics, error) +} + type VRFv2PlusLoadTestConsumer interface { Address() string RequestRandomness(keyHash [32]byte, subID *big.Int, requestConfirmations uint16, callbackGasLimit uint32, nativePayment bool, numWords uint32, requestCount uint16) (*types.Transaction, error) diff --git a/integration-tests/contracts/ethereum_vrfv2_contracts.go b/integration-tests/contracts/ethereum_vrfv2_contracts.go index 5d22167158a..579174e07c6 100644 --- a/integration-tests/contracts/ethereum_vrfv2_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2_contracts.go @@ -18,6 +18,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_consumer_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_load_test_with_metrics" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2_wrapper_load_test_consumer" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2_consumer_wrapper" ) @@ -50,6 +52,24 @@ type EthereumVRFv2LoadTestConsumer struct { consumer *vrf_load_test_with_metrics.VRFV2LoadTestWithMetrics } +type EthereumVRFV2Wrapper struct { + address *common.Address + client blockchain.EVMClient + wrapper *vrfv2_wrapper.VRFV2Wrapper +} + +type EthereumVRFV2WrapperLoadTestConsumer struct { + address *common.Address + client blockchain.EVMClient + consumer *vrfv2_wrapper_load_test_consumer.VRFV2WrapperLoadTestConsumer +} + +type GetRequestConfig struct { + MinimumRequestConfirmations uint16 + MaxGasLimit uint32 + ProvingKeyHashes [32]byte +} + // DeployVRFCoordinatorV2 deploys VRFV2 coordinator contract func (e *EthereumContractDeployer) DeployVRFCoordinatorV2(linkAddr string, bhsAddr string, linkEthFeedAddr string) (VRFCoordinatorV2, error) { address, _, instance, err := e.client.DeployContract("VRFCoordinatorV2", func( @@ -121,6 +141,40 @@ func (e *EthereumContractDeployer) DeployVRFv2LoadTestConsumer(coordinatorAddr s }, err } +func (e *EthereumContractDeployer) DeployVRFV2Wrapper(linkAddr string, linkEthFeedAddr string, coordinatorAddr string) (VRFV2Wrapper, error) { + address, _, instance, err := e.client.DeployContract("VRFV2Wrapper", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return vrfv2_wrapper.DeployVRFV2Wrapper(auth, backend, common.HexToAddress(linkAddr), common.HexToAddress(linkEthFeedAddr), common.HexToAddress(coordinatorAddr)) + }) + if err != nil { + return nil, err + } + return &EthereumVRFV2Wrapper{ + address: address, + client: e.client, + wrapper: instance.(*vrfv2_wrapper.VRFV2Wrapper), + }, err +} + +func (e *EthereumContractDeployer) DeployVRFV2WrapperLoadTestConsumer(linkAddr string, vrfV2WrapperAddr string) (VRFv2WrapperLoadTestConsumer, error) { + address, _, instance, err := e.client.DeployContract("VRFV2WrapperLoadTestConsumer", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return vrfv2_wrapper_load_test_consumer.DeployVRFV2WrapperLoadTestConsumer(auth, backend, common.HexToAddress(linkAddr), common.HexToAddress(vrfV2WrapperAddr)) + }) + if err != nil { + return nil, err + } + return &EthereumVRFV2WrapperLoadTestConsumer{ + address: address, + client: e.client, + consumer: instance.(*vrfv2_wrapper_load_test_consumer.VRFV2WrapperLoadTestConsumer), + }, err +} + func (v *EthereumVRFCoordinatorV2) Address() string { return v.address.Hex() } @@ -149,6 +203,24 @@ func (v *EthereumVRFCoordinatorV2) GetSubscription(ctx context.Context, subID ui return subscription, nil } +func (v *EthereumVRFCoordinatorV2) GetRequestConfig(ctx context.Context) (GetRequestConfig, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + } + minConfirmations, maxGas, keyHashes, err := v.coordinator.GetRequestConfig(opts) + if err != nil { + return GetRequestConfig{}, err + } + requestConfig := GetRequestConfig{ + MinimumRequestConfirmations: minConfirmations, + MaxGasLimit: maxGas, + ProvingKeyHashes: keyHashes[0], + } + + return requestConfig, nil +} + func (v *EthereumVRFCoordinatorV2) SetConfig(minimumRequestConfirmations uint16, maxGasLimit uint32, stalenessSeconds uint32, gasAfterPaymentCalculation uint32, fallbackWeiPerUnitLink *big.Int, feeConfig vrf_coordinator_v2.VRFCoordinatorV2FeeConfig) error { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { @@ -599,3 +671,126 @@ func (v *EthereumVRFv2LoadTestConsumer) GetLoadTestMetrics(ctx context.Context) fastestFulfillment, }, nil } + +func (v *EthereumVRFV2Wrapper) Address() string { + return v.address.Hex() +} + +func (v *EthereumVRFV2Wrapper) SetConfig(wrapperGasOverhead uint32, coordinatorGasOverhead uint32, wrapperPremiumPercentage uint8, keyHash [32]byte, maxNumWords uint8) error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.wrapper.SetConfig( + opts, + wrapperGasOverhead, + coordinatorGasOverhead, + wrapperPremiumPercentage, + keyHash, + maxNumWords, + ) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} + +func (v *EthereumVRFV2Wrapper) GetSubID(ctx context.Context) (uint64, error) { + return v.wrapper.SUBSCRIPTIONID(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }) +} + +func (v *EthereumVRFV2WrapperLoadTestConsumer) Address() string { + return v.address.Hex() +} + +func (v *EthereumVRFV2WrapperLoadTestConsumer) Fund(ethAmount *big.Float) error { + gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{}) + if err != nil { + return err + } + return v.client.Fund(v.address.Hex(), ethAmount, gasEstimates) +} + +func (v *EthereumVRFV2WrapperLoadTestConsumer) RequestRandomness(requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16) (*types.Transaction, error) { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + tx, err := v.consumer.MakeRequests(opts, callbackGasLimit, requestConfirmations, numWords, requestCount) + if err != nil { + return nil, err + } + return tx, v.client.ProcessTransaction(tx) +} + +func (v *EthereumVRFV2WrapperLoadTestConsumer) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrfv2_wrapper_load_test_consumer.GetRequestStatus, error) { + return v.consumer.GetRequestStatus(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }, requestID) +} + +func (v *EthereumVRFV2WrapperLoadTestConsumer) GetLastRequestId(ctx context.Context) (*big.Int, error) { + return v.consumer.SLastRequestId(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }) +} + +func (v *EthereumVRFV2WrapperLoadTestConsumer) GetWrapper(ctx context.Context) (common.Address, error) { + return v.consumer.IVrfV2Wrapper(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }) +} + +func (v *EthereumVRFV2WrapperLoadTestConsumer) GetLoadTestMetrics(ctx context.Context) (*VRFLoadTestMetrics, error) { + requestCount, err := v.consumer.SRequestCount(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }) + if err != nil { + return nil, err + } + fulfilmentCount, err := v.consumer.SResponseCount(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }) + + if err != nil { + return nil, err + } + averageFulfillmentInMillions, err := v.consumer.SAverageFulfillmentInMillions(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }) + if err != nil { + return nil, err + } + slowestFulfillment, err := v.consumer.SSlowestFulfillment(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }) + + if err != nil { + return nil, err + } + fastestFulfillment, err := v.consumer.SFastestFulfillment(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }) + if err != nil { + return nil, err + } + + return &VRFLoadTestMetrics{ + requestCount, + fulfilmentCount, + averageFulfillmentInMillions, + slowestFulfillment, + fastestFulfillment, + }, nil +} diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index f5719277609..8cdb566b92c 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -3,10 +3,12 @@ package test_env import ( "context" "fmt" + "io" "maps" "math/big" "net/url" "os" + "regexp" "strings" "testing" "time" @@ -15,6 +17,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" "github.com/pelletier/go-toml/v2" + "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/rs/zerolog/log" tc "github.com/testcontainers/testcontainers-go" @@ -48,6 +51,10 @@ type ClNode struct { PostgresDb *test_env.PostgresDb `json:"postgresDb"` UserEmail string `json:"userEmail"` UserPassword string `json:"userPassword"` + AlwaysPullImage bool `json:"-"` + PostStartsHooks []tc.ContainerHook `json:"-"` + PostStopsHooks []tc.ContainerHook `json:"-"` + PreTerminatesHooks []tc.ContainerHook `json:"-"` t *testing.T l zerolog.Logger ls *logstream.LogStream @@ -136,12 +143,32 @@ func NewClNode(networks []string, imageName, imageVersion string, nodeConfig *ch PostgresDb: pgDb, l: log.Logger, } + n.SetDefaultHooks() for _, opt := range opts { opt(n) } return n, nil } +func (n *ClNode) SetDefaultHooks() { + n.PostStartsHooks = []tc.ContainerHook{ + func(ctx context.Context, c tc.Container) error { + if n.ls != nil { + return n.ls.ConnectContainer(ctx, c, "cl-node") + } + return nil + }, + } + n.PostStopsHooks = []tc.ContainerHook{ + func(ctx context.Context, c tc.Container) error { + if n.ls != nil { + return n.ls.DisconnectContainer(c) + } + return nil + }, + } +} + func (n *ClNode) SetTestLogger(t *testing.T) { n.l = logging.GetTestLogger(t) n.t = t @@ -361,6 +388,28 @@ func (n *ClNode) StartContainer() error { return nil } +func (n *ClNode) ExecGetVersion() (string, error) { + cmd := []string{"chainlink", "--version"} + _, output, err := n.Container.Exec(context.Background(), cmd) + if err != nil { + return "", errors.Wrapf(err, "could not execute cmd %s", cmd) + } + outputBytes, err := io.ReadAll(output) + if err != nil { + return "", err + } + outputString := strings.TrimSpace(string(outputBytes)) + + // Find version in cmd output + re := regexp.MustCompile("@(.*)") + matches := re.FindStringSubmatch(outputString) + + if len(matches) > 1 { + return matches[1], nil + } + return "", errors.Errorf("could not find chainlink version in command output '%'", output) +} + func (n *ClNode) getContainerRequest(secrets string) ( *tc.ContainerRequest, error) { configFile, err := os.CreateTemp("", "node_config") @@ -410,10 +459,11 @@ func (n *ClNode) getContainerRequest(secrets string) ( apiCredsPath := "/home/api-credentials.txt" return &tc.ContainerRequest{ - Name: n.ContainerName, - Image: fmt.Sprintf("%s:%s", n.ContainerImage, n.ContainerVersion), - ExposedPorts: []string{"6688/tcp"}, - Env: n.ContainerEnvs, + Name: n.ContainerName, + AlwaysPullImage: n.AlwaysPullImage, + Image: fmt.Sprintf("%s:%s", n.ContainerImage, n.ContainerVersion), + ExposedPorts: []string{"6688/tcp"}, + Env: n.ContainerEnvs, Entrypoint: []string{"chainlink", "-c", configPath, "-s", secretsPath, @@ -449,22 +499,11 @@ func (n *ClNode) getContainerRequest(secrets string) ( }, }, LifecycleHooks: []tc.ContainerLifecycleHooks{ - {PostStarts: []tc.ContainerHook{ - func(ctx context.Context, c tc.Container) error { - if n.ls != nil { - return n.ls.ConnectContainer(ctx, c, "cl-node") - } - return nil - }, + { + PostStarts: n.PostStartsHooks, + PostStops: n.PostStopsHooks, + PreTerminates: n.PreTerminatesHooks, }, - PostStops: []tc.ContainerHook{ - func(ctx context.Context, c tc.Container) error { - if n.ls != nil { - return n.ls.DisconnectContainer(c) - } - return nil - }, - }}, }, }, nil } diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index 7358d76f2af..bd73d33d9bf 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -59,7 +59,8 @@ type CLTestEnvBuilder struct { func NewCLTestEnvBuilder() *CLTestEnvBuilder { return &CLTestEnvBuilder{ - l: log.Logger, + l: log.Logger, + hasLogStream: true, } } @@ -101,8 +102,9 @@ func (b *CLTestEnvBuilder) WithTestInstance(t *testing.T) *CLTestEnvBuilder { return b } -func (b *CLTestEnvBuilder) WithLogStream() *CLTestEnvBuilder { - b.hasLogStream = true +// WithoutLogStream disables LogStream logging component +func (b *CLTestEnvBuilder) WithoutLogStream() *CLTestEnvBuilder { + b.hasLogStream = false return b } diff --git a/integration-tests/go.mod b/integration-tests/go.mod index a9b4808dd8f..83e7f7847d0 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -25,7 +25,7 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240110155415-407896b07206 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240113162114-77e747a4ef17 github.com/smartcontractkit/chainlink-testing-framework v1.22.1 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 @@ -363,7 +363,7 @@ require ( github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231222201016-da3f0a763f71 // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 // indirect - github.com/smartcontractkit/chainlink-feeds v0.0.0-20240112193433-af835dc4b1a3 // indirect + github.com/smartcontractkit/chainlink-feeds v0.0.0-20240113162230-9b808fd915ee // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231222220348-c7d81beaf8fd // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231221191127-1f32389044ea // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 4bbb4caae43..95842250b41 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1481,14 +1481,14 @@ github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumv github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= github.com/smartcontractkit/chainlink-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240110155415-407896b07206 h1:CfKu1c/DBx5qi1lFC9e/aVWwO0IyWKw2poBQR2VflnA= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240110155415-407896b07206/go.mod h1:f+0ei9N4PlTJHu7pbGzEjTnBUr45syPdGFu5+31lS5Q= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240113162114-77e747a4ef17 h1:/2FBQi0y48AwRq0Rr34JKsINAf7WHcaHr8XdbVXDt54= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240113162114-77e747a4ef17/go.mod h1:f+0ei9N4PlTJHu7pbGzEjTnBUr45syPdGFu5+31lS5Q= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231222201016-da3f0a763f71 h1:Ju0cxdrzGFwHGDPp16IzkOyX87LZ/kKDFG1A+VSEJHY= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231222201016-da3f0a763f71/go.mod h1:Ppv5X8MTUkkpKdb270dLefjio724vMkCWmSSaWo7CzI= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20240112193433-af835dc4b1a3 h1:w18bLofojboL74efMvH9iePjBa3KwlpvxR0FL/DN9Wc= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20240112193433-af835dc4b1a3/go.mod h1:L2b9/3wYVUqPAeKG/SLG/T0VsMOJtg+ygw8vTmRDMGE= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240113162230-9b808fd915ee h1:EC8tcNKx3f6qYln5WD+xVhzz60PKPH+sgrbjzAm3xcw= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240113162230-9b808fd915ee/go.mod h1:kXeFFq7kA+pmeG/A27wMi3geIRGn7G+r61v787ZyJtU= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231222220348-c7d81beaf8fd h1:9xSwDgRJDIfDw6171PQEyn5IQ1JKpaJnG5NX6KfCaHQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231222220348-c7d81beaf8fd/go.mod h1:kY435jBtHbyzhe+ImAxZ6G229uHbB0ablA+A0tJkDn8= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231221191127-1f32389044ea h1:WzMa0O6DEauMYMIjzS/T1JF8zvFDt4aG6EUTDlStaZo= diff --git a/integration-tests/load/functions/config.go b/integration-tests/load/functions/config.go index ad7e7446afb..d34e8a9f1eb 100644 --- a/integration-tests/load/functions/config.go +++ b/integration-tests/load/functions/config.go @@ -8,7 +8,7 @@ import ( "github.com/pelletier/go-toml/v2" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" ) const ( @@ -56,49 +56,49 @@ type Funding struct { } type Soak struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *models.Duration `toml:"duration"` + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *commonconfig.Duration `toml:"duration"` } type SecretsSoak struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *models.Duration `toml:"duration"` + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *commonconfig.Duration `toml:"duration"` } type RealSoak struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *models.Duration `toml:"duration"` + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *commonconfig.Duration `toml:"duration"` } type Stress struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *models.Duration `toml:"duration"` + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *commonconfig.Duration `toml:"duration"` } type SecretsStress struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *models.Duration `toml:"duration"` + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *commonconfig.Duration `toml:"duration"` } type RealStress struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *models.Duration `toml:"duration"` + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *commonconfig.Duration `toml:"duration"` } type GatewayListSoak struct { - RPS int64 `toml:"rps"` - Duration *models.Duration `toml:"duration"` + RPS int64 `toml:"rps"` + Duration *commonconfig.Duration `toml:"duration"` } type GatewaySetSoak struct { - RPS int64 `toml:"rps"` - Duration *models.Duration `toml:"duration"` + RPS int64 `toml:"rps"` + Duration *commonconfig.Duration `toml:"duration"` } func ReadConfig() (*PerformanceConfig, error) { diff --git a/integration-tests/load/ocr/README.md b/integration-tests/load/ocr/README.md index 3c231b50278..61951ba700f 100644 --- a/integration-tests/load/ocr/README.md +++ b/integration-tests/load/ocr/README.md @@ -1,21 +1,12 @@ -# OCR Load tests +### OCR Load tests ## Setup - These tests can connect to any cluster create with [chainlink-cluster](../../../charts/chainlink-cluster/README.md) -<<<<<<< HEAD -Create your cluster - -```sh -kubectl create ns my-cluster -devspace use namespace my-cluster -======= Create your cluster, if you already have one just use `kubefwd` ``` kubectl create ns cl-cluster devspace use namespace cl-cluster ->>>>>>> 06656fac80999d1539e16951a54b87c6df13a9c7 devspace deploy sudo kubefwd svc -n cl-cluster ``` @@ -26,7 +17,7 @@ If you haven't changed anything in [devspace.yaml](../../../charts/chainlink-clu ## Usage -```sh +``` export LOKI_TOKEN=... export LOKI_URL=... @@ -34,4 +25,4 @@ go test -v -run TestOCRLoad go test -v -run TestOCRVolume ``` -Check test configuration [here](config.toml) +Check test configuration [here](config.toml) \ No newline at end of file diff --git a/integration-tests/load/ocr/config.go b/integration-tests/load/ocr/config.go index 2991df3774a..4b324210b09 100644 --- a/integration-tests/load/ocr/config.go +++ b/integration-tests/load/ocr/config.go @@ -8,7 +8,7 @@ import ( "github.com/pelletier/go-toml/v2" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" ) const ( @@ -28,22 +28,22 @@ type Common struct { } type Load struct { - TestDuration *models.Duration `toml:"test_duration"` - Rate int64 `toml:"rate"` - RateLimitUnitDuration *models.Duration `toml:"rate_limit_unit_duration"` - VerificationInterval *models.Duration `toml:"verification_interval"` - VerificationTimeout *models.Duration `toml:"verification_timeout"` - EAChangeInterval *models.Duration `toml:"ea_change_interval"` + TestDuration *commonconfig.Duration `toml:"test_duration"` + Rate int64 `toml:"rate"` + RateLimitUnitDuration *commonconfig.Duration `toml:"rate_limit_unit_duration"` + VerificationInterval *commonconfig.Duration `toml:"verification_interval"` + VerificationTimeout *commonconfig.Duration `toml:"verification_timeout"` + EAChangeInterval *commonconfig.Duration `toml:"ea_change_interval"` } type Volume struct { - TestDuration *models.Duration `toml:"test_duration"` - Rate int64 `toml:"rate"` - VURequestsPerUnit int `toml:"vu_requests_per_unit"` - RateLimitUnitDuration *models.Duration `toml:"rate_limit_unit_duration"` - VerificationInterval *models.Duration `toml:"verification_interval"` - VerificationTimeout *models.Duration `toml:"verification_timeout"` - EAChangeInterval *models.Duration `toml:"ea_change_interval"` + TestDuration *commonconfig.Duration `toml:"test_duration"` + Rate int64 `toml:"rate"` + VURequestsPerUnit int `toml:"vu_requests_per_unit"` + RateLimitUnitDuration *commonconfig.Duration `toml:"rate_limit_unit_duration"` + VerificationInterval *commonconfig.Duration `toml:"verification_interval"` + VerificationTimeout *commonconfig.Duration `toml:"verification_timeout"` + EAChangeInterval *commonconfig.Duration `toml:"ea_change_interval"` } func ReadConfig() (*PerformanceConfig, error) { diff --git a/integration-tests/load/vrfv2/config.go b/integration-tests/load/vrfv2/config.go index d5e94bb75fb..e97ac6a964e 100644 --- a/integration-tests/load/vrfv2/config.go +++ b/integration-tests/load/vrfv2/config.go @@ -10,7 +10,7 @@ import ( "github.com/pelletier/go-toml/v2" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" ) const ( @@ -86,10 +86,10 @@ type PerformanceTestConfig struct { NumberOfSubToCreate int `toml:"number_of_sub_to_create"` RPS int64 `toml:"rps"` - //Duration *models.Duration `toml:"duration"` - RateLimitUnitDuration *models.Duration `toml:"rate_limit_unit_duration"` - RandomnessRequestCountPerRequest uint16 `toml:"randomness_request_count_per_request"` - RandomnessRequestCountPerRequestDeviation uint16 `toml:"randomness_request_count_per_request_deviation"` + //Duration *commonconfig.Duration `toml:"duration"` + RateLimitUnitDuration *commonconfig.Duration `toml:"rate_limit_unit_duration"` + RandomnessRequestCountPerRequest uint16 `toml:"randomness_request_count_per_request"` + RandomnessRequestCountPerRequestDeviation uint16 `toml:"randomness_request_count_per_request_deviation"` } func ReadConfig() (*PerformanceConfig, error) { diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go index ec0f945870d..c48f3488594 100644 --- a/integration-tests/load/vrfv2/vrfv2_test.go +++ b/integration-tests/load/vrfv2/vrfv2_test.go @@ -184,7 +184,6 @@ func TestVRFV2Performance(t *testing.T) { l.Error().Err(err).Msg("Error cleaning up test environment") } }). - WithLogStream(). Build() require.NoError(t, err, "error creating test env") diff --git a/integration-tests/load/vrfv2plus/config.go b/integration-tests/load/vrfv2plus/config.go index 43bcf44d044..2fc6b6a4c7f 100644 --- a/integration-tests/load/vrfv2plus/config.go +++ b/integration-tests/load/vrfv2plus/config.go @@ -8,8 +8,8 @@ import ( "github.com/pelletier/go-toml/v2" "github.com/rs/zerolog/log" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) const ( @@ -86,10 +86,10 @@ type PerformanceTestConfig struct { NumberOfSubToCreate int `toml:"number_of_sub_to_create"` RPS int64 `toml:"rps"` - //Duration *models.Duration `toml:"duration"` - RateLimitUnitDuration *models.Duration `toml:"rate_limit_unit_duration"` - RandomnessRequestCountPerRequest uint16 `toml:"randomness_request_count_per_request"` - RandomnessRequestCountPerRequestDeviation uint16 `toml:"randomness_request_count_per_request_deviation"` + //Duration *commonconfig.Duration `toml:"duration"` + RateLimitUnitDuration *commonconfig.Duration `toml:"rate_limit_unit_duration"` + RandomnessRequestCountPerRequest uint16 `toml:"randomness_request_count_per_request"` + RandomnessRequestCountPerRequestDeviation uint16 `toml:"randomness_request_count_per_request_deviation"` } func ReadConfig() (*PerformanceConfig, error) { diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index 069e3115aee..74be537c753 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -189,7 +189,6 @@ func TestVRFV2PlusPerformance(t *testing.T) { l.Error().Err(err).Msg("Error cleaning up test environment") } }). - WithLogStream(). Build() require.NoError(t, err, "error creating test env") diff --git a/integration-tests/scripts/buildTestMatrixList.sh b/integration-tests/scripts/buildTestMatrixList.sh index 7f058b5b659..f02362aa47a 100755 --- a/integration-tests/scripts/buildTestMatrixList.sh +++ b/integration-tests/scripts/buildTestMatrixList.sh @@ -40,24 +40,26 @@ jq -c '.tests[]' ${JSONFILE} | while read -r test; do effective_node_count=${node_count:-$NODE_COUNT} subTests=$(echo ${test} | jq -r '.run[]?.name // empty') output="" + + if [ $COUNTER -ne 1 ]; then + echo -n "," + fi # Loop through subtests, if any, and print in the desired format if [ -n "$subTests" ]; then + subTestString="" + subTestCounter=1 for subTest in $subTests; do - if [ $COUNTER -ne 1 ]; then - echo -n "," + if [ $subTestCounter -ne 1 ]; then + subTestString+="|" fi - matrix_output $COUNTER $MATRIX_JOB_NAME "${testName}/${subTest}" ${effective_node_label} ${effective_node_count} - ((COUNTER++)) + subTestString+="${testName}\/${subTest}" + ((subTestCounter++)) done - else - if [ $COUNTER -ne 1 ]; then - echo -n "," - fi - matrix_output $COUNTER $MATRIX_JOB_NAME "${testName}" ${effective_node_label} ${effective_node_count} - ((COUNTER++)) + testName="${subTestString}" fi - + matrix_output $COUNTER $MATRIX_JOB_NAME "${testName}" ${effective_node_label} ${effective_node_count} + ((COUNTER++)) done > "./tmpout.json" OUTPUT=$(cat ./tmpout.json) echo "[${OUTPUT}]" diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 1dbfc78ec87..0bdb6cf1f4e 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -29,16 +29,15 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams" ) var utilsABI = cltypes.MustGetABI(automation_utils_2_1.AutomationUtilsABI) @@ -90,9 +89,9 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { "registry_2_1_with_logtrigger_and_mercury_v02": ethereum.RegistryVersion_2_1, } - for n, rv := range registryVersions { - name := n - registryVersion := rv + for name, registryVersion := range registryVersions { + name := name + registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) @@ -168,7 +167,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", int64(expect)), "Expected consumer counter to be greater than %d, but got %d", expect, counter.Int64()) } - }, "5m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~2m for performing each upkeep 5 times, ~2m buffer + }, "10m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~2m for performing each upkeep 5 times, ~2m buffer l.Info().Msgf("Total time taken to get 5 performs for each upkeep: %s", time.Since(startTime)) @@ -400,9 +399,9 @@ func TestAutomationAddFunds(t *testing.T) { "registry_2_1": ethereum.RegistryVersion_2_1, } - for n, rv := range registryVersions { - name := n - registryVersion := rv + for name, registryVersion := range registryVersions { + name := name + registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() a := setupAutomationTestDocker( @@ -557,9 +556,9 @@ func TestAutomationRegisterUpkeep(t *testing.T) { "registry_2_1": ethereum.RegistryVersion_2_1, } - for n, rv := range registryVersions { - name := n - registryVersion := rv + for name, registryVersion := range registryVersions { + name := name + registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) @@ -641,9 +640,9 @@ func TestAutomationPauseRegistry(t *testing.T) { "registry_2_1": ethereum.RegistryVersion_2_1, } - for n, rv := range registryVersions { - name := n - registryVersion := rv + for name, registryVersion := range registryVersions { + name := name + registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() a := setupAutomationTestDocker( @@ -710,9 +709,9 @@ func TestAutomationKeeperNodesDown(t *testing.T) { "registry_2_1": ethereum.RegistryVersion_2_1, } - for n, rv := range registryVersions { - name := n - registryVersion := rv + for name, registryVersion := range registryVersions { + name := name + registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) @@ -810,9 +809,9 @@ func TestAutomationPerformSimulation(t *testing.T) { "registry_2_1": ethereum.RegistryVersion_2_1, } - for n, rv := range registryVersions { - name := n - registryVersion := rv + for name, registryVersion := range registryVersions { + name := name + registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() a := setupAutomationTestDocker( @@ -873,9 +872,9 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { "registry_2_1": ethereum.RegistryVersion_2_1, } - for n, rv := range registryVersions { - name := n - registryVersion := rv + for name, registryVersion := range registryVersions { + name := name + registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) @@ -987,9 +986,9 @@ func TestUpdateCheckData(t *testing.T) { "registry_2_1": ethereum.RegistryVersion_2_1, } - for n, rv := range registryVersions { - name := n - registryVersion := rv + for name, registryVersion := range registryVersions { + name := name + registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) @@ -1073,7 +1072,7 @@ func setupAutomationTestDocker( // build the node config clNodeConfig := node.NewConfig(node.NewBaseConfig()) - syncInterval := models.MustMakeDuration(5 * time.Minute) + syncInterval := *commonconfig.MustNewDuration(5 * time.Minute) clNodeConfig.Feature.LogPoller = ptr.Ptr[bool](true) clNodeConfig.OCR2.Enabled = ptr.Ptr[bool](true) clNodeConfig.Keeper.TurnLookBack = ptr.Ptr[int64](int64(0)) @@ -1097,7 +1096,6 @@ func setupAutomationTestDocker( WithMockAdapter(). WithFunding(big.NewFloat(testConfig.ChainlinkNodeFunding)). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err, "Error deploying test environment for Mercury") env.ParallelTransactions(true) diff --git a/integration-tests/smoke/automation_test.go_test_list.json b/integration-tests/smoke/automation_test.go_test_list.json index 5bf941ed2ce..b88684599c7 100644 --- a/integration-tests/smoke/automation_test.go_test_list.json +++ b/integration-tests/smoke/automation_test.go_test_list.json @@ -2,8 +2,30 @@ "tests": [ { "name": "TestAutomationBasic", - "label": "ubuntu-latest-32cores-128GB", - "nodes": 6 + "label": "ubuntu-latest", + "nodes": 2, + "run":[ + {"name":"registry_2_0"}, + {"name":"registry_2_1_conditional"} + ] + }, + { + "name": "TestAutomationBasic", + "label": "ubuntu-latest", + "nodes": 2, + "run":[ + {"name":"registry_2_1_logtrigger"}, + {"name":"registry_2_1_with_mercury_v02"} + ] + }, + { + "name": "TestAutomationBasic", + "label": "ubuntu-latest", + "nodes": 2, + "run":[ + {"name":"registry_2_1_with_mercury_v03"}, + {"name":"registry_2_1_with_logtrigger_and_mercury_v02"} + ] }, { "name": "TestSetUpkeepTriggerConfig" diff --git a/integration-tests/smoke/cron_test.go b/integration-tests/smoke/cron_test.go index 751c2867676..df1b85882e9 100644 --- a/integration-tests/smoke/cron_test.go +++ b/integration-tests/smoke/cron_test.go @@ -25,7 +25,6 @@ func TestCronBasic(t *testing.T) { WithMockAdapter(). WithCLNodes(1). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err) @@ -72,7 +71,6 @@ func TestCronJobReplacement(t *testing.T) { WithMockAdapter(). WithCLNodes(1). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err) diff --git a/integration-tests/smoke/flux_test.go b/integration-tests/smoke/flux_test.go index 828350a9422..345971e8922 100644 --- a/integration-tests/smoke/flux_test.go +++ b/integration-tests/smoke/flux_test.go @@ -31,7 +31,6 @@ func TestFluxBasic(t *testing.T) { WithMockAdapter(). WithCLNodes(3). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err) diff --git a/integration-tests/smoke/forwarder_ocr_test.go b/integration-tests/smoke/forwarder_ocr_test.go index c71c6e31516..fd8dfc780af 100644 --- a/integration-tests/smoke/forwarder_ocr_test.go +++ b/integration-tests/smoke/forwarder_ocr_test.go @@ -26,7 +26,6 @@ func TestForwarderOCRBasic(t *testing.T) { WithCLNodes(6). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err) @@ -68,7 +67,7 @@ func TestForwarderOCRBasic(t *testing.T) { err = actions.CreateOCRJobsWithForwarderLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID().String()) require.NoError(t, err, "failed to setup forwarder jobs") - err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) + err = actions.WatchNewRound(1, ocrInstances, env.EVMClient, l) require.NoError(t, err) err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") @@ -79,7 +78,7 @@ func TestForwarderOCRBasic(t *testing.T) { err = actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockAdapter) require.NoError(t, err) - err = actions.StartNewRound(2, ocrInstances, env.EVMClient, l) + err = actions.WatchNewRound(2, ocrInstances, env.EVMClient, l) require.NoError(t, err) err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") diff --git a/integration-tests/smoke/forwarders_ocr2_test.go b/integration-tests/smoke/forwarders_ocr2_test.go index 5bf7cc57030..f1a01643f5e 100644 --- a/integration-tests/smoke/forwarders_ocr2_test.go +++ b/integration-tests/smoke/forwarders_ocr2_test.go @@ -35,7 +35,6 @@ func TestForwarderOCR2Basic(t *testing.T) { WithCLNodes(6). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err) diff --git a/integration-tests/smoke/keeper_test.go b/integration-tests/smoke/keeper_test.go index 1bc416f0456..cac5aa93d36 100644 --- a/integration-tests/smoke/keeper_test.go +++ b/integration-tests/smoke/keeper_test.go @@ -11,12 +11,11 @@ import ( "github.com/onsi/gomega" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" @@ -1100,7 +1099,7 @@ func setupKeeperTest(t *testing.T) ( ) { clNodeConfig := node.NewConfig(node.NewBaseConfig(), node.WithP2Pv2()) turnLookBack := int64(0) - syncInterval := models.MustMakeDuration(5 * time.Second) + syncInterval := *commonconfig.MustNewDuration(5 * time.Second) performGasOverhead := uint32(150000) clNodeConfig.Keeper.TurnLookBack = &turnLookBack clNodeConfig.Keeper.Registry.SyncInterval = &syncInterval @@ -1113,7 +1112,6 @@ func setupKeeperTest(t *testing.T) ( WithCLNodeConfig(clNodeConfig). WithFunding(big.NewFloat(.5)). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err, "Error deploying test environment") diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index 124bc64c433..f45c324faed 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -58,7 +58,6 @@ func TestOCRv2Basic(t *testing.T) { WithCLNodes(6). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err) @@ -140,7 +139,6 @@ func TestOCRv2Request(t *testing.T) { WithCLNodes(6). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err) @@ -216,7 +214,6 @@ func TestOCRv2JobReplacement(t *testing.T) { WithCLNodes(6). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err) diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index ba158923812..5f091835894 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -27,7 +27,6 @@ func TestOCRBasic(t *testing.T) { WithCLNodes(6). WithFunding(big.NewFloat(.5)). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err) @@ -47,7 +46,7 @@ func TestOCRBasic(t *testing.T) { err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID()) require.NoError(t, err) - err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) + err = actions.WatchNewRound(1, ocrInstances, env.EVMClient, l) require.NoError(t, err) answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) @@ -56,7 +55,7 @@ func TestOCRBasic(t *testing.T) { err = actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockAdapter) require.NoError(t, err) - err = actions.StartNewRound(2, ocrInstances, env.EVMClient, l) + err = actions.WatchNewRound(2, ocrInstances, env.EVMClient, l) require.NoError(t, err) answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) @@ -94,7 +93,7 @@ func TestOCRJobReplacement(t *testing.T) { err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID()) require.NoError(t, err) - err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) + err = actions.WatchNewRound(1, ocrInstances, env.EVMClient, l) require.NoError(t, err) answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) @@ -103,7 +102,7 @@ func TestOCRJobReplacement(t *testing.T) { err = actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockAdapter) require.NoError(t, err) - err = actions.StartNewRound(2, ocrInstances, env.EVMClient, l) + err = actions.WatchNewRound(2, ocrInstances, env.EVMClient, l) require.NoError(t, err) answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) @@ -120,7 +119,7 @@ func TestOCRJobReplacement(t *testing.T) { err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID()) require.NoError(t, err) - err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) + err = actions.WatchNewRound(1, ocrInstances, env.EVMClient, l) require.NoError(t, err) answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) diff --git a/integration-tests/smoke/runlog_test.go b/integration-tests/smoke/runlog_test.go index 5cc21a28c2c..dc08b19b16f 100644 --- a/integration-tests/smoke/runlog_test.go +++ b/integration-tests/smoke/runlog_test.go @@ -29,7 +29,6 @@ func TestRunLogBasic(t *testing.T) { WithCLNodes(1). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err) diff --git a/integration-tests/smoke/vrf_test.go b/integration-tests/smoke/vrf_test.go index 0554bd34760..51ea3828cfd 100644 --- a/integration-tests/smoke/vrf_test.go +++ b/integration-tests/smoke/vrf_test.go @@ -29,7 +29,6 @@ func TestVRFBasic(t *testing.T) { WithCLNodes(1). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err) env.ParallelTransactions(true) @@ -119,7 +118,6 @@ func TestVRFJobReplacement(t *testing.T) { WithCLNodes(1). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err) env.ParallelTransactions(true) diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index 4167342c41f..8958480d51e 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -12,6 +12,8 @@ import ( "github.com/kelseyhightower/envconfig" "github.com/stretchr/testify/require" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" @@ -39,7 +41,6 @@ func TestVRFv2Basic(t *testing.T) { WithCLNodes(1). WithFunding(big.NewFloat(vrfv2Config.ChainlinkNodeFunding)). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err, "error creating test env") @@ -116,6 +117,79 @@ func TestVRFv2Basic(t *testing.T) { } }) + t.Run("Direct Funding (VRFV2Wrapper)", func(t *testing.T) { + testConfig := vrfv2Config + wrapperContracts, wrapperSubID, err := vrfv2_actions.SetupVRFV2WrapperEnvironment( + env, + testConfig, + linkToken, + mockETHLinkFeed, + vrfv2Contracts.Coordinator, + vrfv2Data.KeyHash, + 1, + ) + require.NoError(t, err) + wrapperConsumer := wrapperContracts.LoadTestConsumers[0] + + wrapperConsumerJuelsBalanceBeforeRequest, err := linkToken.BalanceOf(testcontext.Get(t), wrapperConsumer.Address()) + require.NoError(t, err, "Error getting wrapper consumer balance") + + wrapperSubscription, err := vrfv2Contracts.Coordinator.GetSubscription(testcontext.Get(t), *wrapperSubID) + require.NoError(t, err, "Error getting subscription information") + subBalanceBeforeRequest := wrapperSubscription.Balance + + // Request Randomness and wait for fulfillment event + randomWordsFulfilledEvent, err := vrfv2_actions.DirectFundingRequestRandomnessAndWaitForFulfillment( + wrapperConsumer, + vrfv2Contracts.Coordinator, + vrfv2Data, + *wrapperSubID, + vrfv2Config.RandomnessRequestCountPerRequest, + vrfv2Config, + testConfig.RandomWordsFulfilledEventTimeout, + l, + ) + require.NoError(t, err, "Error requesting randomness and waiting for fulfilment") + + // Check wrapper subscription balance + expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) + wrapperSubscription, err = vrfv2Contracts.Coordinator.GetSubscription(testcontext.Get(t), *wrapperSubID) + require.NoError(t, err, "Error getting subscription information") + subBalanceAfterRequest := wrapperSubscription.Balance + require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) + + // Check status of randomness request within the wrapper consumer contract + consumerStatus, err := wrapperConsumer.GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) + require.NoError(t, err, "Error getting randomness request status") + require.True(t, consumerStatus.Fulfilled) + + // Check wrapper consumer LINK balance + expectedWrapperConsumerJuelsBalance := new(big.Int).Sub(wrapperConsumerJuelsBalanceBeforeRequest, consumerStatus.Paid) + wrapperConsumerJuelsBalanceAfterRequest, err := linkToken.BalanceOf(testcontext.Get(t), wrapperConsumer.Address()) + require.NoError(t, err, "Error getting wrapper consumer balance") + require.Equal(t, expectedWrapperConsumerJuelsBalance, wrapperConsumerJuelsBalanceAfterRequest) + + // Check random word count + require.Equal(t, testConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) + for _, w := range consumerStatus.RandomWords { + l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") + require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") + } + + l.Info(). + Str("Consumer Balance Before Request (Link)", (*commonassets.Link)(wrapperConsumerJuelsBalanceBeforeRequest).Link()). + Str("Consumer Balance After Request (Link)", (*commonassets.Link)(wrapperConsumerJuelsBalanceAfterRequest).Link()). + Bool("Fulfilment Status", consumerStatus.Fulfilled). + Str("Paid by Consumer Contract (Link)", (*commonassets.Link)(consumerStatus.Paid).Link()). + Str("Paid by Coordinator Sub (Link)", (*commonassets.Link)(randomWordsFulfilledEvent.Payment).Link()). + Str("RequestTimestamp", consumerStatus.RequestTimestamp.String()). + Str("FulfilmentTimestamp", consumerStatus.FulfilmentTimestamp.String()). + Str("RequestBlockNumber", consumerStatus.RequestBlockNumber.String()). + Str("FulfilmentBlockNumber", consumerStatus.FulfilmentBlockNumber.String()). + Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). + Msg("Random Words Fulfilment Details For Link Billing") + }) + t.Run("Oracle Withdraw", func(t *testing.T) { testConfig := vrfv2Config subIDsForOracleWithDraw, err := vrfv2_actions.CreateFundSubsAndAddConsumers( @@ -168,6 +242,7 @@ func TestVRFv2Basic(t *testing.T) { "LINK funds were not returned after oracle withdraw", ) }) + t.Run("Canceling Sub And Returning Funds", func(t *testing.T) { testConfig := vrfv2Config subIDsForCancelling, err := vrfv2_actions.CreateFundSubsAndAddConsumers( @@ -371,7 +446,6 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { WithCLNodes(1). WithFunding(big.NewFloat(vrfv2Config.ChainlinkNodeFunding)). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err, "error creating test env") diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index 9ddc87422be..6cc4a07237f 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -42,7 +42,6 @@ func TestVRFv2Plus(t *testing.T) { WithCLNodes(1). WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err, "error creating test env") @@ -622,7 +621,6 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { WithCLNodes(1). WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err, "error creating test env") @@ -713,7 +711,6 @@ func TestVRFv2PlusMigration(t *testing.T) { WithCLNodes(1). WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err, "error creating test env") env.ParallelTransactions(true) diff --git a/integration-tests/types/config/node/core.go b/integration-tests/types/config/node/core.go index d8536c1395e..3508f77555f 100644 --- a/integration-tests/types/config/node/core.go +++ b/integration-tests/types/config/node/core.go @@ -7,25 +7,22 @@ import ( "os" "time" - "go.uber.org/zap/zapcore" - "github.com/segmentio/ksuid" + "go.uber.org/zap/zapcore" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/config" - + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" + it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" - - it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func NewBaseConfig() *chainlink.Config { @@ -48,7 +45,7 @@ func NewBaseConfig() *chainlink.Config { AllowOrigins: ptr.Ptr("*"), HTTPPort: ptr.Ptr[uint16](6688), SecureCookies: ptr.Ptr(false), - SessionTimeout: models.MustNewDuration(time.Hour * 999), + SessionTimeout: commonconfig.MustNewDuration(time.Hour * 999), TLS: toml.WebServerTLS{ HTTPSPort: ptr.Ptr[uint16](0), }, @@ -186,7 +183,7 @@ func WithPrivateEVMs(networks []blockchain.EVMNetwork) NodeConfigOpt { AutoCreateKey: ptr.Ptr(true), FinalityDepth: ptr.Ptr[uint32](50), MinContractPayment: commonassets.NewLinkFromJuels(0), - LogPollInterval: models.MustNewDuration(1 * time.Second), + LogPollInterval: commonconfig.MustNewDuration(1 * time.Second), HeadTracker: evmcfg.HeadTracker{ HistoryDepth: ptr.Ptr(uint32(100)), }, @@ -237,6 +234,6 @@ func WithVRFv2EVMEstimator(addresses []string, maxGasPriceGWei int64) NodeConfig func WithLogPollInterval(interval time.Duration) NodeConfigOpt { return func(c *chainlink.Config) { - c.EVM[0].Chain.LogPollInterval = models.MustNewDuration(interval) + c.EVM[0].Chain.LogPollInterval = commonconfig.MustNewDuration(interval) } } diff --git a/integration-tests/universal/log_poller/config.go b/integration-tests/universal/log_poller/config.go index 78a0da46bc6..d42520397e8 100644 --- a/integration-tests/universal/log_poller/config.go +++ b/integration-tests/universal/log_poller/config.go @@ -10,7 +10,7 @@ import ( "github.com/pelletier/go-toml/v2" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" ) const ( @@ -65,11 +65,11 @@ type WaspConfig struct { } type Load struct { - RPS int64 `toml:"rps"` - LPS int64 `toml:"lps"` - RateLimitUnitDuration *models.Duration `toml:"rate_limit_unit_duration"` - Duration *models.Duration `toml:"duration"` - CallTimeout *models.Duration `toml:"call_timeout"` + RPS int64 `toml:"rps"` + LPS int64 `toml:"lps"` + RateLimitUnitDuration *commonconfig.Duration `toml:"rate_limit_unit_duration"` + Duration *commonconfig.Duration `toml:"duration"` + CallTimeout *commonconfig.Duration `toml:"call_timeout"` } func ReadConfig(configName string) (*Config, error) { @@ -105,7 +105,7 @@ func (c *Config) OverrideFromEnv() error { } if duration := os.Getenv("LOAD_DURATION"); duration != "" { - d, err := models.ParseDuration(duration) + d, err := commonconfig.ParseDuration(duration) if err != nil { return err } diff --git a/integration-tests/universal/log_poller/helpers.go b/integration-tests/universal/log_poller/helpers.go index 1abd98632f1..8ad115ecec8 100644 --- a/integration-tests/universal/log_poller/helpers.go +++ b/integration-tests/universal/log_poller/helpers.go @@ -23,11 +23,18 @@ import ( "github.com/smartcontractkit/wasp" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" + "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -35,14 +42,6 @@ import ( le "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" core_logger "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" ) var ( @@ -1009,7 +1008,7 @@ func setupLogPollerTestDocker( // build the node config clNodeConfig := node.NewConfig(node.NewBaseConfig()) - syncInterval := models.MustMakeDuration(5 * time.Minute) + syncInterval := *commonconfig.MustNewDuration(5 * time.Minute) clNodeConfig.Feature.LogPoller = ptr.Ptr[bool](true) clNodeConfig.OCR2.Enabled = ptr.Ptr[bool](true) clNodeConfig.Keeper.TurnLookBack = ptr.Ptr[int64](int64(0)) @@ -1026,7 +1025,7 @@ func setupLogPollerTestDocker( clNodesCount := 5 var logPolllerSettingsFn = func(chain *evmcfg.Chain) *evmcfg.Chain { - chain.LogPollInterval = models.MustNewDuration(lpPollingInterval) + chain.LogPollInterval = commonconfig.MustNewDuration(lpPollingInterval) chain.FinalityDepth = ptr.Ptr[uint32](uint32(finalityDepth)) chain.FinalityTagEnabled = ptr.Ptr[bool](finalityTagEnabled) return chain @@ -1060,7 +1059,6 @@ func setupLogPollerTestDocker( WithChainOptions(logPolllerSettingsFn). EVMClientNetworkOptions(evmClientSettingsFn). WithStandardCleanup(). - WithLogStream(). Build() require.NoError(t, err, "Error deploying test environment") diff --git a/integration-tests/utils/common.go b/integration-tests/utils/common.go index 34a40e396d2..cc77e4cc3b0 100644 --- a/integration-tests/utils/common.go +++ b/integration-tests/utils/common.go @@ -4,11 +4,11 @@ import ( "math/big" "net" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" ) -func MustURL(s string) *models.URL { - var u models.URL +func MustURL(s string) *commonconfig.URL { + var u commonconfig.URL if err := u.UnmarshalText([]byte(s)); err != nil { panic(err) } diff --git a/revive.toml b/revive.toml deleted file mode 100644 index daa62cd5487..00000000000 --- a/revive.toml +++ /dev/null @@ -1,53 +0,0 @@ -ignoreGeneratedHeader = false -severity = "warning" -confidence = 0.8 -errorCode = 0 -warningCode = 0 - -[rule.blank-imports] -[rule.context-as-argument] -[rule.context-keys-type] -[rule.dot-imports] -[rule.error-return] -[rule.error-strings] -[rule.error-naming] -[rule.exported] -Disabled = true -[rule.if-return] -[rule.increment-decrement] -[rule.var-naming] -Disabled = true -[rule.var-declaration] -[rule.package-comments] -[rule.range] -[rule.receiver-naming] -[rule.time-naming] -[rule.unexported-return] -Disabled = true -[rule.indent-error-flow] -[rule.errorf] -[rule.empty-block] -[rule.superfluous-else] -[rule.unused-parameter] -Disabled = true -[rule.unreachable-code] -[rule.redefines-builtin-id] -[rule.waitgroup-by-value] -[rule.unconditional-recursion] -[rule.struct-tag] -# [rule.string-format] -[rule.string-of-int] -# [rule.range-val-address] -[rule.range-val-in-closure] -[rule.modifies-value-receiver] -[rule.modifies-parameter] -[rule.identical-branches] -[rule.get-return] -# [rule.flag-parameter] -# [rule.early-return] -[rule.defer] -[rule.constant-logical-expr] -# [rule.confusing-naming] -# [rule.confusing-results] -[rule.bool-literal-in-expr] -[rule.atomic] diff --git a/test.txt b/test.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/scripts/health/default.txtar b/testdata/scripts/health/default.txtar index c80faadfd13..15be9da1fe6 100644 --- a/testdata/scripts/health/default.txtar +++ b/testdata/scripts/health/default.txtar @@ -31,7 +31,6 @@ fj293fbBnlQ!f9vNs HTTPPort = $PORT -- out.txt -- --EventBroadcaster -JobSpawner -Mailbox.Monitor -Mercury.WSRPCPool @@ -44,15 +43,6 @@ HTTPPort = $PORT -- out.json -- { "data": [ - { - "type": "checks", - "id": "EventBroadcaster", - "attributes": { - "name": "EventBroadcaster", - "status": "passing", - "output": "" - } - }, { "type": "checks", "id": "JobSpawner", diff --git a/testdata/scripts/health/multi-chain.txtar b/testdata/scripts/health/multi-chain.txtar index 72c5fd8e3f6..6a6adb895cb 100644 --- a/testdata/scripts/health/multi-chain.txtar +++ b/testdata/scripts/health/multi-chain.txtar @@ -74,7 +74,6 @@ URL = 'http://stark.node' -EVM.1.Txm.Broadcaster -EVM.1.Txm.Confirmer -EVM.1.Txm.WrappedEvmEstimator --EventBroadcaster -JobSpawner -Mailbox.Monitor -Mercury.WSRPCPool @@ -206,15 +205,6 @@ URL = 'http://stark.node' "output": "" } }, - { - "type": "checks", - "id": "EventBroadcaster", - "attributes": { - "name": "EventBroadcaster", - "status": "passing", - "output": "" - } - }, { "type": "checks", "id": "JobSpawner", diff --git a/testdata/scripts/keys/eth/create/help.txtar b/testdata/scripts/keys/eth/create/help.txtar new file mode 100644 index 00000000000..d089b220ae4 --- /dev/null +++ b/testdata/scripts/keys/eth/create/help.txtar @@ -0,0 +1,14 @@ +exec chainlink keys eth create --help +cmp stdout out.txt + +-- out.txt -- +NAME: + chainlink keys eth create - Create a key in the node's keystore alongside the existing key; to create an original key, just run the node + +USAGE: + chainlink keys eth create [command options] [arguments...] + +OPTIONS: + --evm-chain-id value, --evmChainID value Chain ID for the key. If left blank, default chain will be used. + --max-gas-price-gwei value, --maxGasPriceGWei value Optional maximum gas price (GWei) for the creating key. (default: 0) + diff --git a/testdata/scripts/keys/eth/list/help.txtar b/testdata/scripts/keys/eth/list/help.txtar new file mode 100644 index 00000000000..d7156fd3e69 --- /dev/null +++ b/testdata/scripts/keys/eth/list/help.txtar @@ -0,0 +1,9 @@ +exec chainlink keys eth list --help +cmp stdout out.txt + +-- out.txt -- +NAME: + chainlink keys eth list - List available Ethereum accounts with their ETH & LINK balances and other metadata + +USAGE: + chainlink keys eth list [arguments...] \ No newline at end of file diff --git a/testdata/scripts/keys/eth/list/unavailable.txtar b/testdata/scripts/keys/eth/list/unavailable.txtar new file mode 100644 index 00000000000..912ad75c1e4 --- /dev/null +++ b/testdata/scripts/keys/eth/list/unavailable.txtar @@ -0,0 +1,38 @@ +# start node +exec sh -c 'eval "echo \"$(cat config.toml.tmpl)\" > config.toml"' +exec chainlink node -c config.toml start -p password -a creds & + +# initialize client +env NODEURL=http://localhost:$PORT +exec curl --retry 10 --retry-max-time 60 --retry-connrefused $NODEURL +exec chainlink --remote-node-url $NODEURL admin login -file creds --bypass-version-check + +exec chainlink --remote-node-url $NODEURL keys eth list +! stdout 'ETH: ' +! stdout 'LINK: ' +! stdout '' +stdout 'ETH: Unknown' +stdout 'LINK: Unknown' + +-- testdb.txt -- +CL_DATABASE_URL +-- testport.txt -- +PORT + +-- password -- +T.tLHkcmwePT/p,]sYuntjwHKAsrhm#4eRs4LuKHwvHejWYAC2JP4M8HimwgmbaZ +-- creds -- +notreal@fakeemail.ch +fj293fbBnlQ!f9vNs + +-- config.toml.tmpl -- +[Webserver] +HTTPPort = $PORT + +[[EVM]] +ChainID = '99' + +[[EVM.Nodes]] +Name = 'fake' +WSURL = 'wss://foo.bar/ws' +HTTPURL = 'https://foo.bar' diff --git a/testdata/scripts/node/validate/default.txtar b/testdata/scripts/node/validate/default.txtar index c9f86e43b29..32a7e5f71b3 100644 --- a/testdata/scripts/node/validate/default.txtar +++ b/testdata/scripts/node/validate/default.txtar @@ -240,6 +240,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + Invalid configuration: invalid secrets: 2 errors: - Database.URL: empty: must be provided and non-empty - Password.Keystore: empty: must be provided and non-empty diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index 1ae283c8a8a..9cca8764eed 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -284,6 +284,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar index dcb2d05ce39..d1658a1772d 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -284,6 +284,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar index fee173d3083..18ac99db785 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -284,6 +284,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index 5acbad83f8c..f048e35547e 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -274,6 +274,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index b54fc899bbd..47c63e4c03e 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -281,6 +281,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/warnings.txtar b/testdata/scripts/node/validate/warnings.txtar index 710e29d4983..c6daa829ddb 100644 --- a/testdata/scripts/node/validate/warnings.txtar +++ b/testdata/scripts/node/validate/warnings.txtar @@ -263,6 +263,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + # Configuration warning: Tracing.TLSCertPath: invalid value (something): must be empty when Tracing.Mode is 'unencrypted' Valid configuration. diff --git a/tools/bin/cldev b/tools/bin/cldev index af8d8c06135..77d0a7b8bb8 100755 --- a/tools/bin/cldev +++ b/tools/bin/cldev @@ -12,6 +12,6 @@ case "$1" in go run -ldflags "$LDFLAGS" . -- node start -d -p tools/secrets/password.txt -a tools/secrets/apicredentials ;; *) - go run . -- $@ + go run . -- "$@" ;; esac diff --git a/tools/flakeytests/cmd/runner/main.go b/tools/flakeytests/cmd/runner/main.go index f38179f502b..0f36ab25ef9 100644 --- a/tools/flakeytests/cmd/runner/main.go +++ b/tools/flakeytests/cmd/runner/main.go @@ -1,10 +1,12 @@ package main import ( + "context" "flag" "io" "log" "os" + "os/signal" "strings" "github.com/smartcontractkit/chainlink/v2/tools/flakeytests" @@ -13,6 +15,13 @@ import ( const numReruns = 2 func main() { + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) + go func() { + <-ctx.Done() + stop() // restore default exit behavior + log.Println("Cancelling... interrupt again to exit") + }() + grafanaHost := flag.String("grafana_host", "", "grafana host URL") grafanaAuth := flag.String("grafana_auth", "", "grafana basic auth for Loki API") command := flag.String("command", "", "test command being rerun; used to tag metrics") @@ -48,10 +57,10 @@ func main() { readers = append(readers, r) } - ctx := flakeytests.GetGithubMetadata(*ghRepo, *ghEventName, *ghSHA, *ghEventPath, *ghRunID) - rep := flakeytests.NewLokiReporter(*grafanaHost, *grafanaAuth, *command, ctx) + meta := flakeytests.GetGithubMetadata(*ghRepo, *ghEventName, *ghSHA, *ghEventPath, *ghRunID) + rep := flakeytests.NewLokiReporter(*grafanaHost, *grafanaAuth, *command, meta) r := flakeytests.NewRunner(readers, rep, numReruns) - err := r.Run() + err := r.Run(ctx) if err != nil { log.Fatalf("Error re-running flakey tests: %s", err) } diff --git a/tools/flakeytests/reporter.go b/tools/flakeytests/reporter.go index f17a44ef9f1..b7c7f66698f 100644 --- a/tools/flakeytests/reporter.go +++ b/tools/flakeytests/reporter.go @@ -2,6 +2,7 @@ package flakeytests import ( "bytes" + "context" "encoding/base64" "encoding/json" "fmt" @@ -138,14 +139,14 @@ func (l *LokiReporter) createRequest(report *Report) (pushRequest, error) { return pr, nil } -func (l *LokiReporter) makeRequest(pushReq pushRequest) error { +func (l *LokiReporter) makeRequest(ctx context.Context, pushReq pushRequest) error { body, err := json.Marshal(pushReq) if err != nil { return err } u := url.URL{Scheme: "https", Host: l.host, Path: "loki/api/v1/push"} - req, err := http.NewRequest("POST", u.String(), bytes.NewReader(body)) + req, err := http.NewRequestWithContext(ctx, "POST", u.String(), bytes.NewReader(body)) if err != nil { return err } @@ -167,13 +168,13 @@ func (l *LokiReporter) makeRequest(pushReq pushRequest) error { return err } -func (l *LokiReporter) Report(report *Report) error { +func (l *LokiReporter) Report(ctx context.Context, report *Report) error { pushReq, err := l.createRequest(report) if err != nil { return err } - return l.makeRequest(pushReq) + return l.makeRequest(ctx, pushReq) } func NewLokiReporter(host, auth, command string, ctx Context) *LokiReporter { diff --git a/tools/flakeytests/runner.go b/tools/flakeytests/runner.go index 97402633f38..88ab647e7c1 100644 --- a/tools/flakeytests/runner.go +++ b/tools/flakeytests/runner.go @@ -3,6 +3,7 @@ package flakeytests import ( "bufio" "bytes" + "context" "encoding/json" "errors" "fmt" @@ -33,7 +34,7 @@ type tester interface { } type reporter interface { - Report(r *Report) error + Report(ctx context.Context, r *Report) error } type parseFn func(readers ...io.Reader) (*Report, error) @@ -297,7 +298,7 @@ func dedupeEntries(report *Report) (*Report, error) { return out, nil } -func (r *Runner) Run() error { +func (r *Runner) Run(ctx context.Context) error { parseReport, err := r.parse(r.readers...) if err != nil { return err @@ -323,5 +324,5 @@ func (r *Runner) Run() error { return err } - return r.reporter.Report(report) + return r.reporter.Report(ctx, report) } diff --git a/tools/flakeytests/runner_test.go b/tools/flakeytests/runner_test.go index 64e2a6c968a..ee069a1655d 100644 --- a/tools/flakeytests/runner_test.go +++ b/tools/flakeytests/runner_test.go @@ -1,6 +1,7 @@ package flakeytests import ( + "context" "io" "os" "os/exec" @@ -9,13 +10,15 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" ) type mockReporter struct { report *Report } -func (m *mockReporter) Report(report *Report) error { +func (m *mockReporter) Report(_ context.Context, report *Report) error { m.report = report return nil } @@ -120,7 +123,7 @@ func TestRunner_WithFlake(t *testing.T) { // This will report a flake since we've mocked the rerun // to only report one failure (not two as expected). - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) assert.Len(t, m.report.tests, 1) _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] @@ -155,7 +158,7 @@ func TestRunner_WithFailedPackage(t *testing.T) { // This will report a flake since we've mocked the rerun // to only report one failure (not two as expected). - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) assert.Len(t, m.report.tests, 1) _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] @@ -181,7 +184,7 @@ func TestRunner_AllFailures(t *testing.T) { reporter: m, } - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) assert.Len(t, m.report.tests, 0) } @@ -207,7 +210,7 @@ func TestRunner_RerunSuccessful(t *testing.T) { reporter: m, } - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] assert.True(t, ok) @@ -229,7 +232,7 @@ func TestRunner_RootLevelTest(t *testing.T) { reporter: m, } - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/"]["TestConfigDocs"] assert.True(t, ok) @@ -256,7 +259,7 @@ func TestRunner_RerunFailsWithNonzeroExitCode(t *testing.T) { reporter: m, } - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] assert.True(t, ok) @@ -293,7 +296,7 @@ func TestRunner_RerunWithNonZeroExitCodeDoesntStopCommand(t *testing.T) { reporter: m, } - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) calls := index assert.Equal(t, 4, calls) @@ -366,7 +369,7 @@ func TestIntegration_DealsWithSubtests(t *testing.T) { reporter: m, } - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) expectedTests := map[string]map[string]int{ "github.com/smartcontractkit/chainlink/v2/tools/flakeytests/": { @@ -402,7 +405,7 @@ func TestIntegration_ParsesPanics(t *testing.T) { reporter: m, } - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/tools/flakeytests"]["TestSkippedForTests"] assert.False(t, ok) @@ -433,7 +436,7 @@ func TestIntegration(t *testing.T) { reporter: m, } - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/tools/flakeytests"]["TestSkippedForTests_Success"] assert.False(t, ok)