diff --git a/.github/actions/golangci-lint/action.yml b/.github/actions/golangci-lint/action.yml new file mode 100644 index 00000000000..c8c44262594 --- /dev/null +++ b/.github/actions/golangci-lint/action.yml @@ -0,0 +1,77 @@ +name: CI lint for Golang +description: Runs CI lint for Golang +inputs: + # general inputs + name: + description: Name of the lint action + default: lint + go-directory: + description: Go directory to run commands from + default: "." + # setup-go inputs + only-modules: + description: Set to 'true' to only cache modules + default: "false" + cache-version: + description: Set this to cache bust + default: "1" + go-version-file: + description: Set where the go version file is located at + default: "go.mod" + go-module-file: + description: Set where the go module file is located at + default: "go.sum" + # grafana cloud inputs + gc-host: + description: "grafana cloud hostname" + gc-basic-auth: + description: "grafana cloud basic auth" + +runs: + using: composite + steps: + - uses: actions/checkout@v4 + - name: Setup Go + uses: ./.github/actions/setup-go + with: + only-modules: ${{ inputs.only-modules }} + cache-version: ${{ inputs.cache-version }} + go-version-file: ${{ inputs.go-version-file }} + go-module-file: ${{ inputs.go-module-file }} + - name: Touching core/web/assets/index.html + shell: bash + run: mkdir -p core/web/assets && touch core/web/assets/index.html + - name: Build binary + if: ${{ inputs.go-directory == '.' }} + shell: bash + run: go build ./... + - name: Build binary + if: ${{ inputs.go-directory != '.' }} + working-directory: ${{ inputs.go-directory }} + shell: bash + run: go build + - name: golangci-lint + uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 + with: + version: v1.54.2 + # We already cache these directories in setup-go + skip-pkg-cache: true + skip-build-cache: true + # only-new-issues is only applicable to PRs, otherwise it is always set to false + only-new-issues: true + args: --out-format colored-line-number,checkstyle:golangci-lint-report.xml + working-directory: ${{ inputs.go-directory }} + - name: Store lint report artifact + if: always() + uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 + with: + name: golangci-lint-report + path: ${{ inputs.go-directory }}/golangci-lint-report.xml + - name: Collect Metrics + if: always() + uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + with: + basic-auth: ${{ inputs.gc-basic-auth }} + hostname: ${{ inputs.gc-host }} + this-job-name: ${{ inputs.name }} + continue-on-error: true diff --git a/.github/actions/setup-go/action.yml b/.github/actions/setup-go/action.yml index 996fb4ac507..eba01521068 100644 --- a/.github/actions/setup-go/action.yml +++ b/.github/actions/setup-go/action.yml @@ -1,53 +1,64 @@ name: Setup Go -description: Setup Golang with efficient caching +description: Setup Golang with efficient caching inputs: only-modules: description: Set to 'true' to only cache modules - default: 'false' + default: "false" cache-version: description: Set this to cache bust default: "1" + go-version-file: + description: Set where the go version file is located at + default: "go.mod" + go-module-file: + description: Set where the go module file is located at + default: "go.sum" runs: using: composite steps: - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version-file: "go.mod" - cache: false + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version-file: ${{ inputs.go-version-file }} + cache: false - - name: Get branch name - if: ${{ inputs.only-modules == 'false' }} - id: branch-name - uses: tj-actions/branch-names@2e5354c6733793113f416314375826df030ada23 #v6.5 + - name: Get branch name + if: ${{ inputs.only-modules == 'false' }} + id: branch-name + uses: tj-actions/branch-names@2e5354c6733793113f416314375826df030ada23 #v6.5 - - name: Set go cache keys - shell: bash - id: go-cache-dir - run: | - echo "gomodcache=$(go env GOMODCACHE)" >> $GITHUB_OUTPUT - echo "gobuildcache=$(go env GOCACHE)" >> $GITHUB_OUTPUT + - name: Set go cache keys + shell: bash + id: go-cache-dir + run: | + echo "gomodcache=$(go env GOMODCACHE)" >> $GITHUB_OUTPUT + echo "gobuildcache=$(go env GOCACHE)" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 - name: Cache Go Modules - with: - path: | - ${{ steps.go-cache-dir.outputs.gomodcache }} - # The lifetime of go modules is much higher than the build outputs, so we increase cache efficiency - # here by not having the primary key contain the branch name - key: ${{ runner.os }}-gomod-${{ inputs.cache-version }}-${{ hashFiles('./go.sum') }} - restore-keys: | - ${{ runner.os }}-gomod-${{ inputs.cache-version }}- + - name: Set go module path + id: go-module-path + shell: bash + run: echo "path=./${{ inputs.go-module-file }}" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 - if: ${{ inputs.only-modules == 'false' }} - name: Cache Go Build Outputs - with: - path: | - ${{ steps.go-cache-dir.outputs.gobuildcache }} - # The lifetime of go build outputs is pretty short, so we make our primary cache key be the branch name - key: ${{ runner.os }}-gobuild-${{ inputs.cache-version }}-${{ hashFiles('./go.sum') }}-${{ steps.branch-name.outputs.current_branch }} - restore-keys: | - ${{ runner.os }}-gobuild-${{ inputs.cache-version }}-${{ hashFiles('./go.sum') }}- - ${{ runner.os }}-gobuild-${{ inputs.cache-version }}- + - uses: actions/cache@v3 + name: Cache Go Modules + with: + path: | + ${{ steps.go-cache-dir.outputs.gomodcache }} + # The lifetime of go modules is much higher than the build outputs, so we increase cache efficiency + # here by not having the primary key contain the branch name + key: ${{ runner.os }}-gomod-${{ inputs.cache-version }}-${{ hashFiles(steps.go-module-path.output.path) }} + restore-keys: | + ${{ runner.os }}-gomod-${{ inputs.cache-version }}- + + - uses: actions/cache@v3 + if: ${{ inputs.only-modules == 'false' }} + name: Cache Go Build Outputs + with: + path: | + ${{ steps.go-cache-dir.outputs.gobuildcache }} + # The lifetime of go build outputs is pretty short, so we make our primary cache key be the branch name + key: ${{ runner.os }}-gobuild-${{ inputs.cache-version }}-${{ hashFiles(steps.go-module-path.output.path) }}-${{ steps.branch-name.outputs.current_branch }} + restore-keys: | + ${{ runner.os }}-gobuild-${{ inputs.cache-version }}-${{ hashFiles(steps.go-module-path.output.path) }}- + ${{ runner.os }}-gobuild-${{ inputs.cache-version }}- diff --git a/.github/workflows/automation-ondemand-tests.yml b/.github/workflows/automation-ondemand-tests.yml index 71cd08eaf45..1693e001634 100644 --- a/.github/workflows/automation-ondemand-tests.yml +++ b/.github/workflows/automation-ondemand-tests.yml @@ -140,8 +140,8 @@ jobs: command: -run ^TestAutomationReorg$ ./reorg - name: upgrade suite: smoke - nodes: 1 - os: ubuntu-latest + nodes: 3 + os: ubuntu20.04-8cores-32GB pyroscope_env: ci-automation-on-demand-upgrade network: SIMULATED command: -run ^TestAutomationNodeUpgrade$ ./smoke @@ -160,10 +160,12 @@ jobs: echo "image=${{ env.CHAINLINK_IMAGE }}" >>$GITHUB_OUTPUT echo "version=${{ github.sha }}" >>$GITHUB_OUTPUT echo "upgrade_version=${{ github.sha }}" >>$GITHUB_OUTPUT + echo "upgrade_image=${{ env.CHAINLINK_IMAGE }}" >>$GITHUB_OUTPUT else echo "image=${{ inputs.chainlinkImage }}" >>$GITHUB_OUTPUT echo "version=${{ inputs.chainlinkVersion }}" >>$GITHUB_OUTPUT echo "upgrade_version=${{ inputs.chainlinkVersion }}" >>$GITHUB_OUTPUT + echo "upgrade_image=${{ inputs.chainlinkImage }}" >>$GITHUB_OUTPUT fi if [[ "${{ matrix.tests.name }}" == "upgrade" ]]; then echo "image=${{ inputs.chainlinkImageUpdate }}" >>$GITHUB_OUTPUT @@ -177,10 +179,10 @@ jobs: PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} SELECTED_NETWORKS: ${{ matrix.tests.network }} TEST_SUITE: ${{ matrix.tests.suite }} - TEST_UPGRADE_VERSION: ${{ steps.determine-build.outputs.upgrade_version }} - TEST_UPGRADE_IMAGE: ${{ env.CHAINLINK_IMAGE }} + UPGRADE_VERSION: ${{ steps.determine-build.outputs.upgrade_version }} + UPGRADE_IMAGE: ${{ steps.determine-build.outputs.upgrade_image }} with: - test_command_to_run: make test_need_operator_assets && cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.tests.nodes }} ${{ matrix.tests.command }} 2>&1 | tee /tmp/gotest.log | gotestfmt + test_command_to_run: make test_need_operator_assets && cd ./integration-tests && go test -timeout 60m -count=1 -json -test.parallel=${{ matrix.tests.nodes }} ${{ matrix.tests.command }} 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ steps.determine-build.outputs.image }} cl_image_tag: ${{ steps.determine-build.outputs.version }} diff --git a/.github/workflows/ci-chaincli.yml b/.github/workflows/ci-chaincli.yml new file mode 100644 index 00000000000..97225e46557 --- /dev/null +++ b/.github/workflows/ci-chaincli.yml @@ -0,0 +1,26 @@ +name: chaincli CI + +on: + push: + paths: + - "core/scripts/chaincli/**" + pull_request: + paths: + - "core/scripts/chaincli/**" + +jobs: + golangci: + if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' }} + name: chaincli-lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Golang Lint + uses: ./.github/actions/golangci-lint + with: + name: chaincli-lint + go-directory: core/scripts/chaincli + go-version-file: core/scripts/go.mod + go-module-file: core/scripts/go.sum + gc-basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + gc-host: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index 09d805a116e..9c1322d2e8b 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -23,36 +23,11 @@ jobs: runs-on: ubuntu20.04-8cores-32GB steps: - uses: actions/checkout@v4 - - name: Setup Go - uses: ./.github/actions/setup-go - - name: Touching core/web/assets/index.html - run: mkdir -p core/web/assets && touch core/web/assets/index.html - - name: Build binary - run: go build ./... - - name: golangci-lint - uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 + - name: Golang Lint + uses: ./.github/actions/golangci-lint with: - version: v1.54.2 - # We already cache these directories in setup-go - skip-pkg-cache: true - skip-build-cache: true - # only-new-issues is only applicable to PRs, otherwise it is always set to false - only-new-issues: true - args: --out-format colored-line-number,checkstyle:golangci-lint-report.xml - - name: Store lint report artifact - if: always() - uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 - with: - name: golangci-lint-report - path: golangci-lint-report.xml - - name: Collect Metrics - if: always() - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec - with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: lint - continue-on-error: true + gc-basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + gc-host: ${{ secrets.GRAFANA_CLOUD_HOST }} core: strategy: @@ -237,7 +212,7 @@ jobs: clean: name: Clean Go Tidy & Generate if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') }} - runs-on: ubuntu-latest + runs-on: ubuntu20.04-8cores-32GB defaults: run: shell: bash diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 884da09f4cb..05916bab63e 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -111,7 +111,7 @@ jobs: echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY build-test-image: - if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'schedule' || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')) || contains(join(github.event.pull_request.labels.*.name, ' '), 'build-test-image') + if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'schedule' || contains(join(github.event.pull_request.labels.*.name, ' '), 'build-test-image') environment: integration permissions: id-token: write @@ -709,6 +709,33 @@ jobs: with: repository: smartcontractkit/chainlink-solana ref: ${{ needs.get_solana_sha.outputs.sha }} + - name: Run Setup + if: needs.changes.outputs.src == 'true' + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + with: + go_mod_path: ./integration-tests/go.mod + cache_restore_only: true + cache_key_id: core-solana-e2e-${{ env.MOD_CACHE_VERSION }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Pull Artfacts + if: needs.changes.outputs.src == 'true' + run: | + IMAGE_NAME=${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-solana-tests:${{ needs.get_solana_sha.outputs.sha }} + # Pull the Docker image + docker pull "$IMAGE_NAME" + + # Create a container without starting it + CONTAINER_ID=$(docker create "$IMAGE_NAME") + + # Copy the artifacts from the container + mkdir -p ./${{env.CONTRACT_ARTIFACTS_PATH}}/ + docker cp "$CONTAINER_ID:/go/testdir/${{env.CONTRACT_ARTIFACTS_PATH}}/" "./${{env.CONTRACT_ARTIFACTS_PATH}}/../" + + # Remove the created container + docker rm "$CONTAINER_ID" - name: Run Tests if: needs.changes.outputs.src == 'true' uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 @@ -721,9 +748,11 @@ jobs: go_mod_path: ./integration-tests/go.mod cache_key_id: core-solana-e2e-${{ env.MOD_CACHE_VERSION }} token: ${{ secrets.GITHUB_TOKEN }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + run_setup: false - name: Upload test log uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 if: failure() diff --git a/.github/workflows/on-demand-ocr-soak-test.yml b/.github/workflows/on-demand-ocr-soak-test.yml index 08e37d9c8eb..382d74a8d90 100644 --- a/.github/workflows/on-demand-ocr-soak-test.yml +++ b/.github/workflows/on-demand-ocr-soak-test.yml @@ -17,7 +17,9 @@ on: - "BSC_MAINNET" - "BSC_TESTNET" - "SCROLL_SEPOLIA" - - "SCROLL_MAINNET" + - "SCROLL_MAINNET" + - "MUMBAI" + - "POLYGON_MAINNET" fundingPrivateKey: description: Private funding key (Skip for Simulated) required: false diff --git a/.github/workflows/on-demand-vrfv2plus-load-test.yml b/.github/workflows/on-demand-vrfv2plus-load-test.yml index dcfd2def52d..28c47b453de 100644 --- a/.github/workflows/on-demand-vrfv2plus-load-test.yml +++ b/.github/workflows/on-demand-vrfv2plus-load-test.yml @@ -38,27 +38,22 @@ on: chainlinkVersion: description: Container image version for the Chainlink nodes required: true - default: "2.5.0" + default: "2.6.0-beta0" testDuration: description: Duration of the test (time string) required: false default: 1m - chainlinkNodeFunding: - description: How much to fund each Chainlink node (in ETH) - required: false - default: ".1" - rps: - description: Requests Per Second - required: false - default: 1 - rateLimitDuration: - description: How long to wait between requests - required: false - default: 1m randomnessRequestCountPerRequest: description: Randomness request Count per one TX request required: false default: 1 + useExistingEnv: + description: Whether to deploy a new contracts or use an existing one + required: false + default: false + configBase64: + description: TOML config in base64 + required: false jobs: vrfv2plus_load_test: name: ${{ inputs.network }} VRFV2 Plus Load Test @@ -72,15 +67,15 @@ jobs: env: SELECTED_NETWORKS: ${{ inputs.network }} VRFV2PLUS_TEST_DURATION: ${{ inputs.testDuration }} - VRFV2PLUS_CHAINLINK_NODE_FUNDING: ${{ inputs.chainlinkNodeFunding }} - VRFV2PLUS_RATE_LIMIT_UNIT_DURATION: ${{ inputs.rateLimitDuration }} - VRFV2PLUS_RPS: ${{ inputs.rps }} + VRFV2PLUS_RATE_LIMIT_UNIT_DURATION: 1m + VRFV2PLUS_RPS: 1 VRFV2PLUS_RANDOMNESS_REQUEST_COUNT_PER_REQUEST: ${{ inputs.randomnessRequestCountPerRequest }} - + VRFV2PLUS_USE_EXISTING_ENV: ${{ inputs.useExistingEnv }} + CONFIG: ${{ inputs.configBase64 }} TEST_LOG_LEVEL: debug REF_NAME: ${{ github.head_ref || github.ref_name }} - ENV_JOB_IMAGE_BASE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests - + CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} + CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} WASP_LOG_LEVEL: info steps: - name: Collect Metrics diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index 8f0181640ea..38b6a511127 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -30,6 +30,7 @@ jobs: tests: strategy: + fail-fast: false matrix: product: [vrf, automation, llo-feeds, functions, shared] needs: [changes] @@ -54,7 +55,7 @@ jobs: uses: foundry-rs/foundry-toolchain@v1 with: # Has to match the `make foundry` version. - version: nightly-ca67d15f4abd46394b324c50e21e66f306a1162d + version: nightly-e0722a10b45859892ec3b998df958a9edc77c202 - name: Run Forge build run: | diff --git a/.gitignore b/.gitignore index 4d65eb32a1e..decea4a68a7 100644 --- a/.gitignore +++ b/.gitignore @@ -45,7 +45,7 @@ core/cmd/TestClient_ImportExportP2PKeyBundle_test_key.json output.txt race.* golangci-lint-output.txt -golangci-lint/ +/golangci-lint/ # DB state ./db/ diff --git a/CODEOWNERS b/CODEOWNERS index 0c7e4dc7e7b..8ec42ed6dd4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -72,16 +72,24 @@ core/scripts/gateway @bolekk @pinebit # Contracts /contracts/ @se3000 @connorwstein @RensR -/contracts/**/*Keeper* @smartcontractkit/keepers -/contracts/**/*Upkeep* @smartcontractkit/keepers -/contracts/**/*Functions* @smartcontractkit/functions + +/contracts/srv/v0.8/automation @smartcontractkit/keepers +/contracts/**/*keeper* @smartcontractkit/keepers +/contracts/**/*upkeep* @smartcontractkit/keepers +/contracts/**/*automation* @smartcontractkit/keepers +/contracts/gas-snapshots/automation.gas-snapshot @smartcontractkit/keepers + /contracts/src/v0.8/functions @smartcontractkit/functions -/contracts/test/v0.8/functions @smartcontractkit/functions +/contracts/**/*functions* @smartcontractkit/functions +/contracts/gas-snapshots/functions.gas-snapshot @smartcontractkit/functions + /contracts/src/v0.8/llo-feeds @austinborn @Fletch153 +/contracts/gas-snapshots/llo-feeds.gas-snapshot @austinborn @Fletch153 + /contracts/src/v0.8/vrf @smartcontractkit/vrf-team -/contracts/src/v0.8/dev/vrf @smartcontractkit/vrf-team -/contracts/src/v0.8/dev/BlockhashStore.sol @smartcontractkit/vrf-team -/contracts/src/v0.8/dev/VRFConsumerBaseV2Upgradeable.sol @smartcontractkit/vrf-team +/contracts/**/*vrf* @smartcontractkit/vrf-team + +/contracts/src/v0.8/l2ep @simsonraj # Tests /integration-tests/ @smartcontractkit/test-tooling-team diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index 4f0e92d0bcd..6512f67fe0b 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -109,7 +109,7 @@ type Broadcaster[ txStore txmgrtypes.TransactionStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, SEQ, FEE] client txmgrtypes.TransactionClient[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] - sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH] + sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH, SEQ] resumeCallback ResumeCallback chainID CHAIN_ID config txmgrtypes.BroadcasterChainConfig @@ -143,6 +143,10 @@ type Broadcaster[ utils.StartStopOnce parseAddr func(string) (ADDR, error) + + sequenceLock sync.RWMutex + nextSequenceMap map[ADDR]SEQ + generateNextSequence types.GenerateNextSequenceFunc[SEQ] } func NewBroadcaster[ @@ -163,11 +167,12 @@ func NewBroadcaster[ keystore txmgrtypes.KeyStore[ADDR, CHAIN_ID, SEQ], eventBroadcaster pg.EventBroadcaster, txAttemptBuilder txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], - sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH], + sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH, SEQ], logger logger.Logger, checkerFactory TransmitCheckerFactory[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], autoSyncSequence bool, parseAddress func(string) (ADDR, error), + generateNextSequence types.GenerateNextSequenceFunc[SEQ], ) *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] { logger = logger.Named("Broadcaster") b := &Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]{ @@ -189,6 +194,7 @@ func NewBroadcaster[ } b.processUnstartedTxsImpl = b.processUnstartedTxs + b.generateNextSequence = generateNextSequence return b } @@ -235,6 +241,13 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) star eb.wg.Add(1) go eb.txInsertTriggerer() + eb.sequenceLock.Lock() + defer eb.sequenceLock.Unlock() + eb.nextSequenceMap, err = eb.loadNextSequenceMap(eb.enabledAddresses) + if err != nil { + return errors.Wrap(err, "Broadcaster: failed to load next sequence map") + } + eb.isStarted = true return nil } @@ -312,6 +325,33 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) txIn } } +// Load the next sequence map using the tx table or on-chain (if not found in tx table) +func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) loadNextSequenceMap(addresses []ADDR) (map[ADDR]SEQ, error) { + ctx, cancel := eb.chStop.NewCtx() + defer cancel() + + nextSequenceMap := make(map[ADDR]SEQ) + for _, address := range addresses { + // Get the highest sequence from the tx table + // Will need to be incremented since this sequence is already used + seq, err := eb.txStore.FindLatestSequence(ctx, address, eb.chainID) + if err != nil { + // Look for nonce on-chain if no tx found for address in TxStore or if error occurred + // Returns the nonce that should be used for the next transaction so no need to increment + seq, err = eb.client.PendingSequenceAt(ctx, address) + if err != nil { + return nil, errors.New("failed to retrieve next sequence from on-chain causing failure to load next sequence map on broadcaster startup") + } + + nextSequenceMap[address] = seq + } else { + nextSequenceMap[address] = eb.generateNextSequence(seq) + } + } + + return nextSequenceMap, nil +} + func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) newSequenceSyncBackoff() backoff.Backoff { return backoff.Backoff{ Min: 100 * time.Millisecond, @@ -389,31 +429,42 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) moni } } -// syncSequence tries to sync the key sequence, retrying indefinitely until success +// syncSequence tries to sync the key sequence, retrying indefinitely until success or stop signal is sent func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SyncSequence(ctx context.Context, addr ADDR) { sequenceSyncRetryBackoff := eb.newSequenceSyncBackoff() - if err := eb.sequenceSyncer.Sync(ctx, addr); err != nil { - // Enter retry loop with backoff - var attempt int - eb.logger.Errorw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) - for { - select { - case <-eb.chStop: - return - case <-time.After(sequenceSyncRetryBackoff.Duration()): - attempt++ - - if err := eb.sequenceSyncer.Sync(ctx, addr); err != nil { - if attempt > 5 { - eb.logger.Criticalw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) - eb.SvcErrBuffer.Append(err) - } else { - eb.logger.Warnw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) - } - continue + localSequence, err := eb.GetNextSequence(addr) + // Address not found in map so skip sync + if err != nil { + eb.logger.Criticalw("Failed to retrieve local next sequence for address", "address", addr.String(), "err", err) + return + } + + // Enter loop with retries + var attempt int + for { + select { + case <-eb.chStop: + return + case <-time.After(sequenceSyncRetryBackoff.Duration()): + attempt++ + newNextSequence, err := eb.sequenceSyncer.Sync(ctx, addr, localSequence) + if err != nil { + if attempt > 5 { + eb.logger.Criticalw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) + eb.SvcErrBuffer.Append(err) + } else { + eb.logger.Warnw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) } - return + continue + } + // Found new sequence to use from on-chain + if localSequence.String() != newNextSequence.String() { + eb.logger.Infow("Fast-forward sequence", "address", addr, "newNextSequence", newNextSequence, "oldNextSequence", localSequence) + // Set new sequence in the map + eb.SetNextSequence(addr, newNextSequence) } + return + } } } @@ -505,16 +556,6 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand return nil, false } -// This function is used to pass the queryer from the txmgr to the keystore. -// It is inevitable we have to pass the queryer because we need the keystate's next sequence to be incremented -// atomically alongside the transition from `in_progress` to `broadcast` so it is ready for the next transaction -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) incrementNextSequenceAtomic(tx pg.Queryer, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { - if err := eb.incrementNextSequence(etx.FromAddress, *etx.Sequence, pg.WithQueryer(tx)); err != nil { - return errors.Wrap(err, "saveUnconfirmed failed") - } - return nil -} - // There can be at most one in_progress transaction per address. // Here we complete the job that we didn't finish last time. func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) handleInProgressTx(ctx context.Context, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time) (error, bool) { @@ -603,9 +644,19 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand // and hand off to the confirmer to get the receipt (or mark as // failed). observeTimeUntilBroadcast(eb.chainID, etx.CreatedAt, time.Now()) - return eb.txStore.UpdateTxAttemptInProgressToBroadcast(&etx, attempt, txmgrtypes.TxAttemptBroadcast, func(tx pg.Queryer) error { - return eb.incrementNextSequenceAtomic(tx, etx) - }), true + // Check if from_address exists in map to ensure it is valid before broadcasting + var sequence SEQ + sequence, err = eb.GetNextSequence(etx.FromAddress) + if err != nil { + return err, true + } + err = eb.txStore.UpdateTxAttemptInProgressToBroadcast(ctx, &etx, attempt, txmgrtypes.TxAttemptBroadcast) + if err != nil { + return err, true + } + // Increment sequence if successfully broadcasted + eb.IncrementNextSequence(etx.FromAddress, sequence) + return err, true case clienttypes.Underpriced: return eb.tryAgainBumpingGas(ctx, lgr, err, etx, attempt, initialBroadcastAt) case clienttypes.InsufficientFunds: @@ -650,9 +701,20 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand // Despite the error, the RPC node considers the previously sent // transaction to have been accepted. In this case, the right thing to // do is assume success and hand off to Confirmer - return eb.txStore.UpdateTxAttemptInProgressToBroadcast(&etx, attempt, txmgrtypes.TxAttemptBroadcast, func(tx pg.Queryer) error { - return eb.incrementNextSequenceAtomic(tx, etx) - }), true + + // Check if from_address exists in map to ensure it is valid before broadcasting + var sequence SEQ + sequence, err = eb.GetNextSequence(etx.FromAddress) + if err != nil { + return err, true + } + err = eb.txStore.UpdateTxAttemptInProgressToBroadcast(ctx, &etx, attempt, txmgrtypes.TxAttemptBroadcast) + if err != nil { + return err, true + } + // Increment sequence if successfully broadcasted + eb.IncrementNextSequence(etx.FromAddress, sequence) + return err, true } // Either the unknown error prevented the transaction from being mined, or // it has not yet propagated to the mempool, or there is some race on the @@ -679,7 +741,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) next return nil, errors.Wrap(err, "findNextUnstartedTransactionFromAddress failed") } - sequence, err := eb.getNextSequence(etx.FromAddress) + sequence, err := eb.GetNextSequence(etx.FromAddress) if err != nil { return nil, err } @@ -763,12 +825,30 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) save return eb.txStore.UpdateTxFatalError(ctx, etx) } -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) getNextSequence(address ADDR) (sequence SEQ, err error) { - return eb.ks.NextSequence(address, eb.chainID) +// Used to get the next usable sequence for a transaction +func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetNextSequence(address ADDR) (seq SEQ, err error) { + eb.sequenceLock.Lock() + defer eb.sequenceLock.Unlock() + // Get next sequence from map + seq, exists := eb.nextSequenceMap[address] + if !exists { + return seq, errors.New(fmt.Sprint("address not found in next sequence map: ", address)) + } + return seq, nil +} + +// Used to increment the sequence in the mapping to have the next usable one available for the next transaction +func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) IncrementNextSequence(address ADDR, seq SEQ) { + eb.sequenceLock.Lock() + defer eb.sequenceLock.Unlock() + eb.nextSequenceMap[address] = eb.generateNextSequence(seq) } -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) incrementNextSequence(address ADDR, currentSequence SEQ, qopts ...pg.QOpt) error { - return eb.ks.IncrementNextSequence(address, eb.chainID, currentSequence, qopts...) +// Used to set the next sequence explicitly to a certain value +func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SetNextSequence(address ADDR, seq SEQ) { + eb.sequenceLock.Lock() + defer eb.sequenceLock.Unlock() + eb.nextSequenceMap[address] = seq } func observeTimeUntilBroadcast[CHAIN_ID types.ID](chainID CHAIN_ID, createdAt, broadcastAt time.Time) { diff --git a/common/txmgr/mocks/tx_manager.go b/common/txmgr/mocks/tx_manager.go index fe19023bd5c..caf204103cf 100644 --- a/common/txmgr/mocks/tx_manager.go +++ b/common/txmgr/mocks/tx_manager.go @@ -137,13 +137,13 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Regist _m.Called(fn) } -// Reset provides a mock function with given fields: f, addr, abandon -func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Reset(f func(), addr ADDR, abandon bool) error { - ret := _m.Called(f, addr, abandon) +// Reset provides a mock function with given fields: addr, abandon +func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Reset(addr ADDR, abandon bool) error { + ret := _m.Called(addr, abandon) var r0 error - if rf, ok := ret.Get(0).(func(func(), ADDR, bool) error); ok { - r0 = rf(f, addr, abandon) + if rf, ok := ret.Get(0).(func(ADDR, bool) error); ok { + r0 = rf(addr, abandon) } else { r0 = ret.Error(0) } diff --git a/common/txmgr/nonce_syncer.go b/common/txmgr/sequence_syncer.go similarity index 55% rename from common/txmgr/nonce_syncer.go rename to common/txmgr/sequence_syncer.go index 3c96473f800..dd4d458dd74 100644 --- a/common/txmgr/nonce_syncer.go +++ b/common/txmgr/sequence_syncer.go @@ -6,6 +6,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/common/types" ) -type SequenceSyncer[ADDR types.Hashable, TX_HASH types.Hashable, BLOCK_HASH types.Hashable] interface { - Sync(ctx context.Context, addr ADDR) (err error) +type SequenceSyncer[ADDR types.Hashable, TX_HASH types.Hashable, BLOCK_HASH types.Hashable, SEQ types.Sequence] interface { + Sync(ctx context.Context, addr ADDR, localSequence SEQ) (SEQ, error) } diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index c6388e2a85c..feb3218bfc6 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -45,7 +45,7 @@ type TxManager[ GetForwarderForEOA(eoa ADDR) (forwarder ADDR, err error) RegisterResumeCallback(fn ResumeCallback) SendNativeToken(ctx context.Context, chainID CHAIN_ID, from, to ADDR, value big.Int, gasLimit uint32) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) - Reset(f func(), addr ADDR, abandon bool) error + Reset(addr ADDR, abandon bool) error } type reset struct { @@ -91,7 +91,7 @@ type Txm[ confirmer *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] fwdMgr txmgrtypes.ForwarderManager[ADDR] txAttemptBuilder txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] - sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH] + sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH, SEQ] } func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) RegisterResumeCallback(fn ResumeCallback) { @@ -120,7 +120,7 @@ func NewTxm[ fwdMgr txmgrtypes.ForwarderManager[ADDR], txAttemptBuilder txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txStore txmgrtypes.TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE], - sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH], + sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH, SEQ], broadcaster *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], confirmer *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE], resender *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], @@ -196,13 +196,11 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(ctx }) } -// Reset stops Broadcaster/Confirmer, executes callback, then starts them -// again -func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Reset(callback func(), addr ADDR, abandon bool) (err error) { +// Reset stops Broadcaster/Confirmer, executes callback, then starts them again +func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Reset(addr ADDR, abandon bool) (err error) { ok := b.IfStarted(func() { done := make(chan error) f := func() { - callback() if abandon { err = b.abandon(addr) } @@ -546,7 +544,7 @@ func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Cre func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetForwarderForEOA(addr ADDR) (fwdr ADDR, err error) { return fwdr, err } -func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Reset(f func(), addr ADDR, abandon bool) error { +func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Reset(addr ADDR, abandon bool) error { return nil } diff --git a/common/txmgr/types/keystore.go b/common/txmgr/types/keystore.go index 4793e6579ad..9c5b8cfce37 100644 --- a/common/txmgr/types/keystore.go +++ b/common/txmgr/types/keystore.go @@ -2,7 +2,6 @@ package types import ( "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) // KeyStore encompasses the subset of keystore used by txmgr @@ -17,8 +16,6 @@ type KeyStore[ SEQ types.Sequence, ] interface { CheckEnabled(address ADDR, chainID CHAIN_ID) error - NextSequence(address ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) (SEQ, error) EnabledAddressesForChain(chainId CHAIN_ID) ([]ADDR, error) - IncrementNextSequence(address ADDR, chainID CHAIN_ID, currentSequence SEQ, qopts ...pg.QOpt) error SubscribeToKeyChanges() (ch chan struct{}, unsub func()) } diff --git a/common/txmgr/types/mocks/key_store.go b/common/txmgr/types/mocks/key_store.go index 90d8040f3e4..e4189c1dd00 100644 --- a/common/txmgr/types/mocks/key_store.go +++ b/common/txmgr/types/mocks/key_store.go @@ -3,7 +3,6 @@ package mocks import ( - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" mock "github.com/stretchr/testify/mock" types "github.com/smartcontractkit/chainlink/v2/common/types" @@ -54,58 +53,6 @@ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) EnabledAddressesForChain(chainId CHAIN_ return r0, r1 } -// IncrementNextSequence provides a mock function with given fields: address, chainID, currentSequence, qopts -func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) IncrementNextSequence(address ADDR, chainID CHAIN_ID, currentSequence SEQ, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, address, chainID, currentSequence) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 error - if rf, ok := ret.Get(0).(func(ADDR, CHAIN_ID, SEQ, ...pg.QOpt) error); ok { - r0 = rf(address, chainID, currentSequence, qopts...) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// NextSequence provides a mock function with given fields: address, chainID, qopts -func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) NextSequence(address ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) (SEQ, error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, address, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 SEQ - var r1 error - if rf, ok := ret.Get(0).(func(ADDR, CHAIN_ID, ...pg.QOpt) (SEQ, error)); ok { - return rf(address, chainID, qopts...) - } - if rf, ok := ret.Get(0).(func(ADDR, CHAIN_ID, ...pg.QOpt) SEQ); ok { - r0 = rf(address, chainID, qopts...) - } else { - r0 = ret.Get(0).(SEQ) - } - - if rf, ok := ret.Get(1).(func(ADDR, CHAIN_ID, ...pg.QOpt) error); ok { - r1 = rf(address, chainID, qopts...) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // SubscribeToKeyChanges provides a mock function with given fields: func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) SubscribeToKeyChanges() (chan struct{}, func()) { ret := _m.Called() diff --git a/common/txmgr/types/mocks/tx_store.go b/common/txmgr/types/mocks/tx_store.go index dd40a064b9c..7384bf82ec0 100644 --- a/common/txmgr/types/mocks/tx_store.go +++ b/common/txmgr/types/mocks/tx_store.go @@ -8,8 +8,6 @@ import ( feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" mock "github.com/stretchr/testify/mock" - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - time "time" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -143,6 +141,30 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) DeleteInPro return r0 } +// FindLatestSequence provides a mock function with given fields: ctx, fromAddress, chainId +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindLatestSequence(ctx context.Context, fromAddress ADDR, chainId CHAIN_ID) (SEQ, error) { + ret := _m.Called(ctx, fromAddress, chainId) + + var r0 SEQ + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) (SEQ, error)); ok { + return rf(ctx, fromAddress, chainId) + } + if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) SEQ); ok { + r0 = rf(ctx, fromAddress, chainId) + } else { + r0 = ret.Get(0).(SEQ) + } + + if rf, ok := ret.Get(1).(func(context.Context, ADDR, CHAIN_ID) error); ok { + r1 = rf(ctx, fromAddress, chainId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // FindNextUnstartedTransactionFromAddress provides a mock function with given fields: ctx, etx, fromAddress, chainID func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindNextUnstartedTransactionFromAddress(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], fromAddress ADDR, chainID CHAIN_ID) error { ret := _m.Called(ctx, etx, fromAddress, chainID) @@ -673,41 +695,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateBroad return r0 } -// UpdateKeyNextSequence provides a mock function with given fields: newNextSequence, currentNextSequence, address, chainID, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateKeyNextSequence(newNextSequence SEQ, currentNextSequence SEQ, address ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, newNextSequence, currentNextSequence, address, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 error - if rf, ok := ret.Get(0).(func(SEQ, SEQ, ADDR, CHAIN_ID, ...pg.QOpt) error); ok { - r0 = rf(newNextSequence, currentNextSequence, address, chainID, qopts...) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// UpdateTxAttemptInProgressToBroadcast provides a mock function with given fields: etx, attempt, NewAttemptState, incrNextSequenceCallback, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxAttemptInProgressToBroadcast(etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], NewAttemptState txmgrtypes.TxAttemptState, incrNextSequenceCallback func(pg.Queryer) error, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, etx, attempt, NewAttemptState, incrNextSequenceCallback) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// UpdateTxAttemptInProgressToBroadcast provides a mock function with given fields: ctx, etx, attempt, NewAttemptState +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxAttemptInProgressToBroadcast(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], NewAttemptState txmgrtypes.TxAttemptState) error { + ret := _m.Called(ctx, etx, attempt, NewAttemptState) var r0 error - if rf, ok := ret.Get(0).(func(*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txmgrtypes.TxAttemptState, func(pg.Queryer) error, ...pg.QOpt) error); ok { - r0 = rf(etx, attempt, NewAttemptState, incrNextSequenceCallback, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txmgrtypes.TxAttemptState) error); ok { + r0 = rf(ctx, etx, attempt, NewAttemptState) } else { r0 = ret.Error(0) } diff --git a/common/txmgr/types/tx_store.go b/common/txmgr/types/tx_store.go index a17188be441..059a87d7ab2 100644 --- a/common/txmgr/types/tx_store.go +++ b/common/txmgr/types/tx_store.go @@ -34,7 +34,6 @@ type TxStore[ UnstartedTxQueuePruner TxHistoryReaper[CHAIN_ID] TransactionStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, SEQ, FEE] - SequenceStore[ADDR, CHAIN_ID, SEQ] // methods for saving & retreiving receipts FindReceiptsPendingConfirmation(ctx context.Context, blockNum int64, chainID CHAIN_ID) (receiptsPlus []ReceiptPlus[R], err error) @@ -59,6 +58,7 @@ type TransactionStore[ CountUnstartedTransactions(ctx context.Context, fromAddress ADDR, chainID CHAIN_ID) (count uint32, err error) CreateTransaction(ctx context.Context, txRequest TxRequest[ADDR, TX_HASH], chainID CHAIN_ID) (tx Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) DeleteInProgressAttempt(ctx context.Context, attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error + FindLatestSequence(ctx context.Context, fromAddress ADDR, chainId CHAIN_ID) (SEQ, error) FindTxsRequiringGasBump(ctx context.Context, address ADDR, blockNum, gasBumpThreshold, depth int64, chainID CHAIN_ID) (etxs []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) FindTxsRequiringResubmissionDueToInsufficientFunds(ctx context.Context, address ADDR, chainID CHAIN_ID) (etxs []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) FindTxAttemptsConfirmedMissingReceipt(ctx context.Context, chainID CHAIN_ID) (attempts []TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) @@ -84,7 +84,7 @@ type TransactionStore[ SaveSentAttempt(ctx context.Context, timeout time.Duration, attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error SetBroadcastBeforeBlockNum(ctx context.Context, blockNum int64, chainID CHAIN_ID) error UpdateBroadcastAts(ctx context.Context, now time.Time, etxIDs []int64) error - UpdateTxAttemptInProgressToBroadcast(etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], NewAttemptState TxAttemptState, incrNextSequenceCallback QueryerFunc, qopts ...pg.QOpt) error + UpdateTxAttemptInProgressToBroadcast(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], NewAttemptState TxAttemptState) error UpdateTxsUnconfirmed(ctx context.Context, ids []int64) error UpdateTxUnstartedToInProgress(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error UpdateTxFatalError(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error @@ -99,14 +99,6 @@ type UnstartedTxQueuePruner interface { PruneUnstartedTxQueue(ctx context.Context, queueSize uint32, subject uuid.UUID) (n int64, err error) } -type SequenceStore[ - ADDR types.Hashable, - CHAIN_ID types.ID, - SEQ types.Sequence, -] interface { - UpdateKeyNextSequence(newNextSequence, currentNextSequence SEQ, address ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) error -} - // R is the raw unparsed transaction receipt type ReceiptPlus[R any] struct { ID uuid.UUID `db:"pipeline_run_id"` diff --git a/common/types/chain.go b/common/types/chain.go index 800f0d9fdc0..c2c2011d8de 100644 --- a/common/types/chain.go +++ b/common/types/chain.go @@ -9,6 +9,9 @@ type Sequence interface { Int64() int64 // needed for numeric sequence confirmation - to be removed with confirmation logic generalization: https://smartcontract-it.atlassian.net/browse/BCI-860 } +// Generate the next usable sequence for a transaction +type GenerateNextSequenceFunc[SEQ Sequence] func(prev SEQ) SEQ + // ID represents the base type, for any chain's ID. // It should be convertible to a string, that can uniquely identify this chain type ID fmt.Stringer diff --git a/contracts/.solhintignore b/contracts/.solhintignore index 88ad92c6b87..d36b4a27261 100644 --- a/contracts/.solhintignore +++ b/contracts/.solhintignore @@ -1,22 +1,9 @@ -# 368 warnings +# 351 warnings #./src/v0.8/automation -# 302 warnings +# 60 warnings #./src/v0.8/dev # 91 warnings #./src/v0.8/functions -# 91 warnings -#./src/v0.8/l2ep/dev -# 116 warnings -#./src/v0.8/vrf - -# Temp ignore the following files as they contain issues. -./src/v0.8/ChainlinkClient.sol -./src/v0.8/Flags.sol -./src/v0.8/KeepersVRFConsumer.sol -./src/v0.8/PermissionedForwardProxy.sol -./src/v0.8/ValidatorProxy.sol -./src/v0.8/Chainlink.sol -./src/v0.8/ChainSpecificUtil.sol # Ignore tests, this should not be the long term plan but is OK in the short term diff --git a/contracts/CHANGELOG.md b/contracts/CHANGELOG.md index 1cb2e0e905b..5f06c21c250 100644 --- a/contracts/CHANGELOG.md +++ b/contracts/CHANGELOG.md @@ -2,7 +2,12 @@ ## Unreleased -... +- Moved `VRFCoordinatorV2Mock.sol` to src/v0.8/vrf/mocks +- Moved `VRFCoordinatorMock.sol` to src/v0.8/vrf/mocks + +### Removed + +- Removed all code related to versions prior to Solidity 0.8.0 (#10931) ## 0.8.0 - 2023-10-04 diff --git a/contracts/GNUmakefile b/contracts/GNUmakefile index 328c921545c..5e9397e2b0e 100644 --- a/contracts/GNUmakefile +++ b/contracts/GNUmakefile @@ -38,7 +38,7 @@ mockery: $(mockery) ## Install mockery. .PHONY: foundry foundry: ## Install foundry. - foundryup --version nightly-ca67d15f4abd46394b324c50e21e66f306a1162d + foundryup --version nightly-e0722a10b45859892ec3b998df958a9edc77c202 .PHONY: foundry-refresh foundry-refresh: foundry diff --git a/contracts/foundry-lib/forge-std b/contracts/foundry-lib/forge-std index 1d9650e9512..f73c73d2018 160000 --- a/contracts/foundry-lib/forge-std +++ b/contracts/foundry-lib/forge-std @@ -1 +1 @@ -Subproject commit 1d9650e951204a0ddce9ff89c32f1997984cef4d +Subproject commit f73c73d2018eb6a111f35e4dae7b4f27401e9421 diff --git a/contracts/foundry.toml b/contracts/foundry.toml index d1bec52c391..1228ce3ec03 100644 --- a/contracts/foundry.toml +++ b/contracts/foundry.toml @@ -33,13 +33,18 @@ optimizer_runs = 10000 src = 'src/v0.8/automation' test = 'src/v0.8/automation/test' +[profile.l2ep] +optimizer_runs = 1000000 +src = 'src/v0.8/l2ep' +test = 'src/v0.8/l2ep/test' + + [profile.llo-feeds] optimizer_runs = 1000000 src = 'src/v0.8/llo-feeds' test = 'src/v0.8/llo-feeds/test' solc_version = '0.8.16' -# We cannot turn on deny_warnings = true as that will -# hide any CI failure +# We cannot turn on deny_warnings = true as that will hide any CI failure [profile.shared] optimizer_runs = 1000000 diff --git a/contracts/gas-snapshots/functions.gas-snapshot b/contracts/gas-snapshots/functions.gas-snapshot index 0c3caa6522e..b2ef072c1f7 100644 --- a/contracts/gas-snapshots/functions.gas-snapshot +++ b/contracts/gas-snapshots/functions.gas-snapshot @@ -95,9 +95,9 @@ FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotAll FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotSubscriptionOwner() (gas: 89316) FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPaused() (gas: 20191) FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPendingRequests() (gas: 193222) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitAllBalanceAsDeposit() (gas: 113352) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitSomeBalanceAsDeposit() (gas: 124604) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessRecieveDeposit() (gas: 310090) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitAllBalanceAsDeposit() (gas: 114636) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitSomeBalanceAsDeposit() (gas: 125891) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessRecieveDeposit() (gas: 311988) FunctionsSubscriptions_Constructor:test_Constructor_Success() (gas: 7654) FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfNotAllowedSender() (gas: 28637) FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfPaused() (gas: 17948) @@ -106,8 +106,8 @@ FunctionsSubscriptions_GetConsumer:test_GetConsumer_Success() (gas: 16225) FunctionsSubscriptions_GetFlags:test_GetFlags_Success() (gas: 40858) FunctionsSubscriptions_GetSubscription:test_GetSubscription_Success() (gas: 30959) FunctionsSubscriptions_GetSubscriptionCount:test_GetSubscriptionCount_Success() (gas: 12967) -FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfEndIsAfterLastSubscription() (gas: 14949) -FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfStartIsAfterEnd() (gas: 11863) +FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfEndIsAfterLastSubscription() (gas: 16523) +FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfStartIsAfterEnd() (gas: 13436) FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_Success() (gas: 59568) FunctionsSubscriptions_GetTotalBalance:test_GetTotalBalance_Success() (gas: 15032) FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata() (gas: 27594) @@ -124,7 +124,7 @@ FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_SuccessSetsBalanceToZe FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_RevertIfNoSubscription() (gas: 12818) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_RevertIfNotOwner() (gas: 15549) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_Success() (gas: 54867) -FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessDeletesSubscription() (gas: 48362) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessDeletesSubscription() (gas: 49624) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessSubOwnerRefunded() (gas: 50896) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessWhenRequestInFlight() (gas: 163867) FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfAmountMoreThanBalance() (gas: 17924) diff --git a/contracts/gas-snapshots/llo-feeds.gas-snapshot b/contracts/gas-snapshots/llo-feeds.gas-snapshot index 74b9a9f9258..a9877fbe33c 100644 --- a/contracts/gas-snapshots/llo-feeds.gas-snapshot +++ b/contracts/gas-snapshots/llo-feeds.gas-snapshot @@ -20,7 +20,7 @@ FeeManagerProcessFeeTest:test_discountIsNoLongerAppliedAfterRemoving() (gas: 459 FeeManagerProcessFeeTest:test_discountIsNotAppliedForInvalidTokenAddress() (gas: 17546) FeeManagerProcessFeeTest:test_discountIsNotAppliedToOtherFeeds() (gas: 54241) FeeManagerProcessFeeTest:test_discountIsReturnedForLink() (gas: 49252) -FeeManagerProcessFeeTest:test_emptyQuoteRevertsWithError() (gas: 11286) +FeeManagerProcessFeeTest:test_emptyQuoteRevertsWithError() (gas: 12152) FeeManagerProcessFeeTest:test_eventIsEmittedAfterSurchargeIsSet() (gas: 41348) FeeManagerProcessFeeTest:test_eventIsEmittedIfNotEnoughLink() (gas: 172711) FeeManagerProcessFeeTest:test_eventIsEmittedUponWithdraw() (gas: 68984) @@ -87,7 +87,7 @@ FeeManagerProcessFeeTest:test_surchargeIsAppliedForNativeFeeWithDiscount() (gas: FeeManagerProcessFeeTest:test_surchargeIsNoLongerAppliedAfterRemoving() (gas: 46503) FeeManagerProcessFeeTest:test_surchargeIsNotAppliedForLinkFee() (gas: 49585) FeeManagerProcessFeeTest:test_surchargeIsNotAppliedWith100PercentDiscount() (gas: 77890) -FeeManagerProcessFeeTest:test_testRevertIfReportHasExpired() (gas: 14042) +FeeManagerProcessFeeTest:test_testRevertIfReportHasExpired() (gas: 14908) RewardManagerClaimTest:test_claimAllRecipients() (gas: 275763) RewardManagerClaimTest:test_claimMultipleRecipients() (gas: 153306) RewardManagerClaimTest:test_claimRewardsWithDuplicatePoolIdsDoesNotPayoutTwice() (gas: 328345) @@ -123,7 +123,7 @@ RewardManagerRecipientClaimMultiplePoolsTest:test_claimSingleUniqueRecipient() ( RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnevenAmountRoundsDown() (gas: 576289) RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnregisteredRecipient() (gas: 63555) RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorAndTotalPoolsEqual() (gas: 10202) -RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorCannotBeGreaterThanTotalPools() (gas: 11107) +RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorCannotBeGreaterThanTotalPools() (gas: 12680) RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorSingleResult() (gas: 19606) RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPools() (gas: 29052) RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPoolsWhereAlreadyClaimed() (gas: 147218) @@ -181,11 +181,11 @@ VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrappedReturnsChange( VerifierConstructorTest:test_revertsIfInitializedWithEmptyVerifierProxy() (gas: 59967) VerifierConstructorTest:test_setsTheCorrectProperties() (gas: 1815769) VerifierDeactivateFeedWithVerifyTest:test_currentReportAllowsVerification() (gas: 192062) -VerifierDeactivateFeedWithVerifyTest:test_currentReportFailsVerification() (gas: 111727) +VerifierDeactivateFeedWithVerifyTest:test_currentReportFailsVerification() (gas: 113377) VerifierDeactivateFeedWithVerifyTest:test_previousReportAllowsVerification() (gas: 99613) -VerifierDeactivateFeedWithVerifyTest:test_previousReportFailsVerification() (gas: 68305) +VerifierDeactivateFeedWithVerifyTest:test_previousReportFailsVerification() (gas: 69932) VerifierProxyAccessControlledVerificationTest:test_proxiesToTheVerifierIfHasAccess() (gas: 205796) -VerifierProxyAccessControlledVerificationTest:test_revertsIfNoAccess() (gas: 110688) +VerifierProxyAccessControlledVerificationTest:test_revertsIfNoAccess() (gas: 112334) VerifierProxyConstructorTest:test_correctlySetsTheCorrectAccessControllerInterface() (gas: 1482522) VerifierProxyConstructorTest:test_correctlySetsTheOwner() (gas: 1462646) VerifierProxyConstructorTest:test_correctlySetsVersion() (gas: 6873) @@ -207,7 +207,7 @@ VerifierProxyUnsetVerifierTest:test_revertsIfNotAdmin() (gas: 14965) VerifierProxyUnsetVerifierWithPreviouslySetVerifierTest:test_correctlyUnsetsVerifier() (gas: 12720) VerifierProxyUnsetVerifierWithPreviouslySetVerifierTest:test_emitsAnEventAfterUnsettingVerifier() (gas: 17965) VerifierProxyVerifyTest:test_proxiesToTheCorrectVerifier() (gas: 201609) -VerifierProxyVerifyTest:test_revertsIfNoVerifierConfigured() (gas: 115615) +VerifierProxyVerifyTest:test_revertsIfNoVerifierConfigured() (gas: 117256) VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlySetsConfigWhenDigestsAreRemoved() (gas: 538896) VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesDigestsOnMultipleVerifiersInTheProxy() (gas: 964726) VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesTheDigestInTheProxy() (gas: 520480) @@ -230,17 +230,17 @@ VerifierTestBillingReport:test_verifyWithNativeUnwrapped() (gas: 317892) VerifierTestBillingReport:test_verifyWithNativeUnwrappedReturnsChange() (gas: 324958) VerifierVerifyMultipleConfigDigestTest:test_canVerifyNewerReportsWithNewerConfigs() (gas: 131228) VerifierVerifyMultipleConfigDigestTest:test_canVerifyOlderReportsWithOlderConfigs() (gas: 187132) -VerifierVerifyMultipleConfigDigestTest:test_revertsIfAReportIsVerifiedWithAnExistingButIncorrectDigest() (gas: 86566) -VerifierVerifyMultipleConfigDigestTest:test_revertsIfVerifyingWithAnUnsetDigest() (gas: 126411) +VerifierVerifyMultipleConfigDigestTest:test_revertsIfAReportIsVerifiedWithAnExistingButIncorrectDigest() (gas: 88205) +VerifierVerifyMultipleConfigDigestTest:test_revertsIfVerifyingWithAnUnsetDigest() (gas: 128062) VerifierVerifySingleConfigDigestTest:test_emitsAnEventIfReportVerified() (gas: 186945) VerifierVerifySingleConfigDigestTest:test_returnsThePriceAndBlockNumIfReportVerified() (gas: 187114) -VerifierVerifySingleConfigDigestTest:test_revertsIfConfigDigestNotSet() (gas: 114479) -VerifierVerifySingleConfigDigestTest:test_revertsIfDuplicateSignersHaveSigned() (gas: 180665) -VerifierVerifySingleConfigDigestTest:test_revertsIfMismatchedSignatureLength() (gas: 51479) -VerifierVerifySingleConfigDigestTest:test_revertsIfReportHasUnconfiguredFeedID() (gas: 102318) -VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedByNonProxy() (gas: 99348) -VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedWithIncorrectAddresses() (gas: 182416) -VerifierVerifySingleConfigDigestTest:test_revertsIfWrongNumberOfSigners() (gas: 108382) +VerifierVerifySingleConfigDigestTest:test_revertsIfConfigDigestNotSet() (gas: 116130) +VerifierVerifySingleConfigDigestTest:test_revertsIfDuplicateSignersHaveSigned() (gas: 182315) +VerifierVerifySingleConfigDigestTest:test_revertsIfMismatchedSignatureLength() (gas: 53037) +VerifierVerifySingleConfigDigestTest:test_revertsIfReportHasUnconfiguredFeedID() (gas: 103976) +VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedByNonProxy() (gas: 100992) +VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedWithIncorrectAddresses() (gas: 184066) +VerifierVerifySingleConfigDigestTest:test_revertsIfWrongNumberOfSigners() (gas: 110031) VerifierVerifySingleConfigDigestTest:test_setsTheCorrectEpoch() (gas: 194270) Verifier_accessControlledVerify:testVerifyWithAccessControl_gas() (gas: 212066) Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithLinkFeeSuccess_gas() (gas: 519368) diff --git a/contracts/package.json b/contracts/package.json index 65cc873f34f..6b5b57df8d9 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -18,11 +18,11 @@ "prepublishOnly": "pnpm compile && ./scripts/prepublish_generate_abi_folder", "publish-beta": "pnpm publish --tag beta", "publish-prod": "npm dist-tag add @chainlink/contracts@0.8.0 latest", - "solhint": "solhint --max-warnings 593 \"./src/v0.8/**/*.sol\"" + "solhint": "solhint --max-warnings 502 \"./src/v0.8/**/*.sol\"" }, "files": [ - "src/", - "abi/" + "src/v0.8", + "abi/src/v0.8" ], "pnpm": { "_comment": "See https://github.com/ethers-io/ethers.js/discussions/2849#discussioncomment-2696454", diff --git a/contracts/scripts/native_solc_compile_all_automation b/contracts/scripts/native_solc_compile_all_automation index 005570f4c12..7e0b6058aed 100755 --- a/contracts/scripts/native_solc_compile_all_automation +++ b/contracts/scripts/native_solc_compile_all_automation @@ -39,9 +39,6 @@ compileContract automation/UpkeepTranscoder.sol compileContract automation/mocks/MockAggregatorProxy.sol compileContract automation/testhelpers/LogUpkeepCounter.sol -# Keepers x VRF v2 -compileContract KeepersVRFConsumer.sol - compileContract automation/mocks/KeeperRegistrar1_2Mock.sol compileContract automation/mocks/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.sol diff --git a/contracts/scripts/native_solc_compile_all_vrf b/contracts/scripts/native_solc_compile_all_vrf index fd9f1b91539..302dc18d2fe 100755 --- a/contracts/scripts/native_solc_compile_all_vrf +++ b/contracts/scripts/native_solc_compile_all_vrf @@ -36,7 +36,7 @@ compileContract vrf/VRFRequestIDBase.sol compileContract vrf/VRFConsumerBase.sol compileContract vrf/testhelpers/VRFConsumer.sol compileContract vrf/testhelpers/VRFRequestIDBaseTestHelper.sol -compileContract mocks/VRFCoordinatorMock.sol +compileContract vrf/mocks/VRFCoordinatorMock.sol # VRF V2 compileContract vrf/VRFConsumerBaseV2.sol @@ -52,34 +52,35 @@ compileContract vrf/BatchBlockhashStore.sol compileContract vrf/BatchVRFCoordinatorV2.sol compileContract vrf/testhelpers/VRFCoordinatorV2TestHelper.sol compileContractAltOpts vrf/VRFCoordinatorV2.sol 10000 -compileContract mocks/VRFCoordinatorV2Mock.sol +compileContract vrf/mocks/VRFCoordinatorV2Mock.sol compileContract vrf/VRFOwner.sol -compileContract dev/VRFSubscriptionBalanceMonitor.sol +compileContract vrf/dev/VRFSubscriptionBalanceMonitor.sol +compileContract vrf/KeepersVRFConsumer.sol # VRF V2Plus -compileContract dev/interfaces/IVRFCoordinatorV2PlusInternal.sol -compileContract dev/vrf/testhelpers/VRFV2PlusConsumerExample.sol -compileContractAltOpts dev/vrf/VRFCoordinatorV2_5.sol 50 -compileContract dev/vrf/BatchVRFCoordinatorV2Plus.sol -compileContract dev/vrf/VRFV2PlusWrapper.sol -compileContract dev/vrf/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol -compileContract dev/vrf/testhelpers/VRFMaliciousConsumerV2Plus.sol -compileContract dev/vrf/testhelpers/VRFV2PlusExternalSubOwnerExample.sol -compileContract dev/vrf/testhelpers/VRFV2PlusSingleConsumerExample.sol -compileContract dev/vrf/testhelpers/VRFV2PlusWrapperConsumerExample.sol -compileContract dev/vrf/testhelpers/VRFV2PlusRevertingExample.sol -compileContract dev/vrf/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol -compileContract dev/vrf/testhelpers/VRFV2PlusMaliciousMigrator.sol -compileContract dev/vrf/libraries/VRFV2PlusClient.sol -compileContract dev/vrf/testhelpers/VRFCoordinatorV2Plus_V2Example.sol -compileContract dev/vrf/TrustedBlockhashStore.sol -compileContract dev/vrf/testhelpers/VRFV2PlusLoadTestWithMetrics.sol -compileContractAltOpts dev/vrf/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol 5 -compileContract dev/vrf/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol +compileContract vrf/dev/interfaces/IVRFCoordinatorV2PlusInternal.sol +compileContract vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol +compileContractAltOpts vrf/dev/VRFCoordinatorV2_5.sol 50 +compileContract vrf/dev/BatchVRFCoordinatorV2Plus.sol +compileContract vrf/dev/VRFV2PlusWrapper.sol +compileContract vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol +compileContract vrf/dev/testhelpers/VRFMaliciousConsumerV2Plus.sol +compileContract vrf/dev/testhelpers/VRFV2PlusExternalSubOwnerExample.sol +compileContract vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol +compileContract vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol +compileContract vrf/dev/testhelpers/VRFV2PlusRevertingExample.sol +compileContract vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol +compileContract vrf/dev/testhelpers/VRFV2PlusMaliciousMigrator.sol +compileContract vrf/dev/libraries/VRFV2PlusClient.sol +compileContract vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol +compileContract vrf/dev/TrustedBlockhashStore.sol +compileContract vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol +compileContractAltOpts vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol 5 +compileContract vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol # VRF V2 Wrapper compileContract vrf/VRFV2Wrapper.sol -compileContract interfaces/VRFV2WrapperInterface.sol +compileContract vrf/interfaces/VRFV2WrapperInterface.sol compileContract vrf/VRFV2WrapperConsumerBase.sol compileContract vrf/testhelpers/VRFV2WrapperConsumerExample.sol @@ -91,3 +92,8 @@ compileContract vrf/testhelpers/VRFLoadTestOwnerlessConsumer.sol compileContract vrf/testhelpers/VRFLoadTestExternalSubOwner.sol compileContract vrf/testhelpers/VRFV2LoadTestWithMetrics.sol compileContract vrf/testhelpers/VRFV2OwnerTestConsumer.sol + +# Helper contracts +compileContract vrf/interfaces/IAuthorizedReceiver.sol +compileContract vrf/interfaces/VRFCoordinatorV2Interface.sol +compileContract vrf/interfaces/VRFV2WrapperInterface.sol diff --git a/contracts/src/v0.8/ChainSpecificUtil.sol b/contracts/src/v0.8/ChainSpecificUtil.sol index 67e788d0ee4..172d8c526f2 100644 --- a/contracts/src/v0.8/ChainSpecificUtil.sol +++ b/contracts/src/v0.8/ChainSpecificUtil.sol @@ -53,10 +53,10 @@ library ChainSpecificUtil { * @notice Otherwise, it uses the blockhash opcode. * @notice Note that the blockhash opcode will return the L2 blockhash on Optimism. */ - function getBlockhash(uint64 blockNumber) internal view returns (bytes32) { + function _getBlockhash(uint64 blockNumber) internal view returns (bytes32) { uint256 chainid = block.chainid; - if (isArbitrumChainId(chainid)) { - if ((getBlockNumber() - blockNumber) > 256 || blockNumber >= getBlockNumber()) { + if (_isArbitrumChainId(chainid)) { + if ((_getBlockNumber() - blockNumber) > 256 || blockNumber >= _getBlockNumber()) { return ""; } return ARBSYS.arbBlockHash(blockNumber); @@ -70,9 +70,9 @@ library ChainSpecificUtil { * @notice Otherwise, it uses the block.number opcode. * @notice Note that the block.number opcode will return the L2 block number on Optimism. */ - function getBlockNumber() internal view returns (uint256) { + function _getBlockNumber() internal view returns (uint256) { uint256 chainid = block.chainid; - if (isArbitrumChainId(chainid)) { + if (_isArbitrumChainId(chainid)) { return ARBSYS.arbBlockNumber(); } return block.number; @@ -86,11 +86,11 @@ library ChainSpecificUtil { * @notice On Optimism, the provided calldata is passed to the OVM_GasPriceOracle predeploy * @notice and getL1Fee is called to get the fees. */ - function getCurrentTxL1GasFees(bytes memory txCallData) internal view returns (uint256) { + function _getCurrentTxL1GasFees(bytes memory txCallData) internal view returns (uint256) { uint256 chainid = block.chainid; - if (isArbitrumChainId(chainid)) { + if (_isArbitrumChainId(chainid)) { return ARBGAS.getCurrentTxL1GasFees(); - } else if (isOptimismChainId(chainid)) { + } else if (_isOptimismChainId(chainid)) { return OVM_GASPRICEORACLE.getL1Fee(bytes.concat(txCallData, L1_FEE_DATA_PADDING)); } return 0; @@ -100,15 +100,15 @@ library ChainSpecificUtil { * @notice Returns the gas cost in wei of calldataSizeBytes of calldata being posted * @notice to L1. */ - function getL1CalldataGasCost(uint256 calldataSizeBytes) internal view returns (uint256) { + function _getL1CalldataGasCost(uint256 calldataSizeBytes) internal view returns (uint256) { uint256 chainid = block.chainid; - if (isArbitrumChainId(chainid)) { + if (_isArbitrumChainId(chainid)) { (, uint256 l1PricePerByte, , , , ) = ARBGAS.getPricesInWei(); // see https://developer.arbitrum.io/devs-how-tos/how-to-estimate-gas#where-do-we-get-all-this-information-from // for the justification behind the 140 number. return l1PricePerByte * (calldataSizeBytes + 140); - } else if (isOptimismChainId(chainid)) { - return calculateOptimismL1DataFee(calldataSizeBytes); + } else if (_isOptimismChainId(chainid)) { + return _calculateOptimismL1DataFee(calldataSizeBytes); } return 0; } @@ -116,7 +116,7 @@ library ChainSpecificUtil { /** * @notice Return true if and only if the provided chain ID is an Arbitrum chain ID. */ - function isArbitrumChainId(uint256 chainId) internal pure returns (bool) { + function _isArbitrumChainId(uint256 chainId) internal pure returns (bool) { return chainId == ARB_MAINNET_CHAIN_ID || chainId == ARB_GOERLI_TESTNET_CHAIN_ID || @@ -127,7 +127,7 @@ library ChainSpecificUtil { * @notice Return true if and only if the provided chain ID is an Optimism chain ID. * @notice Note that optimism chain id's are also OP stack chain id's. */ - function isOptimismChainId(uint256 chainId) internal pure returns (bool) { + function _isOptimismChainId(uint256 chainId) internal pure returns (bool) { return chainId == OP_MAINNET_CHAIN_ID || chainId == OP_GOERLI_CHAIN_ID || @@ -136,7 +136,7 @@ library ChainSpecificUtil { chainId == BASE_GOERLI_CHAIN_ID; } - function calculateOptimismL1DataFee(uint256 calldataSizeBytes) internal view returns (uint256) { + function _calculateOptimismL1DataFee(uint256 calldataSizeBytes) internal view returns (uint256) { // from: https://community.optimism.io/docs/developers/build/transaction-fees/#the-l1-data-fee // l1_data_fee = l1_gas_price * (tx_data_gas + fixed_overhead) * dynamic_overhead // tx_data_gas = count_zero_bytes(tx_data) * 4 + count_non_zero_bytes(tx_data) * 16 diff --git a/contracts/src/v0.8/Chainlink.sol b/contracts/src/v0.8/Chainlink.sol index 0475a351473..e511cfc8085 100644 --- a/contracts/src/v0.8/Chainlink.sol +++ b/contracts/src/v0.8/Chainlink.sol @@ -9,7 +9,8 @@ import {BufferChainlink} from "./vendor/BufferChainlink.sol"; * @dev Uses imported CBOR library for encoding to buffer */ library Chainlink { - uint256 internal constant defaultBufferSize = 256; // solhint-disable-line const-name-snakecase + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + uint256 internal constant defaultBufferSize = 256; using CBORChainlink for BufferChainlink.buffer; @@ -30,7 +31,7 @@ library Chainlink { * @param callbackFunc The callback function signature * @return The initialized request */ - function initialize( + function _initialize( Request memory self, bytes32 jobId, address callbackAddr, @@ -49,7 +50,7 @@ library Chainlink { * @param self The initialized request * @param data The CBOR data */ - function setBuffer(Request memory self, bytes memory data) internal pure { + function _setBuffer(Request memory self, bytes memory data) internal pure { BufferChainlink.init(self.buf, data.length); BufferChainlink.append(self.buf, data); } @@ -60,7 +61,7 @@ library Chainlink { * @param key The name of the key * @param value The string value to add */ - function add(Request memory self, string memory key, string memory value) internal pure { + function _add(Request memory self, string memory key, string memory value) internal pure { self.buf.encodeString(key); self.buf.encodeString(value); } @@ -71,7 +72,7 @@ library Chainlink { * @param key The name of the key * @param value The bytes value to add */ - function addBytes(Request memory self, string memory key, bytes memory value) internal pure { + function _addBytes(Request memory self, string memory key, bytes memory value) internal pure { self.buf.encodeString(key); self.buf.encodeBytes(value); } @@ -82,7 +83,7 @@ library Chainlink { * @param key The name of the key * @param value The int256 value to add */ - function addInt(Request memory self, string memory key, int256 value) internal pure { + function _addInt(Request memory self, string memory key, int256 value) internal pure { self.buf.encodeString(key); self.buf.encodeInt(value); } @@ -93,7 +94,7 @@ library Chainlink { * @param key The name of the key * @param value The uint256 value to add */ - function addUint(Request memory self, string memory key, uint256 value) internal pure { + function _addUint(Request memory self, string memory key, uint256 value) internal pure { self.buf.encodeString(key); self.buf.encodeUInt(value); } @@ -104,7 +105,7 @@ library Chainlink { * @param key The name of the key * @param values The array of string values to add */ - function addStringArray(Request memory self, string memory key, string[] memory values) internal pure { + function _addStringArray(Request memory self, string memory key, string[] memory values) internal pure { self.buf.encodeString(key); self.buf.startArray(); for (uint256 i = 0; i < values.length; i++) { diff --git a/contracts/src/v0.8/ChainlinkClient.sol b/contracts/src/v0.8/ChainlinkClient.sol index fda69143f45..2d9302faef7 100644 --- a/contracts/src/v0.8/ChainlinkClient.sol +++ b/contracts/src/v0.8/ChainlinkClient.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./Chainlink.sol"; -import "./interfaces/ENSInterface.sol"; -import "./shared/interfaces/LinkTokenInterface.sol"; -import "./interfaces/ChainlinkRequestInterface.sol"; -import "./interfaces/OperatorInterface.sol"; -import "./interfaces/PointerInterface.sol"; +import {Chainlink} from "./Chainlink.sol"; +import {ENSInterface} from "./interfaces/ENSInterface.sol"; +import {LinkTokenInterface} from "./shared/interfaces/LinkTokenInterface.sol"; +import {ChainlinkRequestInterface} from "./interfaces/ChainlinkRequestInterface.sol"; +import {OperatorInterface} from "./interfaces/OperatorInterface.sol"; +import {PointerInterface} from "./interfaces/PointerInterface.sol"; import {ENSResolver as ENSResolver_Chainlink} from "./vendor/ENSResolver.sol"; /** @@ -14,6 +14,7 @@ import {ENSResolver as ENSResolver_Chainlink} from "./vendor/ENSResolver.sol"; * @notice Contract writers can inherit this contract in order to create requests for the * Chainlink network */ +// solhint-disable custom-errors abstract contract ChainlinkClient { using Chainlink for Chainlink.Request; @@ -44,13 +45,13 @@ abstract contract ChainlinkClient { * @param callbackFunctionSignature function signature to use for the callback * @return A Chainlink Request struct in memory */ - function buildChainlinkRequest( + function _buildChainlinkRequest( bytes32 specId, address callbackAddr, bytes4 callbackFunctionSignature ) internal pure returns (Chainlink.Request memory) { Chainlink.Request memory req; - return req.initialize(specId, callbackAddr, callbackFunctionSignature); + return req._initialize(specId, callbackAddr, callbackFunctionSignature); } /** @@ -59,12 +60,12 @@ abstract contract ChainlinkClient { * @param callbackFunctionSignature function signature to use for the callback * @return A Chainlink Request struct in memory */ - function buildOperatorRequest( + function _buildOperatorRequest( bytes32 specId, bytes4 callbackFunctionSignature ) internal view returns (Chainlink.Request memory) { Chainlink.Request memory req; - return req.initialize(specId, address(this), callbackFunctionSignature); + return req._initialize(specId, address(this), callbackFunctionSignature); } /** @@ -74,8 +75,8 @@ abstract contract ChainlinkClient { * @param payment The amount of LINK to send for the request * @return requestId The request ID */ - function sendChainlinkRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) { - return sendChainlinkRequestTo(address(s_oracle), req, payment); + function _sendChainlinkRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) { + return _sendChainlinkRequestTo(address(s_oracle), req, payment); } /** @@ -88,7 +89,7 @@ abstract contract ChainlinkClient { * @param payment The amount of LINK to send for the request * @return requestId The request ID */ - function sendChainlinkRequestTo( + function _sendChainlinkRequestTo( address oracleAddress, Chainlink.Request memory req, uint256 payment @@ -117,8 +118,8 @@ abstract contract ChainlinkClient { * @param payment The amount of LINK to send for the request * @return requestId The request ID */ - function sendOperatorRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) { - return sendOperatorRequestTo(address(s_oracle), req, payment); + function _sendOperatorRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) { + return _sendOperatorRequestTo(address(s_oracle), req, payment); } /** @@ -132,7 +133,7 @@ abstract contract ChainlinkClient { * @param payment The amount of LINK to send for the request * @return requestId The request ID */ - function sendOperatorRequestTo( + function _sendOperatorRequestTo( address oracleAddress, Chainlink.Request memory req, uint256 payment @@ -182,7 +183,7 @@ abstract contract ChainlinkClient { * @param callbackFunc The callback function specified for the request * @param expiration The time of the expiration for the request */ - function cancelChainlinkRequest( + function _cancelChainlinkRequest( bytes32 requestId, uint256 payment, bytes4 callbackFunc, @@ -199,7 +200,7 @@ abstract contract ChainlinkClient { * @dev starts at 1 in order to ensure consistent gas cost * @return returns the next request count to be used in a nonce */ - function getNextRequestCount() internal view returns (uint256) { + function _getNextRequestCount() internal view returns (uint256) { return s_requestCount; } @@ -207,7 +208,7 @@ abstract contract ChainlinkClient { * @notice Sets the stored oracle address * @param oracleAddress The address of the oracle contract */ - function setChainlinkOracle(address oracleAddress) internal { + function _setChainlinkOracle(address oracleAddress) internal { s_oracle = OperatorInterface(oracleAddress); } @@ -215,7 +216,7 @@ abstract contract ChainlinkClient { * @notice Sets the LINK token address * @param linkAddress The address of the LINK token contract */ - function setChainlinkToken(address linkAddress) internal { + function _setChainlinkToken(address linkAddress) internal { s_link = LinkTokenInterface(linkAddress); } @@ -223,15 +224,15 @@ abstract contract ChainlinkClient { * @notice Sets the Chainlink token address for the public * network as given by the Pointer contract */ - function setPublicChainlinkToken() internal { - setChainlinkToken(PointerInterface(LINK_TOKEN_POINTER).getAddress()); + function _setPublicChainlinkToken() internal { + _setChainlinkToken(PointerInterface(LINK_TOKEN_POINTER).getAddress()); } /** * @notice Retrieves the stored address of the LINK token * @return The address of the LINK token */ - function chainlinkTokenAddress() internal view returns (address) { + function _chainlinkTokenAddress() internal view returns (address) { return address(s_link); } @@ -239,7 +240,7 @@ abstract contract ChainlinkClient { * @notice Retrieves the stored address of the oracle contract * @return The address of the oracle contract */ - function chainlinkOracleAddress() internal view returns (address) { + function _chainlinkOracleAddress() internal view returns (address) { return address(s_oracle); } @@ -249,7 +250,10 @@ abstract contract ChainlinkClient { * @param oracleAddress The address of the oracle contract that will fulfill the request * @param requestId The request ID used for the response */ - function addChainlinkExternalRequest(address oracleAddress, bytes32 requestId) internal notPendingRequest(requestId) { + function _addChainlinkExternalRequest( + address oracleAddress, + bytes32 requestId + ) internal notPendingRequest(requestId) { s_pendingRequests[requestId] = oracleAddress; } @@ -259,23 +263,23 @@ abstract contract ChainlinkClient { * @param ensAddress The address of the ENS contract * @param node The ENS node hash */ - function useChainlinkWithENS(address ensAddress, bytes32 node) internal { + function _useChainlinkWithENS(address ensAddress, bytes32 node) internal { s_ens = ENSInterface(ensAddress); s_ensNode = node; bytes32 linkSubnode = keccak256(abi.encodePacked(s_ensNode, ENS_TOKEN_SUBNAME)); ENSResolver_Chainlink resolver = ENSResolver_Chainlink(s_ens.resolver(linkSubnode)); - setChainlinkToken(resolver.addr(linkSubnode)); - updateChainlinkOracleWithENS(); + _setChainlinkToken(resolver.addr(linkSubnode)); + _updateChainlinkOracleWithENS(); } /** * @notice Sets the stored oracle contract with the address resolved by ENS * @dev This may be called on its own as long as `useChainlinkWithENS` has been called previously */ - function updateChainlinkOracleWithENS() internal { + function _updateChainlinkOracleWithENS() internal { bytes32 oracleSubnode = keccak256(abi.encodePacked(s_ensNode, ENS_ORACLE_SUBNAME)); ENSResolver_Chainlink resolver = ENSResolver_Chainlink(s_ens.resolver(oracleSubnode)); - setChainlinkOracle(resolver.addr(oracleSubnode)); + _setChainlinkOracle(resolver.addr(oracleSubnode)); } /** @@ -283,7 +287,7 @@ abstract contract ChainlinkClient { * @dev Use if the contract developer prefers methods instead of modifiers for validation * @param requestId The request ID for fulfillment */ - function validateChainlinkCallback( + function _validateChainlinkCallback( bytes32 requestId ) internal diff --git a/contracts/src/v0.8/Flags.sol b/contracts/src/v0.8/Flags.sol index c4d1d0e61cd..7cd5a54b0fd 100644 --- a/contracts/src/v0.8/Flags.sol +++ b/contracts/src/v0.8/Flags.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./shared/access/SimpleReadAccessController.sol"; -import "./shared/interfaces/AccessControllerInterface.sol"; -import "./interfaces/FlagsInterface.sol"; +import {SimpleReadAccessController} from "./shared/access/SimpleReadAccessController.sol"; +import {AccessControllerInterface} from "./shared/interfaces/AccessControllerInterface.sol"; +import {FlagsInterface} from "./interfaces/FlagsInterface.sol"; /** * @title The Flags contract @@ -13,10 +13,11 @@ import "./interfaces/FlagsInterface.sol"; * to allow addresses to raise flags on themselves, so if you are subscribing to * FlagOn events you should filter for addresses you care about. */ +// solhint-disable custom-errors contract Flags is FlagsInterface, SimpleReadAccessController { AccessControllerInterface public raisingAccessController; - mapping(address => bool) private flags; + mapping(address => bool) private s_flags; event FlagRaised(address indexed subject); event FlagLowered(address indexed subject); @@ -36,7 +37,7 @@ contract Flags is FlagsInterface, SimpleReadAccessController { * false value indicates that no flag was raised. */ function getFlag(address subject) external view override checkAccess returns (bool) { - return flags[subject]; + return s_flags[subject]; } /** @@ -48,7 +49,7 @@ contract Flags is FlagsInterface, SimpleReadAccessController { function getFlags(address[] calldata subjects) external view override checkAccess returns (bool[] memory) { bool[] memory responses = new bool[](subjects.length); for (uint256 i = 0; i < subjects.length; i++) { - responses[i] = flags[subjects[i]]; + responses[i] = s_flags[subjects[i]]; } return responses; } @@ -60,9 +61,9 @@ contract Flags is FlagsInterface, SimpleReadAccessController { * @param subject The contract address whose flag is being raised */ function raiseFlag(address subject) external override { - require(allowedToRaiseFlags(), "Not allowed to raise flags"); + require(_allowedToRaiseFlags(), "Not allowed to raise flags"); - tryToRaiseFlag(subject); + _tryToRaiseFlag(subject); } /** @@ -72,10 +73,10 @@ contract Flags is FlagsInterface, SimpleReadAccessController { * @param subjects List of the contract addresses whose flag is being raised */ function raiseFlags(address[] calldata subjects) external override { - require(allowedToRaiseFlags(), "Not allowed to raise flags"); + require(_allowedToRaiseFlags(), "Not allowed to raise flags"); for (uint256 i = 0; i < subjects.length; i++) { - tryToRaiseFlag(subjects[i]); + _tryToRaiseFlag(subjects[i]); } } @@ -87,8 +88,8 @@ contract Flags is FlagsInterface, SimpleReadAccessController { for (uint256 i = 0; i < subjects.length; i++) { address subject = subjects[i]; - if (flags[subject]) { - flags[subject] = false; + if (s_flags[subject]) { + s_flags[subject] = false; emit FlagLowered(subject); } } @@ -110,13 +111,13 @@ contract Flags is FlagsInterface, SimpleReadAccessController { // PRIVATE - function allowedToRaiseFlags() private view returns (bool) { + function _allowedToRaiseFlags() private view returns (bool) { return msg.sender == owner() || raisingAccessController.hasAccess(msg.sender, msg.data); } - function tryToRaiseFlag(address subject) private { - if (!flags[subject]) { - flags[subject] = true; + function _tryToRaiseFlag(address subject) private { + if (!s_flags[subject]) { + s_flags[subject] = true; emit FlagRaised(subject); } } diff --git a/contracts/src/v0.8/PermissionedForwardProxy.sol b/contracts/src/v0.8/PermissionedForwardProxy.sol index 6206bd5420c..544f89065c0 100644 --- a/contracts/src/v0.8/PermissionedForwardProxy.sol +++ b/contracts/src/v0.8/PermissionedForwardProxy.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.6; -import "@openzeppelin/contracts/utils/Address.sol"; -import "./shared/access/ConfirmedOwner.sol"; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {ConfirmedOwner} from "./shared/access/ConfirmedOwner.sol"; /** * @title PermissionedForwardProxy diff --git a/contracts/src/v0.8/ValidatorProxy.sol b/contracts/src/v0.8/ValidatorProxy.sol index ea81719270b..35909ad87de 100644 --- a/contracts/src/v0.8/ValidatorProxy.sol +++ b/contracts/src/v0.8/ValidatorProxy.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./shared/access/ConfirmedOwner.sol"; -import "./interfaces/AggregatorValidatorInterface.sol"; -import "./interfaces/TypeAndVersionInterface.sol"; +import {ConfirmedOwner} from "./shared/access/ConfirmedOwner.sol"; +import {AggregatorValidatorInterface} from "./interfaces/AggregatorValidatorInterface.sol"; +import {TypeAndVersionInterface} from "./interfaces/TypeAndVersionInterface.sol"; +// solhint-disable custom-errors contract ValidatorProxy is AggregatorValidatorInterface, TypeAndVersionInterface, ConfirmedOwner { /// @notice Uses a single storage slot to store the current address struct AggregatorConfiguration { @@ -97,6 +98,7 @@ contract ValidatorProxy is AggregatorValidatorInterface, TypeAndVersionInterface ValidatorConfiguration memory currentValidator = s_currentValidator; address currentValidatorAddress = address(currentValidator.target); require(currentValidatorAddress != address(0), "No validator set"); + // solhint-disable-next-line avoid-low-level-calls currentValidatorAddress.call( abi.encodeWithSelector( AggregatorValidatorInterface.validate.selector, @@ -108,6 +110,7 @@ contract ValidatorProxy is AggregatorValidatorInterface, TypeAndVersionInterface ); // If there is a new proposed validator, send the validate call to that validator also if (currentValidator.hasNewProposal) { + // solhint-disable-next-line avoid-low-level-calls address(s_proposedValidator).call( abi.encodeWithSelector( AggregatorValidatorInterface.validate.selector, diff --git a/contracts/src/v0.8/automation/dev/MercuryRegistry.sol b/contracts/src/v0.8/automation/dev/MercuryRegistry.sol index e47b33fc012..9c14ce69f48 100644 --- a/contracts/src/v0.8/automation/dev/MercuryRegistry.sol +++ b/contracts/src/v0.8/automation/dev/MercuryRegistry.sol @@ -109,7 +109,7 @@ contract MercuryRegistry is ConfirmedOwner, AutomationCompatibleInterface, Strea // Extracted from `checkUpkeep` for batching purposes. function revertForFeedLookup(string[] memory feeds) public view returns (bool, bytes memory) { - uint256 blockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 blockNumber = ChainSpecificUtil._getBlockNumber(); revert StreamsLookup(c_feedParamKey, feeds, c_timeParamKey, blockNumber, ""); } diff --git a/contracts/src/v0.8/dev/BlockhashStore.sol b/contracts/src/v0.8/dev/BlockhashStore.sol deleted file mode 100644 index 4104be77ed7..00000000000 --- a/contracts/src/v0.8/dev/BlockhashStore.sol +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.6; - -import {ChainSpecificUtil} from "../ChainSpecificUtil.sol"; - -/** - * @title BlockhashStore - * @notice This contract provides a way to access blockhashes older than - * the 256 block limit imposed by the BLOCKHASH opcode. - * You may assume that any blockhash stored by the contract is correct. - * Note that the contract depends on the format of serialized Ethereum - * blocks. If a future hardfork of Ethereum changes that format, the - * logic in this contract may become incorrect and an updated version - * would have to be deployed. - */ -contract BlockhashStore { - mapping(uint256 => bytes32) internal s_blockhashes; - - /** - * @notice stores blockhash of a given block, assuming it is available through BLOCKHASH - * @param n the number of the block whose blockhash should be stored - */ - function store(uint256 n) public { - bytes32 h = ChainSpecificUtil.getBlockhash(uint64(n)); - // solhint-disable-next-line custom-errors - require(h != 0x0, "blockhash(n) failed"); - s_blockhashes[n] = h; - } - - /** - * @notice stores blockhash of the earliest block still available through BLOCKHASH. - */ - function storeEarliest() external { - store(ChainSpecificUtil.getBlockNumber() - 256); - } - - /** - * @notice stores blockhash after verifying blockheader of child/subsequent block - * @param n the number of the block whose blockhash should be stored - * @param header the rlp-encoded blockheader of block n+1. We verify its correctness by checking - * that it hashes to a stored blockhash, and then extract parentHash to get the n-th blockhash. - */ - function storeVerifyHeader(uint256 n, bytes memory header) public { - // solhint-disable-next-line custom-errors - require(keccak256(header) == s_blockhashes[n + 1], "header has unknown blockhash"); - - // At this point, we know that header is the correct blockheader for block n+1. - - // The header is an rlp-encoded list. The head item of that list is the 32-byte blockhash of the parent block. - // Based on how rlp works, we know that blockheaders always have the following form: - // 0xf9____a0PARENTHASH... - // ^ ^ ^ - // | | | - // | | +--- PARENTHASH is 32 bytes. rlpenc(PARENTHASH) is 0xa || PARENTHASH. - // | | - // | +--- 2 bytes containing the sum of the lengths of the encoded list items - // | - // +--- 0xf9 because we have a list and (sum of lengths of encoded list items) fits exactly into two bytes. - // - // As a consequence, the PARENTHASH is always at offset 4 of the rlp-encoded block header. - - bytes32 parentHash; - assembly { - parentHash := mload(add(header, 36)) // 36 = 32 byte offset for length prefix of ABI-encoded array - // + 4 byte offset of PARENTHASH (see above) - } - - s_blockhashes[n] = parentHash; - } - - /** - * @notice gets a blockhash from the store. If no hash is known, this function reverts. - * @param n the number of the block whose blockhash should be returned - */ - function getBlockhash(uint256 n) external view returns (bytes32) { - bytes32 h = s_blockhashes[n]; - // solhint-disable-next-line custom-errors - require(h != 0x0, "blockhash not found in store"); - return h; - } -} diff --git a/contracts/src/v0.8/l2ep/dev/CrossDomainDelegateForwarder.sol b/contracts/src/v0.8/l2ep/dev/CrossDomainDelegateForwarder.sol index a4c912b8ef0..1eb6cba932d 100644 --- a/contracts/src/v0.8/l2ep/dev/CrossDomainDelegateForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/CrossDomainDelegateForwarder.sol @@ -1,9 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./CrossDomainForwarder.sol"; -import "./interfaces/ForwarderInterface.sol"; -import "./interfaces/DelegateForwarderInterface.sol"; +import {CrossDomainOwnable} from "./CrossDomainOwnable.sol"; +import {DelegateForwarderInterface} from "./interfaces/DelegateForwarderInterface.sol"; /** * @title CrossDomainDelegateForwarder - L1 xDomain account representation (with delegatecall support) diff --git a/contracts/src/v0.8/l2ep/dev/CrossDomainForwarder.sol b/contracts/src/v0.8/l2ep/dev/CrossDomainForwarder.sol index 4377c2cc0d7..1f9066c5054 100644 --- a/contracts/src/v0.8/l2ep/dev/CrossDomainForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/CrossDomainForwarder.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./CrossDomainOwnable.sol"; -import "./interfaces/ForwarderInterface.sol"; +import {CrossDomainOwnable} from "./CrossDomainOwnable.sol"; +import {ForwarderInterface} from "./interfaces/ForwarderInterface.sol"; /** * @title CrossDomainForwarder - L1 xDomain account representation diff --git a/contracts/src/v0.8/l2ep/dev/CrossDomainOwnable.sol b/contracts/src/v0.8/l2ep/dev/CrossDomainOwnable.sol index 966a66372fe..b9a435a7e21 100644 --- a/contracts/src/v0.8/l2ep/dev/CrossDomainOwnable.sol +++ b/contracts/src/v0.8/l2ep/dev/CrossDomainOwnable.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/access/ConfirmedOwner.sol"; -import "./interfaces/CrossDomainOwnableInterface.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {CrossDomainOwnableInterface} from "./interfaces/CrossDomainOwnableInterface.sol"; /** * @title The CrossDomainOwnable contract @@ -42,6 +42,7 @@ contract CrossDomainOwnable is CrossDomainOwnableInterface, ConfirmedOwner { * @notice validate, transfer ownership, and emit relevant events */ function _transferL1Ownership(address to) internal { + // solhint-disable-next-line custom-errors require(to != msg.sender, "Cannot transfer to self"); s_l1PendingOwner = to; @@ -64,6 +65,7 @@ contract CrossDomainOwnable is CrossDomainOwnableInterface, ConfirmedOwner { * @notice Reverts if called by anyone other than the L1 owner. */ modifier onlyL1Owner() virtual { + // solhint-disable-next-line custom-errors require(msg.sender == s_l1Owner, "Only callable by L1 owner"); _; } @@ -72,6 +74,7 @@ contract CrossDomainOwnable is CrossDomainOwnableInterface, ConfirmedOwner { * @notice Reverts if called by anyone other than the L1 owner. */ modifier onlyProposedL1Owner() virtual { + // solhint-disable-next-line custom-errors require(msg.sender == s_l1PendingOwner, "Only callable by proposed L1 owner"); _; } diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainForwarder.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainForwarder.sol index 4f4a197d809..cdab6d49612 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainForwarder.sol @@ -1,10 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../../interfaces/TypeAndVersionInterface.sol"; -import "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/libraries/AddressAliasHelper.sol"; -import "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; -import "../CrossDomainForwarder.sol"; +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +// solhint-disable-next-line no-unused-import +import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; + +import {CrossDomainForwarder} from "../CrossDomainForwarder.sol"; +import {CrossDomainOwnable} from "../CrossDomainOwnable.sol"; + +import {AddressAliasHelper} from "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/libraries/AddressAliasHelper.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; /** * @title ArbitrumCrossDomainForwarder - L1 xDomain account representation @@ -51,6 +56,7 @@ contract ArbitrumCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor * @notice The call MUST come from the L1 owner (via cross-chain message.) Reverts otherwise. */ modifier onlyL1Owner() override { + // solhint-disable-next-line custom-errors require(msg.sender == crossDomainMessenger(), "Sender is not the L2 messenger"); _; } @@ -59,6 +65,7 @@ contract ArbitrumCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor * @notice The call MUST come from the proposed L1 owner (via cross-chain message.) Reverts otherwise. */ modifier onlyProposedL1Owner() override { + // solhint-disable-next-line custom-errors require(msg.sender == AddressAliasHelper.applyL1ToL2Alias(s_l1PendingOwner), "Must be proposed L1 owner"); _; } diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainGovernor.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainGovernor.sol index 8035d07ad2f..2f1d775e489 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainGovernor.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainGovernor.sol @@ -1,10 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../interfaces/DelegateForwarderInterface.sol"; -import "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/libraries/AddressAliasHelper.sol"; -import "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; -import "./ArbitrumCrossDomainForwarder.sol"; +// solhint-disable-next-line no-unused-import +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +// solhint-disable-next-line no-unused-import +import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; +import {DelegateForwarderInterface} from "../interfaces/DelegateForwarderInterface.sol"; + +import {ArbitrumCrossDomainForwarder} from "./ArbitrumCrossDomainForwarder.sol"; + +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; /** * @title ArbitrumCrossDomainGovernor - L1 xDomain account representation (with delegatecall support) for Arbitrum @@ -51,6 +56,7 @@ contract ArbitrumCrossDomainGovernor is DelegateForwarderInterface, ArbitrumCros * @notice The call MUST come from either the L1 owner (via cross-chain message) or the L2 owner. Reverts otherwise. */ modifier onlyLocalOrCrossDomainOwner() { + // solhint-disable-next-line custom-errors require(msg.sender == crossDomainMessenger() || msg.sender == owner(), "Sender is not the L2 messenger or owner"); _; } diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol index 5c9b3268c7f..8af16ad7b3e 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol @@ -53,11 +53,15 @@ contract ArbitrumSequencerUptimeFeed is address public constant FLAG_L2_SEQ_OFFLINE = address(bytes20(bytes32(uint256(keccak256("chainlink.flags.arbitrum-seq-offline")) - 1))); + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables uint8 public constant override decimals = 0; + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override description = "L2 Sequencer Uptime Status Feed"; + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables uint256 public constant override version = 1; /// @dev Flags contract to raise/lower flags on, during status transitions + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i FlagsInterface public immutable FLAGS; /// @dev L1 address address private s_l1Sender; @@ -70,7 +74,7 @@ contract ArbitrumSequencerUptimeFeed is * @param l1SenderAddress Address of the L1 contract that is permissioned to call this contract */ constructor(address flagsAddress, address l1SenderAddress) { - setL1Sender(l1SenderAddress); + _setL1Sender(l1SenderAddress); FLAGS = FlagsInterface(flagsAddress); } @@ -80,12 +84,12 @@ contract ArbitrumSequencerUptimeFeed is * @dev Mainly used for AggregatorV2V3Interface functions * @param roundId Round ID to check */ - function isValidRound(uint256 roundId) private view returns (bool) { + function _isValidRound(uint256 roundId) private view returns (bool) { return roundId > 0 && roundId <= type(uint80).max && s_feedState.latestRoundId >= roundId; } /// @notice Check that this contract is initialised, otherwise throw - function requireInitialized(uint80 latestRoundId) private pure { + function _requireInitialized(uint80 latestRoundId) private pure { if (latestRoundId == 0) { revert Uninitialized(); } @@ -106,7 +110,7 @@ contract ArbitrumSequencerUptimeFeed is bool currentStatus = FLAGS.getFlag(FLAG_L2_SEQ_OFFLINE); // Initialise roundId == 1 as the first round - recordRound(1, currentStatus, timestamp); + _recordRound(1, currentStatus, timestamp); emit Initialized(); } @@ -133,11 +137,11 @@ contract ArbitrumSequencerUptimeFeed is * @param to new L1 sender that will be allowed to call `updateStatus` on this contract */ function transferL1Sender(address to) external virtual onlyOwner { - setL1Sender(to); + _setL1Sender(to); } /// @notice internal method that stores the L1 sender - function setL1Sender(address to) private { + function _setL1Sender(address to) private { address from = s_l1Sender; if (from != to) { s_l1Sender = to; @@ -159,14 +163,14 @@ contract ArbitrumSequencerUptimeFeed is * * @param status The status flag to convert to an aggregator-compatible answer */ - function getStatusAnswer(bool status) private pure returns (int256) { + function _getStatusAnswer(bool status) private pure returns (int256) { return status ? int256(1) : int256(0); } /** * @notice Raise or lower the flag on the stored Flags contract. */ - function forwardStatusToFlags(bool status) private { + function _forwardStatusToFlags(bool status) private { if (status) { FLAGS.raiseFlag(FLAG_L2_SEQ_OFFLINE); } else { @@ -181,7 +185,7 @@ contract ArbitrumSequencerUptimeFeed is * @param status Sequencer status * @param timestamp Block timestamp of status update */ - function recordRound(uint80 roundId, bool status, uint64 timestamp) private { + function _recordRound(uint80 roundId, bool status, uint64 timestamp) private { Round memory nextRound = Round(status, timestamp); FeedState memory feedState = FeedState(roundId, status, timestamp); @@ -189,7 +193,7 @@ contract ArbitrumSequencerUptimeFeed is s_feedState = feedState; emit NewRound(roundId, msg.sender, timestamp); - emit AnswerUpdated(getStatusAnswer(status), roundId, timestamp); + emit AnswerUpdated(_getStatusAnswer(status), roundId, timestamp); } /** @@ -201,7 +205,7 @@ contract ArbitrumSequencerUptimeFeed is */ function updateStatus(bool status, uint64 timestamp) external override { FeedState memory feedState = s_feedState; - requireInitialized(feedState.latestRoundId); + _requireInitialized(feedState.latestRoundId); if (msg.sender != aliasedL1MessageSender()) { revert InvalidSender(); } @@ -214,37 +218,37 @@ contract ArbitrumSequencerUptimeFeed is // Prepare a new round with updated status feedState.latestRoundId += 1; - recordRound(feedState.latestRoundId, status, timestamp); + _recordRound(feedState.latestRoundId, status, timestamp); - forwardStatusToFlags(status); + _forwardStatusToFlags(status); } /// @inheritdoc AggregatorInterface function latestAnswer() external view override checkAccess returns (int256) { FeedState memory feedState = s_feedState; - requireInitialized(feedState.latestRoundId); - return getStatusAnswer(feedState.latestStatus); + _requireInitialized(feedState.latestRoundId); + return _getStatusAnswer(feedState.latestStatus); } /// @inheritdoc AggregatorInterface function latestTimestamp() external view override checkAccess returns (uint256) { FeedState memory feedState = s_feedState; - requireInitialized(feedState.latestRoundId); + _requireInitialized(feedState.latestRoundId); return feedState.latestTimestamp; } /// @inheritdoc AggregatorInterface function latestRound() external view override checkAccess returns (uint256) { FeedState memory feedState = s_feedState; - requireInitialized(feedState.latestRoundId); + _requireInitialized(feedState.latestRoundId); return feedState.latestRoundId; } /// @inheritdoc AggregatorInterface function getAnswer(uint256 roundId) external view override checkAccess returns (int256) { - requireInitialized(s_feedState.latestRoundId); - if (isValidRound(roundId)) { - return getStatusAnswer(s_rounds[uint80(roundId)].status); + _requireInitialized(s_feedState.latestRoundId); + if (_isValidRound(roundId)) { + return _getStatusAnswer(s_rounds[uint80(roundId)].status); } return 0; @@ -252,8 +256,8 @@ contract ArbitrumSequencerUptimeFeed is /// @inheritdoc AggregatorInterface function getTimestamp(uint256 roundId) external view override checkAccess returns (uint256) { - requireInitialized(s_feedState.latestRoundId); - if (isValidRound(roundId)) { + _requireInitialized(s_feedState.latestRoundId); + if (_isValidRound(roundId)) { return s_rounds[uint80(roundId)].timestamp; } @@ -270,11 +274,11 @@ contract ArbitrumSequencerUptimeFeed is checkAccess returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) { - requireInitialized(s_feedState.latestRoundId); + _requireInitialized(s_feedState.latestRoundId); - if (isValidRound(_roundId)) { + if (_isValidRound(_roundId)) { Round memory round = s_rounds[_roundId]; - answer = getStatusAnswer(round.status); + answer = _getStatusAnswer(round.status); startedAt = uint256(round.timestamp); } else { answer = 0; @@ -294,10 +298,10 @@ contract ArbitrumSequencerUptimeFeed is returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) { FeedState memory feedState = s_feedState; - requireInitialized(feedState.latestRoundId); + _requireInitialized(feedState.latestRoundId); roundId = feedState.latestRoundId; - answer = getStatusAnswer(feedState.latestStatus); + answer = _getStatusAnswer(feedState.latestStatus); startedAt = feedState.latestTimestamp; updatedAt = startedAt; answeredInRound = roundId; diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol index c882a09254a..3b5fd277e56 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol @@ -1,19 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../../interfaces/AggregatorValidatorInterface.sol"; -import "../../../interfaces/TypeAndVersionInterface.sol"; -import "../../../shared/interfaces/AccessControllerInterface.sol"; -import "../../../interfaces/AggregatorV3Interface.sol"; -import "../../../shared/access/SimpleWriteAccessController.sol"; +import {AggregatorValidatorInterface} from "../../../interfaces/AggregatorValidatorInterface.sol"; +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +import {AccessControllerInterface} from "../../../shared/interfaces/AccessControllerInterface.sol"; +import {SimpleWriteAccessController} from "../../../shared/access/SimpleWriteAccessController.sol"; /* ./dev dependencies - to be moved from ./dev after audit */ -import "../interfaces/ArbitrumSequencerUptimeFeedInterface.sol"; -import "../../../dev/interfaces/FlagsInterface.sol"; -import "../interfaces/IArbitrumDelayedInbox.sol"; -import "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/libraries/AddressAliasHelper.sol"; -import "../../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; -import "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; +import {ArbitrumSequencerUptimeFeedInterface} from "../interfaces/ArbitrumSequencerUptimeFeedInterface.sol"; +import {IArbitrumDelayedInbox} from "../interfaces/IArbitrumDelayedInbox.sol"; +import {AddressAliasHelper} from "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/libraries/AddressAliasHelper.sol"; +import {ArbSys} from "../../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; /** * @title ArbitrumValidator - makes xDomain L2 Flags contract call (using L2 xDomain Forwarder contract) @@ -36,14 +34,17 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf } /// @dev Precompiled contract that exists in every Arbitrum chain at address(100). Exposes a variety of system-level functionality. - address constant ARBSYS_ADDR = address(0x0000000000000000000000000000000000000064); + address internal constant ARBSYS_ADDR = address(0x0000000000000000000000000000000000000064); int256 private constant ANSWER_SEQ_OFFLINE = 1; /// @notice The address of Arbitrum's DelayedInbox + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i address public immutable CROSS_DOMAIN_MESSENGER; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i address public immutable L2_SEQ_STATUS_RECORDER; // L2 xDomain alias address of this contract + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i address public immutable L2_ALIAS = AddressAliasHelper.applyL1ToL2Alias(address(this)); PaymentStrategy private s_paymentStrategy; @@ -85,7 +86,7 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf * @param maxGas gas limit for immediate L2 execution attempt. A value around 1M should be sufficient * @param gasPriceBid maximum L2 gas price to pay * @param gasPriceL1FeedAddr address of the L1 gas price feed (used to approximate Arbitrum retryable ticket submission cost) - * @param paymentStrategy strategy describing how the contract pays for xDomain calls + * @param _paymentStrategy strategy describing how the contract pays for xDomain calls */ constructor( address crossDomainMessengerAddr, @@ -95,16 +96,18 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf uint256 gasPriceBid, uint256 baseFee, address gasPriceL1FeedAddr, - PaymentStrategy paymentStrategy + PaymentStrategy _paymentStrategy ) { + // solhint-disable-next-line custom-errors require(crossDomainMessengerAddr != address(0), "Invalid xDomain Messenger address"); + // solhint-disable-next-line custom-errors require(l2ArbitrumSequencerUptimeFeedAddr != address(0), "Invalid ArbitrumSequencerUptimeFeed contract address"); CROSS_DOMAIN_MESSENGER = crossDomainMessengerAddr; L2_SEQ_STATUS_RECORDER = l2ArbitrumSequencerUptimeFeedAddr; // Additional L2 payment configuration _setConfigAC(configACAddr); _setGasConfig(maxGas, gasPriceBid, baseFee, gasPriceL1FeedAddr); - _setPaymentStrategy(paymentStrategy); + _setPaymentStrategy(_paymentStrategy); } /** @@ -231,10 +234,10 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf /** * @notice sets the payment strategy * @dev access control provided by `configAC` - * @param paymentStrategy strategy describing how the contract pays for xDomain calls + * @param _paymentStrategy strategy describing how the contract pays for xDomain calls */ - function setPaymentStrategy(PaymentStrategy paymentStrategy) external onlyOwnerOrConfigAccess { - _setPaymentStrategy(paymentStrategy); + function setPaymentStrategy(PaymentStrategy _paymentStrategy) external onlyOwnerOrConfigAccess { + _setPaymentStrategy(_paymentStrategy); } /** @@ -289,15 +292,18 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf } /// @notice internal method that stores the payment strategy - function _setPaymentStrategy(PaymentStrategy paymentStrategy) internal { - s_paymentStrategy = paymentStrategy; - emit PaymentStrategySet(paymentStrategy); + function _setPaymentStrategy(PaymentStrategy _paymentStrategy) internal { + s_paymentStrategy = _paymentStrategy; + emit PaymentStrategySet(_paymentStrategy); } /// @notice internal method that stores the gas configuration function _setGasConfig(uint256 maxGas, uint256 gasPriceBid, uint256 baseFee, address gasPriceL1FeedAddr) internal { + // solhint-disable-next-line custom-errors require(maxGas > 0, "Max gas is zero"); + // solhint-disable-next-line custom-errors require(gasPriceBid > 0, "Gas price bid is zero"); + // solhint-disable-next-line custom-errors require(gasPriceL1FeedAddr != address(0), "Gas price Aggregator is zero address"); s_gasConfig = GasConfig(maxGas, gasPriceBid, baseFee, gasPriceL1FeedAddr); emit GasConfigSet(maxGas, gasPriceBid, gasPriceL1FeedAddr); @@ -337,6 +343,7 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf /// @dev reverts if the caller does not have access to change the configuration modifier onlyOwnerOrConfigAccess() { + // solhint-disable-next-line custom-errors require( msg.sender == owner() || (address(s_configAC) != address(0) && s_configAC.hasAccess(msg.sender, msg.data)), "No access" diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/IArbitrumDelayedInbox.sol b/contracts/src/v0.8/l2ep/dev/interfaces/IArbitrumDelayedInbox.sol index 65e437189a7..e18efd65ad2 100644 --- a/contracts/src/v0.8/l2ep/dev/interfaces/IArbitrumDelayedInbox.sol +++ b/contracts/src/v0.8/l2ep/dev/interfaces/IArbitrumDelayedInbox.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/bridge/interfaces/IInbox.sol"; +import {IInbox} from "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/bridge/interfaces/IInbox.sol"; /** * @notice This interface extends Arbitrum's IInbox interface to include diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainForwarder.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainForwarder.sol index 1d7c211bbac..672720156db 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainForwarder.sol @@ -1,12 +1,16 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../../interfaces/TypeAndVersionInterface.sol"; +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +// solhint-disable-next-line no-unused-import +import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; /* ./dev dependencies - to be moved from ./dev after audit */ -import "../CrossDomainForwarder.sol"; -import "../../../vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol"; -import "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; +import {CrossDomainForwarder} from "../CrossDomainForwarder.sol"; +import {CrossDomainOwnable} from "../CrossDomainOwnable.sol"; + +import {iOVM_CrossDomainMessenger} from "../../../vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; /** * @title OptimismCrossDomainForwarder - L1 xDomain account representation @@ -16,6 +20,7 @@ import "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol */ contract OptimismCrossDomainForwarder is TypeAndVersionInterface, CrossDomainForwarder { // OVM_L2CrossDomainMessenger is a precompile usually deployed to 0x4200000000000000000000000000000000000007 + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i iOVM_CrossDomainMessenger private immutable OVM_CROSS_DOMAIN_MESSENGER; /** @@ -24,6 +29,7 @@ contract OptimismCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor * @param l1OwnerAddr the L1 owner address that will be allowed to call the forward fn */ constructor(iOVM_CrossDomainMessenger crossDomainMessengerAddr, address l1OwnerAddr) CrossDomainOwnable(l1OwnerAddr) { + // solhint-disable-next-line custom-errors require(address(crossDomainMessengerAddr) != address(0), "Invalid xDomain Messenger address"); OVM_CROSS_DOMAIN_MESSENGER = crossDomainMessengerAddr; } @@ -59,7 +65,9 @@ contract OptimismCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor * @notice The call MUST come from the L1 owner (via cross-chain message.) Reverts otherwise. */ modifier onlyL1Owner() override { + // solhint-disable-next-line custom-errors require(msg.sender == crossDomainMessenger(), "Sender is not the L2 messenger"); + // solhint-disable-next-line custom-errors require( iOVM_CrossDomainMessenger(crossDomainMessenger()).xDomainMessageSender() == l1Owner(), "xDomain sender is not the L1 owner" @@ -72,7 +80,9 @@ contract OptimismCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor */ modifier onlyProposedL1Owner() override { address messenger = crossDomainMessenger(); + // solhint-disable-next-line custom-errors require(msg.sender == messenger, "Sender is not the L2 messenger"); + // solhint-disable-next-line custom-errors require( iOVM_CrossDomainMessenger(messenger).xDomainMessageSender() == s_l1PendingOwner, "Must be proposed L1 owner" diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainGovernor.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainGovernor.sol index bd1b0b9e885..1f630a3fbde 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainGovernor.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainGovernor.sol @@ -1,10 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../interfaces/DelegateForwarderInterface.sol"; -import "../../../vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol"; -import "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; -import "./OptimismCrossDomainForwarder.sol"; +import {DelegateForwarderInterface} from "../interfaces/DelegateForwarderInterface.sol"; +// solhint-disable-next-line no-unused-import +import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; + +import {OptimismCrossDomainForwarder} from "./OptimismCrossDomainForwarder.sol"; + +import {iOVM_CrossDomainMessenger} from "../../../vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; /** * @title OptimismCrossDomainGovernor - L1 xDomain account representation (with delegatecall support) for Optimism @@ -28,8 +32,6 @@ contract OptimismCrossDomainGovernor is DelegateForwarderInterface, OptimismCros * @notice versions: * * - OptimismCrossDomainForwarder 1.0.0: initial release - * - * @inheritdoc TypeAndVersionInterface */ function typeAndVersion() external pure virtual override returns (string memory) { return "OptimismCrossDomainGovernor 1.0.0"; @@ -57,9 +59,11 @@ contract OptimismCrossDomainGovernor is DelegateForwarderInterface, OptimismCros modifier onlyLocalOrCrossDomainOwner() { address messenger = crossDomainMessenger(); // 1. The delegatecall MUST come from either the L1 owner (via cross-chain message) or the L2 owner + // solhint-disable-next-line custom-errors require(msg.sender == messenger || msg.sender == owner(), "Sender is not the L2 messenger or owner"); // 2. The L2 Messenger's caller MUST be the L1 Owner if (msg.sender == messenger) { + // solhint-disable-next-line custom-errors require( iOVM_CrossDomainMessenger(messenger).xDomainMessageSender() == l1Owner(), "xDomain sender is not the L1 owner" diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol index af7ccc90574..b522a600bab 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol @@ -46,8 +46,11 @@ contract OptimismSequencerUptimeFeed is /// @dev Emitted when a updateStatus is called without the status changing event RoundUpdated(int256 status, uint64 updatedAt); + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables uint8 public constant override decimals = 0; + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override description = "L2 Sequencer Uptime Status Feed"; + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables uint256 public constant override version = 1; /// @dev L1 address @@ -56,6 +59,7 @@ contract OptimismSequencerUptimeFeed is FeedState private s_feedState = FeedState({latestRoundId: 0, latestStatus: false, startedAt: 0, updatedAt: 0}); mapping(uint80 => Round) private s_rounds; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i IL2CrossDomainMessenger private immutable s_l2CrossDomainMessenger; /** @@ -64,12 +68,12 @@ contract OptimismSequencerUptimeFeed is * @param initialStatus The initial status of the feed */ constructor(address l1SenderAddress, address l2CrossDomainMessengerAddr, bool initialStatus) { - setL1Sender(l1SenderAddress); + _setL1Sender(l1SenderAddress); s_l2CrossDomainMessenger = IL2CrossDomainMessenger(l2CrossDomainMessengerAddr); uint64 timestamp = uint64(block.timestamp); // Initialise roundId == 1 as the first round - recordRound(1, initialStatus, timestamp); + _recordRound(1, initialStatus, timestamp); } /** @@ -77,7 +81,7 @@ contract OptimismSequencerUptimeFeed is * @dev Mainly used for AggregatorV2V3Interface functions * @param roundId Round ID to check */ - function isValidRound(uint256 roundId) private view returns (bool) { + function _isValidRound(uint256 roundId) private view returns (bool) { return roundId > 0 && roundId <= type(uint80).max && s_feedState.latestRoundId >= roundId; } @@ -103,11 +107,11 @@ contract OptimismSequencerUptimeFeed is * @param to new L1 sender that will be allowed to call `updateStatus` on this contract */ function transferL1Sender(address to) external virtual onlyOwner { - setL1Sender(to); + _setL1Sender(to); } /// @notice internal method that stores the L1 sender - function setL1Sender(address to) private { + function _setL1Sender(address to) private { address from = s_l1Sender; if (from != to) { s_l1Sender = to; @@ -120,7 +124,7 @@ contract OptimismSequencerUptimeFeed is * * @param status The status flag to convert to an aggregator-compatible answer */ - function getStatusAnswer(bool status) private pure returns (int256) { + function _getStatusAnswer(bool status) private pure returns (int256) { return status ? int256(1) : int256(0); } @@ -131,7 +135,7 @@ contract OptimismSequencerUptimeFeed is * @param status Sequencer status * @param timestamp The L1 block timestamp of status update */ - function recordRound(uint80 roundId, bool status, uint64 timestamp) private { + function _recordRound(uint80 roundId, bool status, uint64 timestamp) private { uint64 updatedAt = uint64(block.timestamp); Round memory nextRound = Round(status, timestamp, updatedAt); FeedState memory feedState = FeedState(roundId, status, timestamp, updatedAt); @@ -140,7 +144,7 @@ contract OptimismSequencerUptimeFeed is s_feedState = feedState; emit NewRound(roundId, msg.sender, timestamp); - emit AnswerUpdated(getStatusAnswer(status), roundId, timestamp); + emit AnswerUpdated(_getStatusAnswer(status), roundId, timestamp); } /** @@ -149,11 +153,11 @@ contract OptimismSequencerUptimeFeed is * @param roundId The round ID to update * @param status Sequencer status */ - function updateRound(uint80 roundId, bool status) private { + function _updateRound(uint80 roundId, bool status) private { uint64 updatedAt = uint64(block.timestamp); s_rounds[roundId].updatedAt = updatedAt; s_feedState.updatedAt = updatedAt; - emit RoundUpdated(getStatusAnswer(status), updatedAt); + emit RoundUpdated(_getStatusAnswer(status), updatedAt); } /** @@ -178,17 +182,17 @@ contract OptimismSequencerUptimeFeed is } if (feedState.latestStatus == status) { - updateRound(feedState.latestRoundId, status); + _updateRound(feedState.latestRoundId, status); } else { feedState.latestRoundId += 1; - recordRound(feedState.latestRoundId, status, timestamp); + _recordRound(feedState.latestRoundId, status, timestamp); } } /// @inheritdoc AggregatorInterface function latestAnswer() external view override checkAccess returns (int256) { FeedState memory feedState = s_feedState; - return getStatusAnswer(feedState.latestStatus); + return _getStatusAnswer(feedState.latestStatus); } /// @inheritdoc AggregatorInterface @@ -205,8 +209,8 @@ contract OptimismSequencerUptimeFeed is /// @inheritdoc AggregatorInterface function getAnswer(uint256 roundId) external view override checkAccess returns (int256) { - if (isValidRound(roundId)) { - return getStatusAnswer(s_rounds[uint80(roundId)].status); + if (_isValidRound(roundId)) { + return _getStatusAnswer(s_rounds[uint80(roundId)].status); } revert NoDataPresent(); @@ -214,7 +218,7 @@ contract OptimismSequencerUptimeFeed is /// @inheritdoc AggregatorInterface function getTimestamp(uint256 roundId) external view override checkAccess returns (uint256) { - if (isValidRound(roundId)) { + if (_isValidRound(roundId)) { return s_rounds[uint80(roundId)].startedAt; } @@ -231,9 +235,9 @@ contract OptimismSequencerUptimeFeed is checkAccess returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) { - if (isValidRound(_roundId)) { + if (_isValidRound(_roundId)) { Round memory round = s_rounds[_roundId]; - answer = getStatusAnswer(round.status); + answer = _getStatusAnswer(round.status); startedAt = uint256(round.startedAt); roundId = _roundId; updatedAt = uint256(round.updatedAt); @@ -254,7 +258,7 @@ contract OptimismSequencerUptimeFeed is FeedState memory feedState = s_feedState; roundId = feedState.latestRoundId; - answer = getStatusAnswer(feedState.latestStatus); + answer = _getStatusAnswer(feedState.latestStatus); startedAt = feedState.startedAt; updatedAt = feedState.updatedAt; answeredInRound = roundId; diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol index c25b481166f..a955b7e92ca 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol @@ -1,15 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../../interfaces/AggregatorValidatorInterface.sol"; -import "../../../interfaces/TypeAndVersionInterface.sol"; -import "../../../shared/interfaces/AccessControllerInterface.sol"; -import "../../../interfaces/AggregatorV3Interface.sol"; -import "../../../shared/access/SimpleWriteAccessController.sol"; +import {AggregatorValidatorInterface} from "../../../interfaces/AggregatorValidatorInterface.sol"; +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +import {OptimismSequencerUptimeFeedInterface} from "./../interfaces/OptimismSequencerUptimeFeedInterface.sol"; -import "./../interfaces/OptimismSequencerUptimeFeedInterface.sol"; -import "@eth-optimism/contracts/L1/messaging/IL1CrossDomainMessenger.sol"; -import "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; +import {SimpleWriteAccessController} from "../../../shared/access/SimpleWriteAccessController.sol"; + +import {IL1CrossDomainMessenger} from "@eth-optimism/contracts/L1/messaging/IL1CrossDomainMessenger.sol"; /** * @title OptimismValidator - makes cross chain call to update the Sequencer Uptime Feed on L2 @@ -18,7 +16,9 @@ contract OptimismValidator is TypeAndVersionInterface, AggregatorValidatorInterf int256 private constant ANSWER_SEQ_OFFLINE = 1; uint32 private s_gasLimit; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i address public immutable L1_CROSS_DOMAIN_MESSENGER_ADDRESS; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i address public immutable L2_UPTIME_FEED_ADDR; /** @@ -33,7 +33,9 @@ contract OptimismValidator is TypeAndVersionInterface, AggregatorValidatorInterf * @param gasLimit the gasLimit to use for sending a message from L1 to L2 */ constructor(address l1CrossDomainMessengerAddress, address l2UptimeFeedAddr, uint32 gasLimit) { + // solhint-disable-next-line custom-errors require(l1CrossDomainMessengerAddress != address(0), "Invalid xDomain Messenger address"); + // solhint-disable-next-line custom-errors require(l2UptimeFeedAddr != address(0), "Invalid OptimismSequencerUptimeFeed contract address"); L1_CROSS_DOMAIN_MESSENGER_ADDRESS = l1CrossDomainMessengerAddress; L2_UPTIME_FEED_ADDR = l2UptimeFeedAddr; @@ -73,12 +75,11 @@ contract OptimismValidator is TypeAndVersionInterface, AggregatorValidatorInterf /** * @notice validate method sends an xDomain L2 tx to update Uptime Feed contract on L2. * @dev A message is sent using the L1CrossDomainMessenger. This method is accessed controlled. - * @param previousAnswer previous aggregator answer * @param currentAnswer new aggregator answer - value of 1 considers the sequencer offline. */ function validate( uint256 /* previousRoundId */, - int256 previousAnswer, + int256 /* previousAnswer */, uint256 /* currentRoundId */, int256 currentAnswer ) external override checkAccess returns (bool) { diff --git a/contracts/src/v0.8/tests/ChainlinkClientTestHelper.sol b/contracts/src/v0.8/tests/ChainlinkClientTestHelper.sol index 38b5817d05b..a344138a17d 100644 --- a/contracts/src/v0.8/tests/ChainlinkClientTestHelper.sol +++ b/contracts/src/v0.8/tests/ChainlinkClientTestHelper.sol @@ -5,21 +5,21 @@ import "../ChainlinkClient.sol"; contract ChainlinkClientTestHelper is ChainlinkClient { constructor(address _link, address _oracle) { - setChainlinkToken(_link); - setChainlinkOracle(_oracle); + _setChainlinkToken(_link); + _setChainlinkOracle(_oracle); } event Request(bytes32 id, address callbackAddress, bytes4 callbackfunctionSelector, bytes data); event LinkAmount(uint256 amount); function publicNewRequest(bytes32 _id, address _address, bytes memory _fulfillmentSignature) public { - Chainlink.Request memory req = buildChainlinkRequest(_id, _address, bytes4(keccak256(_fulfillmentSignature))); + Chainlink.Request memory req = _buildChainlinkRequest(_id, _address, bytes4(keccak256(_fulfillmentSignature))); emit Request(req.id, req.callbackAddress, req.callbackFunctionId, req.buf.buf); } function publicRequest(bytes32 _id, address _address, bytes memory _fulfillmentSignature, uint256 _wei) public { - Chainlink.Request memory req = buildChainlinkRequest(_id, _address, bytes4(keccak256(_fulfillmentSignature))); - sendChainlinkRequest(req, _wei); + Chainlink.Request memory req = _buildChainlinkRequest(_id, _address, bytes4(keccak256(_fulfillmentSignature))); + _sendChainlinkRequest(req, _wei); } function publicRequestRunTo( @@ -29,13 +29,13 @@ contract ChainlinkClientTestHelper is ChainlinkClient { bytes memory _fulfillmentSignature, uint256 _wei ) public { - Chainlink.Request memory run = buildChainlinkRequest(_id, _address, bytes4(keccak256(_fulfillmentSignature))); - sendChainlinkRequestTo(_oracle, run, _wei); + Chainlink.Request memory run = _buildChainlinkRequest(_id, _address, bytes4(keccak256(_fulfillmentSignature))); + _sendChainlinkRequestTo(_oracle, run, _wei); } function publicRequestOracleData(bytes32 _id, bytes memory _fulfillmentSignature, uint256 _wei) public { - Chainlink.Request memory req = buildOperatorRequest(_id, bytes4(keccak256(_fulfillmentSignature))); - sendOperatorRequest(req, _wei); + Chainlink.Request memory req = _buildOperatorRequest(_id, bytes4(keccak256(_fulfillmentSignature))); + _sendOperatorRequest(req, _wei); } function publicRequestOracleDataFrom( @@ -44,8 +44,8 @@ contract ChainlinkClientTestHelper is ChainlinkClient { bytes memory _fulfillmentSignature, uint256 _wei ) public { - Chainlink.Request memory run = buildOperatorRequest(_id, bytes4(keccak256(_fulfillmentSignature))); - sendOperatorRequestTo(_oracle, run, _wei); + Chainlink.Request memory run = _buildOperatorRequest(_id, bytes4(keccak256(_fulfillmentSignature))); + _sendOperatorRequestTo(_oracle, run, _wei); } function publicCancelRequest( @@ -54,11 +54,11 @@ contract ChainlinkClientTestHelper is ChainlinkClient { bytes4 _callbackFunctionId, uint256 _expiration ) public { - cancelChainlinkRequest(_requestId, _payment, _callbackFunctionId, _expiration); + _cancelChainlinkRequest(_requestId, _payment, _callbackFunctionId, _expiration); } function publicChainlinkToken() public view returns (address) { - return chainlinkTokenAddress(); + return _chainlinkTokenAddress(); } function publicFulfillChainlinkRequest(bytes32 _requestId, bytes32) public { @@ -66,7 +66,7 @@ contract ChainlinkClientTestHelper is ChainlinkClient { } function fulfillRequest(bytes32 _requestId, bytes32) public { - validateChainlinkCallback(_requestId); + _validateChainlinkCallback(_requestId); } function publicLINK(uint256 _amount) public { @@ -74,10 +74,10 @@ contract ChainlinkClientTestHelper is ChainlinkClient { } function publicOracleAddress() public view returns (address) { - return chainlinkOracleAddress(); + return _chainlinkOracleAddress(); } function publicAddExternalRequest(address _oracle, bytes32 _requestId) public { - addChainlinkExternalRequest(_oracle, _requestId); + _addChainlinkExternalRequest(_oracle, _requestId); } } diff --git a/contracts/src/v0.8/tests/ChainlinkTestHelper.sol b/contracts/src/v0.8/tests/ChainlinkTestHelper.sol index 1ca38f3038f..d42f30c374d 100644 --- a/contracts/src/v0.8/tests/ChainlinkTestHelper.sol +++ b/contracts/src/v0.8/tests/ChainlinkTestHelper.sol @@ -19,31 +19,31 @@ contract ChainlinkTestHelper { function setBuffer(bytes memory data) public { Chainlink.Request memory r2 = req; - r2.setBuffer(data); + r2._setBuffer(data); req = r2; } function add(string memory _key, string memory _value) public { Chainlink.Request memory r2 = req; - r2.add(_key, _value); + r2._add(_key, _value); req = r2; } function addBytes(string memory _key, bytes memory _value) public { Chainlink.Request memory r2 = req; - r2.addBytes(_key, _value); + r2._addBytes(_key, _value); req = r2; } function addInt(string memory _key, int256 _value) public { Chainlink.Request memory r2 = req; - r2.addInt(_key, _value); + r2._addInt(_key, _value); req = r2; } function addUint(string memory _key, uint256 _value) public { Chainlink.Request memory r2 = req; - r2.addUint(_key, _value); + r2._addUint(_key, _value); req = r2; } @@ -51,7 +51,7 @@ contract ChainlinkTestHelper { // string[] memory can be invoked from truffle tests. function addStringArray(string memory _key, string[] memory _values) public { Chainlink.Request memory r2 = req; - r2.addStringArray(_key, _values); + r2._addStringArray(_key, _values); req = r2; } } diff --git a/contracts/src/v0.8/vrf/BatchBlockhashStore.sol b/contracts/src/v0.8/vrf/BatchBlockhashStore.sol index bdd906897fa..54054344fe7 100644 --- a/contracts/src/v0.8/vrf/BatchBlockhashStore.sol +++ b/contracts/src/v0.8/vrf/BatchBlockhashStore.sol @@ -76,7 +76,8 @@ contract BatchBlockhashStore { // solhint-disable-next-line chainlink-solidity/prefix-private-functions-with-underscore function storeableBlock(uint256 blockNumber) private view returns (bool) { // handle edge case on simulated chains which possibly have < 256 blocks total. - return ChainSpecificUtil.getBlockNumber() <= 256 ? true : blockNumber >= (ChainSpecificUtil.getBlockNumber() - 256); + return + ChainSpecificUtil._getBlockNumber() <= 256 ? true : blockNumber >= (ChainSpecificUtil._getBlockNumber() - 256); } } diff --git a/contracts/src/v0.8/KeepersVRFConsumer.sol b/contracts/src/v0.8/vrf/KeepersVRFConsumer.sol similarity index 88% rename from contracts/src/v0.8/KeepersVRFConsumer.sol rename to contracts/src/v0.8/vrf/KeepersVRFConsumer.sol index 21fd26290a4..438696c7f4d 100644 --- a/contracts/src/v0.8/KeepersVRFConsumer.sol +++ b/contracts/src/v0.8/vrf/KeepersVRFConsumer.sol @@ -1,9 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "./automation/KeeperCompatible.sol"; -import "./vrf/VRFConsumerBaseV2.sol"; -import "./interfaces/VRFCoordinatorV2Interface.sol"; +import {AutomationCompatibleInterface as KeeperCompatibleInterface} from "../automation/interfaces/AutomationCompatibleInterface.sol"; +import {VRFConsumerBaseV2} from "./VRFConsumerBaseV2.sol"; +import {VRFCoordinatorV2Interface} from "./interfaces/VRFCoordinatorV2Interface.sol"; + +// solhint-disable chainlink-solidity/prefix-immutable-variables-with-i +// solhint-disable chainlink-solidity/prefix-internal-functions-with-underscore /** * @title KeepersVRFConsumer @@ -85,6 +88,7 @@ contract KeepersVRFConsumer is KeeperCompatibleInterface, VRFConsumerBaseV2 { function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override { // Check that the request exists. If not, revert. RequestRecord memory record = s_requests[requestId]; + // solhint-disable-next-line custom-errors require(record.requestId == requestId, "request ID not found in map"); // Update the randomness in the record, and increment the response counter. diff --git a/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol b/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol index 92cb0cdb324..994e3af7dcb 100644 --- a/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol +++ b/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.4; import {LinkTokenInterface} from "../shared/interfaces/LinkTokenInterface.sol"; -import {BlockhashStoreInterface} from "../interfaces/BlockhashStoreInterface.sol"; +import {BlockhashStoreInterface} from "./interfaces/BlockhashStoreInterface.sol"; import {AggregatorV3Interface} from "../interfaces/AggregatorV3Interface.sol"; -import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFCoordinatorV2Interface} from "./interfaces/VRFCoordinatorV2Interface.sol"; import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; import {IERC677Receiver} from "../shared/interfaces/IERC677Receiver.sol"; import {VRF} from "./VRF.sol"; @@ -390,7 +390,7 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo (uint256 requestId, uint256 preSeed) = computeRequestId(keyHash, msg.sender, subId, nonce); s_requestCommitments[requestId] = keccak256( - abi.encode(requestId, ChainSpecificUtil.getBlockNumber(), subId, callbackGasLimit, numWords, msg.sender) + abi.encode(requestId, ChainSpecificUtil._getBlockNumber(), subId, callbackGasLimit, numWords, msg.sender) ); emit RandomWordsRequested( keyHash, @@ -483,7 +483,7 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo revert IncorrectCommitment(); } - bytes32 blockHash = ChainSpecificUtil.getBlockhash(rc.blockNum); + bytes32 blockHash = ChainSpecificUtil._getBlockhash(rc.blockNum); if (blockHash == bytes32(0)) { blockHash = BLOCKHASH_STORE.getBlockhash(rc.blockNum); if (blockHash == bytes32(0)) { @@ -587,7 +587,7 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo revert InvalidLinkWeiPrice(weiPerUnitLink); } // Will return non-zero on chains that have this enabled - uint256 l1CostWei = ChainSpecificUtil.getCurrentTxL1GasFees(msg.data); + uint256 l1CostWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data); // (1e18 juels/link) ((wei/gas * gas) + l1wei) / (wei/link) = juels uint256 paymentNoFee = (1e18 * (weiPerUnitGas * (gasAfterPaymentCalculation + startGas - gasleft()) + l1CostWei)) / uint256(weiPerUnitLink); diff --git a/contracts/src/v0.8/vrf/VRFV2Wrapper.sol b/contracts/src/v0.8/vrf/VRFV2Wrapper.sol index 3573b972276..a041c62c3fe 100644 --- a/contracts/src/v0.8/vrf/VRFV2Wrapper.sol +++ b/contracts/src/v0.8/vrf/VRFV2Wrapper.sol @@ -7,8 +7,8 @@ import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol import {VRFConsumerBaseV2} from "./VRFConsumerBaseV2.sol"; import {LinkTokenInterface} from "../shared/interfaces/LinkTokenInterface.sol"; import {AggregatorV3Interface} from "../interfaces/AggregatorV3Interface.sol"; -import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; -import {VRFV2WrapperInterface} from "../interfaces/VRFV2WrapperInterface.sol"; +import {VRFCoordinatorV2Interface} from "./interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFV2WrapperInterface} from "./interfaces/VRFV2WrapperInterface.sol"; import {VRFV2WrapperConsumerBase} from "./VRFV2WrapperConsumerBase.sol"; import {ChainSpecificUtil} from "../ChainSpecificUtil.sol"; @@ -253,7 +253,7 @@ contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBas // transaction, if we are on an L2. uint256 costWei = (_requestGasPrice * (_gas + s_wrapperGasOverhead + s_coordinatorGasOverhead) + - ChainSpecificUtil.getL1CalldataGasCost(s_fulfillmentTxSizeBytes)); + ChainSpecificUtil._getL1CalldataGasCost(s_fulfillmentTxSizeBytes)); // (1e18 juels/link) * ((wei/gas * (gas)) + l1wei) / (wei/link) == 1e18 juels * wei/link / (wei/link) == 1e18 juels * wei/link * link/wei == juels // baseFee is the base fee denominated in juels (link) uint256 baseFee = (1e18 * costWei) / uint256(_weiPerUnitLink); diff --git a/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol b/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol index a9c8e5568a9..2876b19dd7b 100644 --- a/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol +++ b/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import {LinkTokenInterface} from "../shared/interfaces/LinkTokenInterface.sol"; -import {VRFV2WrapperInterface} from "../interfaces/VRFV2WrapperInterface.sol"; +import {VRFV2WrapperInterface} from "./interfaces/VRFV2WrapperInterface.sol"; /** ******************************************************************************* * @notice Interface for contracts using VRF randomness through the VRF V2 wrapper diff --git a/contracts/src/v0.8/dev/vrf/BatchVRFCoordinatorV2Plus.sol b/contracts/src/v0.8/vrf/dev/BatchVRFCoordinatorV2Plus.sol similarity index 98% rename from contracts/src/v0.8/dev/vrf/BatchVRFCoordinatorV2Plus.sol rename to contracts/src/v0.8/vrf/dev/BatchVRFCoordinatorV2Plus.sol index 9247cc21dd5..34b5ff6f189 100644 --- a/contracts/src/v0.8/dev/vrf/BatchVRFCoordinatorV2Plus.sol +++ b/contracts/src/v0.8/vrf/dev/BatchVRFCoordinatorV2Plus.sol @@ -2,7 +2,7 @@ // solhint-disable-next-line one-contract-per-file pragma solidity 0.8.6; -import {VRFTypes} from "../../vrf/VRFTypes.sol"; +import {VRFTypes} from "../VRFTypes.sol"; /** * @title BatchVRFCoordinatorV2Plus diff --git a/contracts/src/v0.8/dev/vrf/BlockhashStore.sol b/contracts/src/v0.8/vrf/dev/BlockhashStore.sol similarity index 96% rename from contracts/src/v0.8/dev/vrf/BlockhashStore.sol rename to contracts/src/v0.8/vrf/dev/BlockhashStore.sol index ad445595ff8..b6389c9b15a 100644 --- a/contracts/src/v0.8/dev/vrf/BlockhashStore.sol +++ b/contracts/src/v0.8/vrf/dev/BlockhashStore.sol @@ -21,7 +21,7 @@ contract BlockhashStore { * @param n the number of the block whose blockhash should be stored */ function store(uint256 n) public { - bytes32 h = ChainSpecificUtil.getBlockhash(uint64(n)); + bytes32 h = ChainSpecificUtil._getBlockhash(uint64(n)); // solhint-disable-next-line custom-errors require(h != 0x0, "blockhash(n) failed"); s_blockhashes[n] = h; @@ -31,7 +31,7 @@ contract BlockhashStore { * @notice stores blockhash of the earliest block still available through BLOCKHASH. */ function storeEarliest() external { - store(ChainSpecificUtil.getBlockNumber() - 256); + store(ChainSpecificUtil._getBlockNumber() - 256); } /** diff --git a/contracts/src/v0.8/dev/vrf/SubscriptionAPI.sol b/contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol similarity index 99% rename from contracts/src/v0.8/dev/vrf/SubscriptionAPI.sol rename to contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol index d79b6daf844..478ff4cce4a 100644 --- a/contracts/src/v0.8/dev/vrf/SubscriptionAPI.sol +++ b/contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol @@ -6,7 +6,7 @@ import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; import {AggregatorV3Interface} from "../../interfaces/AggregatorV3Interface.sol"; import {IERC677Receiver} from "../../shared/interfaces/IERC677Receiver.sol"; -import {IVRFSubscriptionV2Plus} from "../interfaces/IVRFSubscriptionV2Plus.sol"; +import {IVRFSubscriptionV2Plus} from "./interfaces/IVRFSubscriptionV2Plus.sol"; abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscriptionV2Plus { using EnumerableSet for EnumerableSet.UintSet; diff --git a/contracts/src/v0.8/dev/vrf/TrustedBlockhashStore.sol b/contracts/src/v0.8/vrf/dev/TrustedBlockhashStore.sol similarity index 95% rename from contracts/src/v0.8/dev/vrf/TrustedBlockhashStore.sol rename to contracts/src/v0.8/vrf/dev/TrustedBlockhashStore.sol index d084ea5c8eb..b1a53b57163 100644 --- a/contracts/src/v0.8/dev/vrf/TrustedBlockhashStore.sol +++ b/contracts/src/v0.8/vrf/dev/TrustedBlockhashStore.sol @@ -46,7 +46,7 @@ contract TrustedBlockhashStore is ConfirmedOwner, BlockhashStore { uint256 recentBlockNumber, bytes32 recentBlockhash ) external { - bytes32 onChainHash = ChainSpecificUtil.getBlockhash(uint64(recentBlockNumber)); + bytes32 onChainHash = ChainSpecificUtil._getBlockhash(uint64(recentBlockNumber)); if (onChainHash != recentBlockhash) { revert InvalidRecentBlockhash(); } diff --git a/contracts/src/v0.8/dev/vrf/VRFConsumerBaseV2Plus.sol b/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol similarity index 97% rename from contracts/src/v0.8/dev/vrf/VRFConsumerBaseV2Plus.sol rename to contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol index c256630f7c6..fdfbcebaaa2 100644 --- a/contracts/src/v0.8/dev/vrf/VRFConsumerBaseV2Plus.sol +++ b/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -import {IVRFCoordinatorV2Plus} from "../interfaces/IVRFCoordinatorV2Plus.sol"; -import {IVRFMigratableConsumerV2Plus} from "../interfaces/IVRFMigratableConsumerV2Plus.sol"; +import {IVRFCoordinatorV2Plus} from "./interfaces/IVRFCoordinatorV2Plus.sol"; +import {IVRFMigratableConsumerV2Plus} from "./interfaces/IVRFMigratableConsumerV2Plus.sol"; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; /** **************************************************************************** diff --git a/contracts/src/v0.8/dev/VRFConsumerBaseV2Upgradeable.sol b/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Upgradeable.sol similarity index 100% rename from contracts/src/v0.8/dev/VRFConsumerBaseV2Upgradeable.sol rename to contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Upgradeable.sol diff --git a/contracts/src/v0.8/dev/vrf/VRFCoordinatorV2_5.sol b/contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol similarity index 98% rename from contracts/src/v0.8/dev/vrf/VRFCoordinatorV2_5.sol rename to contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol index d69fa38c096..31a555f8ac7 100644 --- a/contracts/src/v0.8/dev/vrf/VRFCoordinatorV2_5.sol +++ b/contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol @@ -1,15 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -import {BlockhashStoreInterface} from "../../interfaces/BlockhashStoreInterface.sol"; +import {BlockhashStoreInterface} from "../interfaces/BlockhashStoreInterface.sol"; import {VRF} from "../../vrf/VRF.sol"; import {VRFConsumerBaseV2Plus, IVRFMigratableConsumerV2Plus} from "./VRFConsumerBaseV2Plus.sol"; import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; import {SubscriptionAPI} from "./SubscriptionAPI.sol"; import {VRFV2PlusClient} from "./libraries/VRFV2PlusClient.sol"; -import {IVRFCoordinatorV2PlusMigration} from "../interfaces/IVRFCoordinatorV2PlusMigration.sol"; +import {IVRFCoordinatorV2PlusMigration} from "./interfaces/IVRFCoordinatorV2PlusMigration.sol"; // solhint-disable-next-line no-unused-import -import {IVRFCoordinatorV2Plus, IVRFSubscriptionV2Plus} from "../interfaces/IVRFCoordinatorV2Plus.sol"; +import {IVRFCoordinatorV2Plus, IVRFSubscriptionV2Plus} from "./interfaces/IVRFCoordinatorV2Plus.sol"; // solhint-disable-next-line contract-name-camelcase contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { @@ -276,7 +276,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { s_requestCommitments[requestId] = keccak256( abi.encode( requestId, - ChainSpecificUtil.getBlockNumber(), + ChainSpecificUtil._getBlockNumber(), req.subId, req.callbackGasLimit, req.numWords, @@ -374,7 +374,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { revert IncorrectCommitment(); } - bytes32 blockHash = ChainSpecificUtil.getBlockhash(rc.blockNum); + bytes32 blockHash = ChainSpecificUtil._getBlockhash(rc.blockNum); if (blockHash == bytes32(0)) { blockHash = BLOCKHASH_STORE.getBlockhash(rc.blockNum); if (blockHash == bytes32(0)) { @@ -488,7 +488,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { uint256 weiPerUnitGas ) internal view returns (uint96) { // Will return non-zero on chains that have this enabled - uint256 l1CostWei = ChainSpecificUtil.getCurrentTxL1GasFees(msg.data); + uint256 l1CostWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data); // calculate the payment without the premium uint256 baseFeeWei = weiPerUnitGas * (gasAfterPaymentCalculation + startGas - gasleft()); // calculate the flat fee in wei @@ -511,7 +511,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { revert InvalidLinkWeiPrice(weiPerUnitLink); } // Will return non-zero on chains that have this enabled - uint256 l1CostWei = ChainSpecificUtil.getCurrentTxL1GasFees(msg.data); + uint256 l1CostWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data); // (1e18 juels/link) ((wei/gas * gas) + l1wei) / (wei/link) = juels uint256 paymentNoFee = (1e18 * (weiPerUnitGas * (gasAfterPaymentCalculation + startGas - gasleft()) + l1CostWei)) / uint256(weiPerUnitLink); diff --git a/contracts/src/v0.8/dev/VRFSubscriptionBalanceMonitor.sol b/contracts/src/v0.8/vrf/dev/VRFSubscriptionBalanceMonitor.sol similarity index 97% rename from contracts/src/v0.8/dev/VRFSubscriptionBalanceMonitor.sol rename to contracts/src/v0.8/vrf/dev/VRFSubscriptionBalanceMonitor.sol index 958ecdc1bad..2dd44c8b1a8 100644 --- a/contracts/src/v0.8/dev/VRFSubscriptionBalanceMonitor.sol +++ b/contracts/src/v0.8/vrf/dev/VRFSubscriptionBalanceMonitor.sol @@ -2,10 +2,10 @@ pragma solidity 0.8.6; -import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol"; -import {AutomationCompatibleInterface as KeeperCompatibleInterface} from "../automation/interfaces/AutomationCompatibleInterface.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {AutomationCompatibleInterface as KeeperCompatibleInterface} from "../../automation/interfaces/AutomationCompatibleInterface.sol"; import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; -import {LinkTokenInterface} from "../shared/interfaces/LinkTokenInterface.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol"; /** diff --git a/contracts/src/v0.8/dev/vrf/VRFV2PlusWrapper.sol b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol similarity index 98% rename from contracts/src/v0.8/dev/vrf/VRFV2PlusWrapper.sol rename to contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol index 29573aa2363..12557f73d2c 100644 --- a/contracts/src/v0.8/dev/vrf/VRFV2PlusWrapper.sol +++ b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol @@ -3,12 +3,12 @@ pragma solidity ^0.8.6; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol"; -import {IVRFV2PlusMigrate} from "../interfaces/IVRFV2PlusMigrate.sol"; +import {IVRFV2PlusMigrate} from "./interfaces/IVRFV2PlusMigrate.sol"; import {VRFConsumerBaseV2Plus} from "./VRFConsumerBaseV2Plus.sol"; import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; import {AggregatorV3Interface} from "../../interfaces/AggregatorV3Interface.sol"; import {VRFV2PlusClient} from "./libraries/VRFV2PlusClient.sol"; -import {IVRFV2PlusWrapper} from "../interfaces/IVRFV2PlusWrapper.sol"; +import {IVRFV2PlusWrapper} from "./interfaces/IVRFV2PlusWrapper.sol"; import {VRFV2PlusWrapperConsumerBase} from "./VRFV2PlusWrapperConsumerBase.sol"; import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; @@ -317,7 +317,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume // transaction, if we are on an L2. uint256 costWei = (_requestGasPrice * (_gas + s_wrapperGasOverhead + s_coordinatorGasOverhead) + - ChainSpecificUtil.getL1CalldataGasCost(s_fulfillmentTxSizeBytes)); + ChainSpecificUtil._getL1CalldataGasCost(s_fulfillmentTxSizeBytes)); // ((wei/gas * (gas)) + l1wei) // baseFee is the base fee denominated in wei uint256 baseFee = costWei; @@ -340,7 +340,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume // transaction, if we are on an L2. uint256 costWei = (_requestGasPrice * (_gas + s_wrapperGasOverhead + s_coordinatorGasOverhead) + - ChainSpecificUtil.getL1CalldataGasCost(s_fulfillmentTxSizeBytes)); + ChainSpecificUtil._getL1CalldataGasCost(s_fulfillmentTxSizeBytes)); // (1e18 juels/link) * ((wei/gas * (gas)) + l1wei) / (wei/link) == 1e18 juels * wei/link / (wei/link) == 1e18 juels * wei/link * link/wei == juels // baseFee is the base fee denominated in juels (link) uint256 baseFee = (1e18 * costWei) / uint256(_weiPerUnitLink); diff --git a/contracts/src/v0.8/dev/vrf/VRFV2PlusWrapperConsumerBase.sol b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol similarity index 98% rename from contracts/src/v0.8/dev/vrf/VRFV2PlusWrapperConsumerBase.sol rename to contracts/src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol index e800753af2b..dd450c9f94a 100644 --- a/contracts/src/v0.8/dev/vrf/VRFV2PlusWrapperConsumerBase.sol +++ b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; -import {IVRFV2PlusWrapper} from "../interfaces/IVRFV2PlusWrapper.sol"; +import {IVRFV2PlusWrapper} from "./interfaces/IVRFV2PlusWrapper.sol"; /** * diff --git a/contracts/src/v0.8/dev/interfaces/IVRFCoordinatorV2Plus.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2Plus.sol similarity index 96% rename from contracts/src/v0.8/dev/interfaces/IVRFCoordinatorV2Plus.sol rename to contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2Plus.sol index 20c60b593da..846da0b1edc 100644 --- a/contracts/src/v0.8/dev/interfaces/IVRFCoordinatorV2Plus.sol +++ b/contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2Plus.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {VRFV2PlusClient} from "../vrf/libraries/VRFV2PlusClient.sol"; +import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; import {IVRFSubscriptionV2Plus} from "./IVRFSubscriptionV2Plus.sol"; // Interface that enables consumers of VRFCoordinatorV2Plus to be future-proof for upgrades diff --git a/contracts/src/v0.8/dev/interfaces/IVRFCoordinatorV2PlusInternal.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2PlusInternal.sol similarity index 100% rename from contracts/src/v0.8/dev/interfaces/IVRFCoordinatorV2PlusInternal.sol rename to contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2PlusInternal.sol diff --git a/contracts/src/v0.8/dev/interfaces/IVRFCoordinatorV2PlusMigration.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2PlusMigration.sol similarity index 100% rename from contracts/src/v0.8/dev/interfaces/IVRFCoordinatorV2PlusMigration.sol rename to contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2PlusMigration.sol diff --git a/contracts/src/v0.8/dev/interfaces/IVRFMigratableConsumerV2Plus.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFMigratableConsumerV2Plus.sol similarity index 100% rename from contracts/src/v0.8/dev/interfaces/IVRFMigratableConsumerV2Plus.sol rename to contracts/src/v0.8/vrf/dev/interfaces/IVRFMigratableConsumerV2Plus.sol diff --git a/contracts/src/v0.8/dev/interfaces/IVRFSubscriptionV2Plus.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFSubscriptionV2Plus.sol similarity index 100% rename from contracts/src/v0.8/dev/interfaces/IVRFSubscriptionV2Plus.sol rename to contracts/src/v0.8/vrf/dev/interfaces/IVRFSubscriptionV2Plus.sol diff --git a/contracts/src/v0.8/dev/interfaces/IVRFV2PlusMigrate.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusMigrate.sol similarity index 100% rename from contracts/src/v0.8/dev/interfaces/IVRFV2PlusMigrate.sol rename to contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusMigrate.sol diff --git a/contracts/src/v0.8/dev/interfaces/IVRFV2PlusWrapper.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusWrapper.sol similarity index 100% rename from contracts/src/v0.8/dev/interfaces/IVRFV2PlusWrapper.sol rename to contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusWrapper.sol diff --git a/contracts/src/v0.8/dev/vrf/libraries/VRFV2PlusClient.sol b/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol similarity index 100% rename from contracts/src/v0.8/dev/vrf/libraries/VRFV2PlusClient.sol rename to contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2_5.sol b/contracts/src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol similarity index 100% rename from contracts/src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2_5.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol similarity index 94% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol index 1211014cd2f..aeaaf4ba266 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.0; import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; -import {IVRFCoordinatorV2Plus} from "../../interfaces/IVRFCoordinatorV2Plus.sol"; -import {VRFConsumerBaseV2Upgradeable} from "../../VRFConsumerBaseV2Upgradeable.sol"; +import {IVRFCoordinatorV2Plus} from "../interfaces/IVRFCoordinatorV2Plus.sol"; +import {VRFConsumerBaseV2Upgradeable} from "../VRFConsumerBaseV2Upgradeable.sol"; import {Initializable} from "@openzeppelin/contracts-upgradeable-4.7.3/proxy/utils/Initializable.sol"; import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol similarity index 98% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol index 07b55388e10..b6c76e1c713 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol @@ -1,15 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -import {BlockhashStoreInterface} from "../../../interfaces/BlockhashStoreInterface.sol"; +import {BlockhashStoreInterface} from "../../interfaces/BlockhashStoreInterface.sol"; // solhint-disable-next-line no-unused-import -import {IVRFCoordinatorV2Plus, IVRFSubscriptionV2Plus} from "../../interfaces/IVRFCoordinatorV2Plus.sol"; +import {IVRFCoordinatorV2Plus, IVRFSubscriptionV2Plus} from "../interfaces/IVRFCoordinatorV2Plus.sol"; import {VRF} from "../../../vrf/VRF.sol"; import {VRFConsumerBaseV2Plus, IVRFMigratableConsumerV2Plus} from "../VRFConsumerBaseV2Plus.sol"; import {ChainSpecificUtil} from "../../../ChainSpecificUtil.sol"; import {SubscriptionAPI} from "../SubscriptionAPI.sol"; import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; -import {IVRFCoordinatorV2PlusMigration} from "../../interfaces/IVRFCoordinatorV2PlusMigration.sol"; +import {IVRFCoordinatorV2PlusMigration} from "../interfaces/IVRFCoordinatorV2PlusMigration.sol"; import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; contract VRFCoordinatorV2PlusUpgradedVersion is @@ -267,7 +267,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is s_requestCommitments[requestId] = keccak256( abi.encode( requestId, - ChainSpecificUtil.getBlockNumber(), + ChainSpecificUtil._getBlockNumber(), req.subId, req.callbackGasLimit, req.numWords, @@ -365,7 +365,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is revert IncorrectCommitment(); } - bytes32 blockHash = ChainSpecificUtil.getBlockhash(rc.blockNum); + bytes32 blockHash = ChainSpecificUtil._getBlockhash(rc.blockNum); if (blockHash == bytes32(0)) { blockHash = BLOCKHASH_STORE.getBlockhash(rc.blockNum); if (blockHash == bytes32(0)) { @@ -479,7 +479,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is uint256 weiPerUnitGas ) internal view returns (uint96) { // Will return non-zero on chains that have this enabled - uint256 l1CostWei = ChainSpecificUtil.getCurrentTxL1GasFees(msg.data); + uint256 l1CostWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data); // calculate the payment without the premium uint256 baseFeeWei = weiPerUnitGas * (gasAfterPaymentCalculation + startGas - gasleft()); // calculate the flat fee in wei @@ -502,7 +502,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is revert InvalidLinkWeiPrice(weiPerUnitLink); } // Will return non-zero on chains that have this enabled - uint256 l1CostWei = ChainSpecificUtil.getCurrentTxL1GasFees(msg.data); + uint256 l1CostWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data); // (1e18 juels/link) ((wei/gas * gas) + l1wei) / (wei/link) = juels uint256 paymentNoFee = (1e18 * (weiPerUnitGas * (gasAfterPaymentCalculation + startGas - gasleft()) + l1CostWei)) / uint256(weiPerUnitLink); diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFCoordinatorV2Plus_V2Example.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol similarity index 98% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFCoordinatorV2Plus_V2Example.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol index 7306931570a..af49abbf6b5 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFCoordinatorV2Plus_V2Example.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -import {IVRFCoordinatorV2PlusMigration} from "../../interfaces/IVRFCoordinatorV2PlusMigration.sol"; +import {IVRFCoordinatorV2PlusMigration} from "../interfaces/IVRFCoordinatorV2PlusMigration.sol"; import {VRFConsumerBaseV2Plus} from "../VRFConsumerBaseV2Plus.sol"; import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFMaliciousConsumerV2Plus.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFMaliciousConsumerV2Plus.sol similarity index 96% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFMaliciousConsumerV2Plus.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFMaliciousConsumerV2Plus.sol index cc3e465bc0c..7ddbb448ab9 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFMaliciousConsumerV2Plus.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFMaliciousConsumerV2Plus.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; -import {IVRFCoordinatorV2Plus} from "../../interfaces/IVRFCoordinatorV2Plus.sol"; +import {IVRFCoordinatorV2Plus} from "../interfaces/IVRFCoordinatorV2Plus.sol"; import {VRFConsumerBaseV2Plus} from "../VRFConsumerBaseV2Plus.sol"; import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusConsumerExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol similarity index 98% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusConsumerExample.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol index 8acc0ce6d0b..6898e101f82 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusConsumerExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; -import {IVRFCoordinatorV2Plus} from "../../interfaces/IVRFCoordinatorV2Plus.sol"; +import {IVRFCoordinatorV2Plus} from "../interfaces/IVRFCoordinatorV2Plus.sol"; import {VRFConsumerBaseV2Plus} from "../VRFConsumerBaseV2Plus.sol"; import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusExternalSubOwnerExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusExternalSubOwnerExample.sol similarity index 96% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusExternalSubOwnerExample.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusExternalSubOwnerExample.sol index 384a5890018..4fe7381b5f2 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusExternalSubOwnerExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusExternalSubOwnerExample.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; -import {IVRFCoordinatorV2Plus} from "../../interfaces/IVRFCoordinatorV2Plus.sol"; +import {IVRFCoordinatorV2Plus} from "../interfaces/IVRFCoordinatorV2Plus.sol"; import {VRFConsumerBaseV2Plus} from "../VRFConsumerBaseV2Plus.sol"; import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusLoadTestWithMetrics.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol similarity index 96% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusLoadTestWithMetrics.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol index ad09f88fd2f..c1330d32237 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusLoadTestWithMetrics.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol @@ -34,7 +34,7 @@ contract VRFV2PlusLoadTestWithMetrics is VRFConsumerBaseV2Plus { // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { - uint256 fulfilmentBlockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 fulfilmentBlockNumber = ChainSpecificUtil._getBlockNumber(); uint256 requestDelay = fulfilmentBlockNumber - requestHeights[_requestId]; uint256 requestDelayInMillions = requestDelay * 1_000_000; @@ -76,7 +76,7 @@ contract VRFV2PlusLoadTestWithMetrics is VRFConsumerBaseV2Plus { uint256 requestId = s_vrfCoordinator.requestRandomWords(req); s_lastRequestId = requestId; - uint256 requestBlockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 requestBlockNumber = ChainSpecificUtil._getBlockNumber(); s_requests[requestId] = RequestStatus({ randomWords: new uint256[](0), fulfilled: false, diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusMaliciousMigrator.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusMaliciousMigrator.sol similarity index 82% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusMaliciousMigrator.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusMaliciousMigrator.sol index 2be0024ae71..16797bb9390 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusMaliciousMigrator.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusMaliciousMigrator.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; -import {IVRFMigratableConsumerV2Plus} from "../../interfaces/IVRFMigratableConsumerV2Plus.sol"; -import {IVRFCoordinatorV2Plus} from "../../interfaces/IVRFCoordinatorV2Plus.sol"; +import {IVRFMigratableConsumerV2Plus} from "../interfaces/IVRFMigratableConsumerV2Plus.sol"; +import {IVRFCoordinatorV2Plus} from "../interfaces/IVRFCoordinatorV2Plus.sol"; import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; contract VRFV2PlusMaliciousMigrator is IVRFMigratableConsumerV2Plus { diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusRevertingExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusRevertingExample.sol similarity index 97% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusRevertingExample.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusRevertingExample.sol index 170ff9dd6e9..10c79a1af5c 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusRevertingExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusRevertingExample.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; -import {IVRFCoordinatorV2Plus} from "../../interfaces/IVRFCoordinatorV2Plus.sol"; +import {IVRFCoordinatorV2Plus} from "../interfaces/IVRFCoordinatorV2Plus.sol"; import {VRFConsumerBaseV2Plus} from "../VRFConsumerBaseV2Plus.sol"; import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusSingleConsumerExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol similarity index 98% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusSingleConsumerExample.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol index b190ebc8715..5d16a9674d2 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusSingleConsumerExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.0; import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; -import {IVRFCoordinatorV2Plus} from "../../interfaces/IVRFCoordinatorV2Plus.sol"; +import {IVRFCoordinatorV2Plus} from "../interfaces/IVRFCoordinatorV2Plus.sol"; import {VRFConsumerBaseV2Plus} from "../VRFConsumerBaseV2Plus.sol"; import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusWrapperConsumerExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol similarity index 100% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusWrapperConsumerExample.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol similarity index 95% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol index 7b6df2c563e..ae1d424c045 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol @@ -5,7 +5,7 @@ import {VRFV2PlusWrapperConsumerBase} from "../VRFV2PlusWrapperConsumerBase.sol" import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; import {ChainSpecificUtil} from "../../../ChainSpecificUtil.sol"; import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; -import {IVRFV2PlusWrapper} from "../../interfaces/IVRFV2PlusWrapper.sol"; +import {IVRFV2PlusWrapper} from "../interfaces/IVRFV2PlusWrapper.sol"; contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, ConfirmedOwner { uint256 public s_responseCount; @@ -49,7 +49,7 @@ contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, Confi uint256 requestId = requestRandomness(_callbackGasLimit, _requestConfirmations, _numWords, extraArgs); s_lastRequestId = requestId; - uint256 requestBlockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 requestBlockNumber = ChainSpecificUtil._getBlockNumber(); uint256 paid = VRF_V2_PLUS_WRAPPER.calculateRequestPrice(_callbackGasLimit); s_requests[requestId] = RequestStatus({ paid: paid, @@ -78,7 +78,7 @@ contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, Confi uint256 requestId = requestRandomnessPayInNative(_callbackGasLimit, _requestConfirmations, _numWords, extraArgs); s_lastRequestId = requestId; - uint256 requestBlockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 requestBlockNumber = ChainSpecificUtil._getBlockNumber(); uint256 paid = VRF_V2_PLUS_WRAPPER.calculateRequestPriceNative(_callbackGasLimit); s_requests[requestId] = RequestStatus({ paid: paid, @@ -100,7 +100,7 @@ contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, Confi 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 fulfilmentBlockNumber = ChainSpecificUtil._getBlockNumber(); uint256 requestDelay = fulfilmentBlockNumber - requestHeights[_requestId]; uint256 requestDelayInMillions = requestDelay * 1_000_000; diff --git a/contracts/src/v0.8/interfaces/BlockhashStoreInterface.sol b/contracts/src/v0.8/vrf/interfaces/BlockhashStoreInterface.sol similarity index 100% rename from contracts/src/v0.8/interfaces/BlockhashStoreInterface.sol rename to contracts/src/v0.8/vrf/interfaces/BlockhashStoreInterface.sol diff --git a/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol b/contracts/src/v0.8/vrf/interfaces/VRFCoordinatorV2Interface.sol similarity index 100% rename from contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol rename to contracts/src/v0.8/vrf/interfaces/VRFCoordinatorV2Interface.sol diff --git a/contracts/src/v0.8/interfaces/VRFV2WrapperInterface.sol b/contracts/src/v0.8/vrf/interfaces/VRFV2WrapperInterface.sol similarity index 100% rename from contracts/src/v0.8/interfaces/VRFV2WrapperInterface.sol rename to contracts/src/v0.8/vrf/interfaces/VRFV2WrapperInterface.sol diff --git a/contracts/src/v0.8/mocks/VRFCoordinatorMock.sol b/contracts/src/v0.8/vrf/mocks/VRFCoordinatorMock.sol similarity index 77% rename from contracts/src/v0.8/mocks/VRFCoordinatorMock.sol rename to contracts/src/v0.8/vrf/mocks/VRFCoordinatorMock.sol index 7e179d5a445..6695e79b052 100644 --- a/contracts/src/v0.8/mocks/VRFCoordinatorMock.sol +++ b/contracts/src/v0.8/vrf/mocks/VRFCoordinatorMock.sol @@ -1,15 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../shared/interfaces/LinkTokenInterface.sol"; -import "../vrf/VRFConsumerBase.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFConsumerBase} from "../../vrf/VRFConsumerBase.sol"; + +// solhint-disable custom-errors contract VRFCoordinatorMock { LinkTokenInterface public LINK; event RandomnessRequest(address indexed sender, bytes32 indexed keyHash, uint256 indexed seed, uint256 fee); - constructor(address linkAddress) public { + constructor(address linkAddress) { LINK = LinkTokenInterface(linkAddress); } @@ -23,6 +25,7 @@ contract VRFCoordinatorMock { bytes memory resp = abi.encodeWithSelector(v.rawFulfillRandomness.selector, requestId, randomness); uint256 b = 206000; require(gasleft() >= b, "not enough gas for consumer"); + // solhint-disable-next-line avoid-low-level-calls, no-unused-vars (bool success, ) = consumerContract.call(resp); } diff --git a/contracts/src/v0.8/mocks/VRFCoordinatorV2Mock.sol b/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol similarity index 92% rename from contracts/src/v0.8/mocks/VRFCoordinatorV2Mock.sol rename to contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol index a263a3be500..b605815f7eb 100644 --- a/contracts/src/v0.8/mocks/VRFCoordinatorV2Mock.sol +++ b/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol @@ -2,10 +2,13 @@ // A mock for testing code that relies on VRFCoordinatorV2. pragma solidity ^0.8.4; -import "../shared/interfaces/LinkTokenInterface.sol"; -import "../interfaces/VRFCoordinatorV2Interface.sol"; -import "../vrf/VRFConsumerBaseV2.sol"; -import "../shared/access/ConfirmedOwner.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; + +// solhint-disable chainlink-solidity/prefix-immutable-variables-with-i +// solhint-disable custom-errors +// solhint-disable avoid-low-level-calls contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface, ConfirmedOwner { uint96 public immutable BASE_FEE; @@ -43,22 +46,22 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface, ConfirmedOwner { bool reentrancyLock; } Config private s_config; - uint64 s_currentSubId; - uint256 s_nextRequestId = 1; - uint256 s_nextPreSeed = 100; + uint64 internal s_currentSubId; + uint256 internal s_nextRequestId = 1; + uint256 internal s_nextPreSeed = 100; struct Subscription { address owner; uint96 balance; } - mapping(uint64 => Subscription) s_subscriptions; /* subId */ /* subscription */ - mapping(uint64 => address[]) s_consumers; /* subId */ /* consumers */ + mapping(uint64 => Subscription) internal s_subscriptions; /* subId */ /* subscription */ + mapping(uint64 => address[]) internal s_consumers; /* subId */ /* consumers */ struct Request { uint64 subId; uint32 callbackGasLimit; uint32 numWords; } - mapping(uint256 => Request) s_requests; /* requestId */ /* request */ + mapping(uint256 => Request) internal s_requests; /* requestId */ /* request */ constructor(uint96 _baseFee, uint96 _gasPriceLink) ConfirmedOwner(msg.sender) { BASE_FEE = _baseFee; diff --git a/contracts/src/v0.8/vrf/testhelpers/ChainSpecificUtilHelper.sol b/contracts/src/v0.8/vrf/testhelpers/ChainSpecificUtilHelper.sol index 6c22dbf9e4f..a594e02659f 100644 --- a/contracts/src/v0.8/vrf/testhelpers/ChainSpecificUtilHelper.sol +++ b/contracts/src/v0.8/vrf/testhelpers/ChainSpecificUtilHelper.sol @@ -6,18 +6,18 @@ import "../../ChainSpecificUtil.sol"; /// @dev A helper contract that exposes ChainSpecificUtil methods for testing contract ChainSpecificUtilHelper { function getBlockhash(uint64 blockNumber) external view returns (bytes32) { - return ChainSpecificUtil.getBlockhash(blockNumber); + return ChainSpecificUtil._getBlockhash(blockNumber); } function getBlockNumber() external view returns (uint256) { - return ChainSpecificUtil.getBlockNumber(); + return ChainSpecificUtil._getBlockNumber(); } function getCurrentTxL1GasFees(string memory txCallData) external view returns (uint256) { - return ChainSpecificUtil.getCurrentTxL1GasFees(bytes(txCallData)); + return ChainSpecificUtil._getCurrentTxL1GasFees(bytes(txCallData)); } function getL1CalldataGasCost(uint256 calldataSize) external view returns (uint256) { - return ChainSpecificUtil.getL1CalldataGasCost(calldataSize); + return ChainSpecificUtil._getL1CalldataGasCost(calldataSize); } } diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFConsumer.sol b/contracts/src/v0.8/vrf/testhelpers/VRFConsumer.sol index 2f063e67267..eaac0be11b1 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFConsumer.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFConsumer.sol @@ -1,8 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../VRFConsumerBase.sol"; +import {VRFConsumerBase} from "../VRFConsumerBase.sol"; contract VRFConsumer is VRFConsumerBase { uint256 public randomnessOutput; diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFConsumerV2.sol b/contracts/src/v0.8/vrf/testhelpers/VRFConsumerV2.sol index 466451c7b6a..e2502fad3ed 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFConsumerV2.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFConsumerV2.sol @@ -1,15 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../VRFConsumerBaseV2.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; contract VRFConsumerV2 is VRFConsumerBaseV2 { uint256[] public s_randomWords; uint256 public s_requestId; - VRFCoordinatorV2Interface COORDINATOR; - LinkTokenInterface LINKTOKEN; + VRFCoordinatorV2Interface internal COORDINATOR; + LinkTokenInterface internal LINKTOKEN; uint64 public s_subId; uint256 public s_gasAvailable; diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFConsumerV2UpgradeableExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFConsumerV2UpgradeableExample.sol index b99abedf3c7..1bd11fc2249 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFConsumerV2UpgradeableExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFConsumerV2UpgradeableExample.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../../dev/VRFConsumerBaseV2Upgradeable.sol"; -import "@openzeppelin/contracts-upgradeable-4.7.3/proxy/utils/Initializable.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2Upgradeable} from "../dev/VRFConsumerBaseV2Upgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable-4.7.3/proxy/utils/Initializable.sol"; contract VRFConsumerV2UpgradeableExample is Initializable, VRFConsumerBaseV2Upgradeable { uint256[] public s_randomWords; diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorV2TestHelper.sol b/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorV2TestHelper.sol index 5d336594e5e..f9385329686 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorV2TestHelper.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorV2TestHelper.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../interfaces/AggregatorV3Interface.sol"; +import {AggregatorV3Interface} from "../../interfaces/AggregatorV3Interface.sol"; // Ideally this contract should inherit from VRFCoordinatorV2 and delegate calls to VRFCoordinatorV2 // However, due to exceeding contract size limit, the logic from VRFCoordinatorV2 is ported over to this contract contract VRFCoordinatorV2TestHelper { - uint96 s_paymentAmount; + uint96 internal s_paymentAmount; AggregatorV3Interface public immutable LINK_ETH_FEED; diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFExternalSubOwnerExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFExternalSubOwnerExample.sol index f6b171cb508..ee2a71df71b 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFExternalSubOwnerExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFExternalSubOwnerExample.sol @@ -1,17 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../VRFConsumerBaseV2.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; contract VRFExternalSubOwnerExample is VRFConsumerBaseV2 { - VRFCoordinatorV2Interface COORDINATOR; - LinkTokenInterface LINKTOKEN; + VRFCoordinatorV2Interface internal COORDINATOR; + LinkTokenInterface internal LINKTOKEN; uint256[] public s_randomWords; uint256 public s_requestId; - address s_owner; + address internal s_owner; constructor(address vrfCoordinator, address link) VRFConsumerBaseV2(vrfCoordinator) { COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFLoadTestExternalSubOwner.sol b/contracts/src/v0.8/vrf/testhelpers/VRFLoadTestExternalSubOwner.sol index b4bf37990d7..0193e3f67f0 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFLoadTestExternalSubOwner.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFLoadTestExternalSubOwner.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../VRFConsumerBaseV2.sol"; -import "../../shared/access/ConfirmedOwner.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; /** * @title The VRFLoadTestExternalSubOwner contract. diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFLoadTestOwnerlessConsumer.sol b/contracts/src/v0.8/vrf/testhelpers/VRFLoadTestOwnerlessConsumer.sol index 93c75298d9e..a967c8a565e 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFLoadTestOwnerlessConsumer.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFLoadTestOwnerlessConsumer.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../VRFConsumerBase.sol"; -import "../../shared/interfaces/IERC677Receiver.sol"; +import {VRFConsumerBase} from "../VRFConsumerBase.sol"; +import {IERC677Receiver} from "../../shared/interfaces/IERC677Receiver.sol"; /** * @title The VRFLoadTestOwnerlessConsumer contract. diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFMaliciousConsumerV2.sol b/contracts/src/v0.8/vrf/testhelpers/VRFMaliciousConsumerV2.sol index f11fcc0b7d0..be416e9a5cf 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFMaliciousConsumerV2.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFMaliciousConsumerV2.sol @@ -1,18 +1,18 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../VRFConsumerBaseV2.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; contract VRFMaliciousConsumerV2 is VRFConsumerBaseV2 { uint256[] public s_randomWords; uint256 public s_requestId; - VRFCoordinatorV2Interface COORDINATOR; - LinkTokenInterface LINKTOKEN; + VRFCoordinatorV2Interface internal COORDINATOR; + LinkTokenInterface internal LINKTOKEN; uint64 public s_subId; uint256 public s_gasAvailable; - bytes32 s_keyHash; + bytes32 internal s_keyHash; constructor(address vrfCoordinator, address link) VRFConsumerBaseV2(vrfCoordinator) { COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFOwnerlessConsumerExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFOwnerlessConsumerExample.sol index 0eeb5ebc8f1..a641267597c 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFOwnerlessConsumerExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFOwnerlessConsumerExample.sol @@ -3,8 +3,8 @@ // contract. pragma solidity ^0.8.4; -import "../VRFConsumerBase.sol"; -import "../../shared/interfaces/IERC677Receiver.sol"; +import {VRFConsumerBase} from "../VRFConsumerBase.sol"; +import {IERC677Receiver} from "../../shared/interfaces/IERC677Receiver.sol"; contract VRFOwnerlessConsumerExample is VRFConsumerBase, IERC677Receiver { uint256 public s_randomnessOutput; diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFRequestIDBaseTestHelper.sol b/contracts/src/v0.8/vrf/testhelpers/VRFRequestIDBaseTestHelper.sol index b97a835a94d..344797f0df3 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFRequestIDBaseTestHelper.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFRequestIDBaseTestHelper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../VRFRequestIDBase.sol"; +import {VRFRequestIDBase} from "../VRFRequestIDBase.sol"; contract VRFRequestIDBaseTestHelper is VRFRequestIDBase { function makeVRFInputSeed_( diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFSingleConsumerExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFSingleConsumerExample.sol index d4dd7b9087a..303394ee888 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFSingleConsumerExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFSingleConsumerExample.sol @@ -2,13 +2,13 @@ // Example of a single consumer contract which owns the subscription. pragma solidity ^0.8.0; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../VRFConsumerBaseV2.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; contract VRFSingleConsumerExample is VRFConsumerBaseV2 { - VRFCoordinatorV2Interface COORDINATOR; - LinkTokenInterface LINKTOKEN; + VRFCoordinatorV2Interface internal COORDINATOR; + LinkTokenInterface internal LINKTOKEN; struct RequestConfig { uint64 subId; diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFSubscriptionBalanceMonitorExposed.sol b/contracts/src/v0.8/vrf/testhelpers/VRFSubscriptionBalanceMonitorExposed.sol index e2c276615a9..471b6f99301 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFSubscriptionBalanceMonitorExposed.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFSubscriptionBalanceMonitorExposed.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.6; -import "../../dev/VRFSubscriptionBalanceMonitor.sol"; +import {VRFSubscriptionBalanceMonitor} from "../dev/VRFSubscriptionBalanceMonitor.sol"; contract VRFSubscriptionBalanceMonitorExposed is VRFSubscriptionBalanceMonitor { constructor( diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFTestHelper.sol b/contracts/src/v0.8/vrf/testhelpers/VRFTestHelper.sol index 56a1058bf03..e3f9ee04824 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFTestHelper.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFTestHelper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../VRF.sol"; +import {VRF} from "../VRF.sol"; /** *********************************************************************** @notice Testing harness for VRF.sol, exposing its internal methods. Not to diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol index 3fd3f4e4038..d364e5002b4 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../VRFConsumerBaseV2.sol"; -import "../../shared/access/ConfirmedOwner.sol"; -import "../../ChainSpecificUtil.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; /** * @title The VRFLoadTestExternalSubOwner contract. @@ -19,7 +19,7 @@ contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2, ConfirmedOwner { uint256 public s_slowestFulfillment = 0; uint256 public s_fastestFulfillment = 999; uint256 public s_lastRequestId; - mapping(uint256 => uint256) requestHeights; // requestIds to block number when rand request was made + mapping(uint256 => uint256) internal requestHeights; // requestIds to block number when rand request was made struct RequestStatus { bool fulfilled; @@ -37,7 +37,7 @@ contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2, ConfirmedOwner { } function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { - uint256 fulfilmentBlockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 fulfilmentBlockNumber = ChainSpecificUtil._getBlockNumber(); uint256 requestDelay = fulfilmentBlockNumber - requestHeights[_requestId]; uint256 requestDelayInMillions = requestDelay * 1_000_000; @@ -74,7 +74,7 @@ contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2, ConfirmedOwner { _numWords ); s_lastRequestId = requestId; - uint256 requestBlockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 requestBlockNumber = ChainSpecificUtil._getBlockNumber(); s_requests[requestId] = RequestStatus({ randomWords: new uint256[](0), fulfilled: false, diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol index 361c32706f4..dd1af80a92d 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol @@ -1,11 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../VRFConsumerBaseV2.sol"; -import "../../shared/access/ConfirmedOwner.sol"; -import "../../ChainSpecificUtil.sol"; -import "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { VRFCoordinatorV2Interface public COORDINATOR; @@ -16,7 +15,7 @@ contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { uint256 public s_slowestFulfillment = 0; uint256 public s_fastestFulfillment = 999; uint256 public s_lastRequestId; - mapping(uint256 => uint256) requestHeights; // requestIds to block number when rand request was made + mapping(uint256 => uint256) internal requestHeights; // requestIds to block number when rand request was made struct RequestStatus { bool fulfilled; @@ -38,7 +37,7 @@ contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { } function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { - uint256 fulfilmentBlockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 fulfilmentBlockNumber = ChainSpecificUtil._getBlockNumber(); uint256 requestDelay = fulfilmentBlockNumber - requestHeights[_requestId]; uint256 requestDelayInMillions = requestDelay * 1_000_000; @@ -74,7 +73,7 @@ contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { _numWords ); s_lastRequestId = requestId; - uint256 requestBlockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 requestBlockNumber = ChainSpecificUtil._getBlockNumber(); s_requests[requestId] = RequestStatus({ randomWords: new uint256[](0), fulfilled: false, diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2RevertingExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2RevertingExample.sol index 72be535a000..4eccafa37ef 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2RevertingExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2RevertingExample.sol @@ -1,16 +1,16 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../VRFConsumerBaseV2.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; // VRFV2RevertingExample will always revert. Used for testing only, useless in prod. contract VRFV2RevertingExample is VRFConsumerBaseV2 { uint256[] public s_randomWords; uint256 public s_requestId; - VRFCoordinatorV2Interface COORDINATOR; - LinkTokenInterface LINKTOKEN; + VRFCoordinatorV2Interface internal COORDINATOR; + LinkTokenInterface internal LINKTOKEN; uint64 public s_subId; uint256 public s_gasAvailable; @@ -20,6 +20,7 @@ contract VRFV2RevertingExample is VRFConsumerBaseV2 { } function fulfillRandomWords(uint256, uint256[] memory) internal pure override { + // solhint-disable-next-line custom-errors, reason-string revert(); } @@ -33,12 +34,14 @@ contract VRFV2RevertingExample is VRFConsumerBaseV2 { } function topUpSubscription(uint96 amount) external { + // solhint-disable-next-line custom-errors require(s_subId != 0, "sub not set"); // Approve the link transfer. LINKTOKEN.transferAndCall(address(COORDINATOR), amount, abi.encode(s_subId)); } function updateSubscription(address[] memory consumers) external { + // solhint-disable-next-line custom-errors require(s_subId != 0, "subID not set"); for (uint256 i = 0; i < consumers.length; i++) { COORDINATOR.addConsumer(s_subId, consumers[i]); diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperConsumerExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperConsumerExample.sol index 7ab54ee9fa3..563a5b09288 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperConsumerExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperConsumerExample.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "../VRFV2WrapperConsumerBase.sol"; -import "../../shared/access/ConfirmedOwner.sol"; +import {VRFV2WrapperConsumerBase} from "../VRFV2WrapperConsumerBase.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; contract VRFV2WrapperConsumerExample is VRFV2WrapperConsumerBase, ConfirmedOwner { event WrappedRequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment); @@ -33,6 +33,7 @@ contract VRFV2WrapperConsumerExample is VRFV2WrapperConsumerBase, ConfirmedOwner } function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { + // solhint-disable-next-line custom-errors require(s_requests[_requestId].paid > 0, "request not found"); s_requests[_requestId].fulfilled = true; s_requests[_requestId].randomWords = _randomWords; @@ -42,6 +43,7 @@ contract VRFV2WrapperConsumerExample is VRFV2WrapperConsumerBase, ConfirmedOwner function getRequestStatus( uint256 _requestId ) external view returns (uint256 paid, bool fulfilled, uint256[] memory randomWords) { + // 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); diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperOutOfGasConsumerExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperOutOfGasConsumerExample.sol index e6747820fdb..353027d5570 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperOutOfGasConsumerExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperOutOfGasConsumerExample.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "../VRFV2WrapperConsumerBase.sol"; -import "../../shared/access/ConfirmedOwner.sol"; +import {VRFV2WrapperConsumerBase} from "../VRFV2WrapperConsumerBase.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; contract VRFV2WrapperOutOfGasConsumerExample is VRFV2WrapperConsumerBase, ConfirmedOwner { constructor( @@ -18,7 +18,7 @@ contract VRFV2WrapperOutOfGasConsumerExample is VRFV2WrapperConsumerBase, Confir return requestRandomness(_callbackGasLimit, _requestConfirmations, _numWords); } - function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal view override { + function fulfillRandomWords(uint256 /* _requestId */, uint256[] memory /* _randomWords */) internal view override { while (gasleft() > 0) {} } } diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperRevertingConsumerExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperRevertingConsumerExample.sol index c3699a1d74b..d78992acfd8 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperRevertingConsumerExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperRevertingConsumerExample.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "../VRFV2WrapperConsumerBase.sol"; -import "../../shared/access/ConfirmedOwner.sol"; +import {VRFV2WrapperConsumerBase} from "../VRFV2WrapperConsumerBase.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; contract VRFV2WrapperRevertingConsumerExample is VRFV2WrapperConsumerBase, ConfirmedOwner { constructor( @@ -18,7 +18,7 @@ contract VRFV2WrapperRevertingConsumerExample is VRFV2WrapperConsumerBase, Confi return requestRandomness(_callbackGasLimit, _requestConfirmations, _numWords); } - function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal pure override { + function fulfillRandomWords(uint256 /* _requestId */, uint256[] memory /* _randomWords */) internal pure override { revert("reverting example"); } } diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperUnderFundingConsumer.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperUnderFundingConsumer.sol index ae0f9eac83c..3bae36f58f1 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperUnderFundingConsumer.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperUnderFundingConsumer.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/access/ConfirmedOwner.sol"; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/VRFV2WrapperInterface.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFV2WrapperInterface} from "../interfaces/VRFV2WrapperInterface.sol"; contract VRFV2WrapperUnderFundingConsumer is ConfirmedOwner { LinkTokenInterface internal immutable LINK; diff --git a/contracts/test/v0.8/VRFD20.test.ts b/contracts/test/v0.8/VRFD20.test.ts index 6183658336f..f1c1278b89a 100644 --- a/contracts/test/v0.8/VRFD20.test.ts +++ b/contracts/test/v0.8/VRFD20.test.ts @@ -34,7 +34,7 @@ before(async () => { roles.defaultAccount, ) vrfCoordinatorMockFactory = await ethers.getContractFactory( - 'src/v0.8/mocks/VRFCoordinatorMock.sol:VRFCoordinatorMock', + 'src/v0.8/vrf/mocks/VRFCoordinatorMock.sol:VRFCoordinatorMock', roles.defaultAccount, ) vrfD20Factory = await ethers.getContractFactory( diff --git a/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts b/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts index b0a2a10b201..04771e4ef7f 100644 --- a/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts +++ b/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts @@ -23,7 +23,7 @@ describe('VRFCoordinatorV2Mock', () => { random = accounts[2] const vrfCoordinatorV2MockFactory = await ethers.getContractFactory( - 'src/v0.8/mocks/VRFCoordinatorV2Mock.sol:VRFCoordinatorV2Mock', + 'src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol:VRFCoordinatorV2Mock', accounts[0], ) vrfCoordinatorV2Mock = await vrfCoordinatorV2MockFactory.deploy( diff --git a/contracts/test/v0.8/foundry/transmission/EIP_712_1014_4337.t.sol b/contracts/test/v0.8/foundry/transmission/EIP_712_1014_4337.t.sol index acdc6773642..ad7b2999c90 100644 --- a/contracts/test/v0.8/foundry/transmission/EIP_712_1014_4337.t.sol +++ b/contracts/test/v0.8/foundry/transmission/EIP_712_1014_4337.t.sol @@ -12,7 +12,7 @@ import "../../../../src/v0.8/vendor/entrypoint/interfaces/IEntryPoint.sol"; import "../../../../src/v0.8/dev/transmission/ERC-4337/SCALibrary.sol"; import "../../../../src/v0.8/mocks/MockLinkToken.sol"; import "../../../../src/v0.8/shared/interfaces/LinkTokenInterface.sol"; -import "../../../../src/v0.8/mocks/VRFCoordinatorMock.sol"; +import "../../../../src/v0.8/vrf/mocks/VRFCoordinatorMock.sol"; import "../../../../src/v0.8/tests/MockV3Aggregator.sol"; import "../../../../src/v0.8/vrf/testhelpers/VRFConsumer.sol"; diff --git a/contracts/test/v0.8/foundry/vrf/ChainSpecificUtil.t.sol b/contracts/test/v0.8/foundry/vrf/ChainSpecificUtil.t.sol index 06f234cfdae..e0ac0036b36 100644 --- a/contracts/test/v0.8/foundry/vrf/ChainSpecificUtil.t.sol +++ b/contracts/test/v0.8/foundry/vrf/ChainSpecificUtil.t.sol @@ -67,14 +67,14 @@ contract ChainSpecificUtilTest is BaseTest { abi.encodeWithSelector(ArbSys.arbBlockHash.selector, expectedBlockNumber), abi.encodePacked(expectedBlockHash) ); - bytes32 actualBlockHash = ChainSpecificUtil.getBlockhash(uint64(expectedBlockNumber)); + bytes32 actualBlockHash = ChainSpecificUtil._getBlockhash(uint64(expectedBlockNumber)); assertEq(expectedBlockHash, actualBlockHash, "incorrect blockhash"); } } function testGetBlockhashOptimism() public { // Optimism L2 block hash is simply blockhash() - bytes32 actualBlockhash = ChainSpecificUtil.getBlockhash(uint64(block.number - 1)); + bytes32 actualBlockhash = ChainSpecificUtil._getBlockhash(uint64(block.number - 1)); assertEq(blockhash(block.number - 1), actualBlockhash); } @@ -85,14 +85,14 @@ contract ChainSpecificUtilTest is BaseTest { vm.chainId(chainIds[i]); uint256 expectedBlockNumber = expectedBlockNumbers[i]; vm.mockCall(ARBSYS_ADDR, abi.encodeWithSelector(ArbSys.arbBlockNumber.selector), abi.encode(expectedBlockNumber)); - uint256 actualBlockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 actualBlockNumber = ChainSpecificUtil._getBlockNumber(); assertEq(expectedBlockNumber, actualBlockNumber, "incorrect block number"); } } function testGetBlockNumberOptimism() public { // Optimism L2 block number is simply block.number - uint256 actualBlockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 actualBlockNumber = ChainSpecificUtil._getBlockNumber(); assertEq(block.number, actualBlockNumber); } @@ -107,7 +107,7 @@ contract ChainSpecificUtilTest is BaseTest { abi.encodeWithSelector(ArbGasInfo.getCurrentTxL1GasFees.selector), abi.encode(expectedGasFee) ); - uint256 actualGasFee = ChainSpecificUtil.getCurrentTxL1GasFees(""); + uint256 actualGasFee = ChainSpecificUtil._getCurrentTxL1GasFees(""); assertEq(expectedGasFee, actualGasFee, "incorrect gas fees"); } } @@ -131,7 +131,7 @@ contract ChainSpecificUtilTest is BaseTest { abi.encodeWithSelector(OVM_GasPriceOracle.getL1Fee.selector, bytes.concat(someCalldata, L1_FEE_DATA_PADDING)), abi.encode(expectedL1Fee) ); - uint256 actualL1Fee = ChainSpecificUtil.getCurrentTxL1GasFees(someCalldata); + uint256 actualL1Fee = ChainSpecificUtil._getCurrentTxL1GasFees(someCalldata); assertEq(expectedL1Fee, actualL1Fee, "incorrect gas fees"); } } @@ -148,7 +148,7 @@ contract ChainSpecificUtilTest is BaseTest { // fee = l1PricePerByte * (calldataSizeBytes + 140) // fee = 10 * (10 + 140) = 1500 - uint256 dataFee = ChainSpecificUtil.getL1CalldataGasCost(10); + uint256 dataFee = ChainSpecificUtil._getL1CalldataGasCost(10); assertEq(dataFee, 1500); } } @@ -188,7 +188,7 @@ contract ChainSpecificUtilTest is BaseTest { // tx_data_gas = 0 * 4 + 10 * 16 = 160 // l1_data_fee = l1_gas_price * (tx_data_gas + fixed_overhead) * dynamic_overhead // l1_data_fee = 10 * (160 + 160) * 500_000 / 1_000_000 = 1600 - uint256 dataFee = ChainSpecificUtil.getL1CalldataGasCost(10); + uint256 dataFee = ChainSpecificUtil._getL1CalldataGasCost(10); assertEq(dataFee, 1600); } } diff --git a/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol b/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol index 47fff7ea900..4f3ea40d828 100644 --- a/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol +++ b/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol @@ -1,7 +1,7 @@ pragma solidity 0.8.6; import "../BaseTest.t.sol"; -import {TrustedBlockhashStore} from "../../../../src/v0.8/dev/vrf/TrustedBlockhashStore.sol"; +import {TrustedBlockhashStore} from "../../../../src/v0.8/vrf/dev/TrustedBlockhashStore.sol"; import {console} from "forge-std/console.sol"; contract TrustedBlockhashStoreTest is BaseTest { diff --git a/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Mock.t.sol b/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Mock.t.sol index dd607f2ce7b..6378d40167b 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Mock.t.sol +++ b/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Mock.t.sol @@ -4,7 +4,7 @@ import "../BaseTest.t.sol"; import {VRF} from "../../../../src/v0.8/vrf/VRF.sol"; import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; -import {VRFCoordinatorV2Mock} from "../../../../src/v0.8/mocks/VRFCoordinatorV2Mock.sol"; +import {VRFCoordinatorV2Mock} from "../../../../src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol"; import {VRFConsumerV2} from "../../../../src/v0.8/vrf/testhelpers/VRFConsumerV2.sol"; contract VRFCoordinatorV2MockTest is BaseTest { diff --git a/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Plus_Migration.t.sol b/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Plus_Migration.t.sol index a847bd5beee..d7a54d6223c 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Plus_Migration.t.sol +++ b/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Plus_Migration.t.sol @@ -1,14 +1,14 @@ pragma solidity 0.8.6; import "../BaseTest.t.sol"; -import {VRFCoordinatorV2Plus_V2Example} from "../../../../src/v0.8/dev/vrf/testhelpers/VRFCoordinatorV2Plus_V2Example.sol"; -import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2_5.sol"; -import {VRFCoordinatorV2_5} from "../../../../src/v0.8/dev/vrf/VRFCoordinatorV2_5.sol"; -import {SubscriptionAPI} from "../../../../src/v0.8/dev/vrf/SubscriptionAPI.sol"; -import {VRFV2PlusConsumerExample} from "../../../../src/v0.8/dev/vrf/testhelpers/VRFV2PlusConsumerExample.sol"; +import {VRFCoordinatorV2Plus_V2Example} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol"; +import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; +import {VRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol"; +import {SubscriptionAPI} from "../../../../src/v0.8/vrf/dev/SubscriptionAPI.sol"; +import {VRFV2PlusConsumerExample} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol"; import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; -import {VRFV2PlusMaliciousMigrator} from "../../../../src/v0.8/dev/vrf/testhelpers/VRFV2PlusMaliciousMigrator.sol"; +import {VRFV2PlusMaliciousMigrator} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFV2PlusMaliciousMigrator.sol"; contract VRFCoordinatorV2Plus_Migration is BaseTest { uint256 internal constant DEFAULT_LINK_FUNDING = 10 ether; // 10 LINK diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol b/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol index 13d52b676c5..e2734f17288 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol +++ b/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol @@ -4,12 +4,12 @@ import "../BaseTest.t.sol"; import {VRF} from "../../../../src/v0.8/vrf/VRF.sol"; import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; -import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2_5.sol"; -import {VRFCoordinatorV2_5} from "../../../../src/v0.8/dev/vrf/VRFCoordinatorV2_5.sol"; -import {SubscriptionAPI} from "../../../../src/v0.8/dev/vrf/SubscriptionAPI.sol"; -import {BlockhashStore} from "../../../../src/v0.8/dev/BlockhashStore.sol"; -import {VRFV2PlusConsumerExample} from "../../../../src/v0.8/dev/vrf/testhelpers/VRFV2PlusConsumerExample.sol"; -import {VRFV2PlusClient} from "../../../../src/v0.8/dev/vrf/libraries/VRFV2PlusClient.sol"; +import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; +import {VRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol"; +import {SubscriptionAPI} from "../../../../src/v0.8/vrf/dev/SubscriptionAPI.sol"; +import {BlockhashStore} from "../../../../src/v0.8/vrf/dev/BlockhashStore.sol"; +import {VRFV2PlusConsumerExample} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol"; +import {VRFV2PlusClient} from "../../../../src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; import {console} from "forge-std/console.sol"; import {VmSafe} from "forge-std/Vm.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; // for Math.ceilDiv @@ -282,15 +282,15 @@ contract VRFV2Plus is BaseTest { // Store the previous block's blockhash, and assert that it is as expected. vm.roll(requestBlock + 1); s_bhs.store(requestBlock); - assertEq(hex"c65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8", s_bhs.getBlockhash(requestBlock)); + assertEq(hex"000000000000000000000000000000000000000000000000000000000000000a", s_bhs.getBlockhash(requestBlock)); // Fulfill the request. // Proof generated via the generate-proof-v2-plus script command. Example usage: /* go run . generate-proof-v2-plus \ -key-hash 0x9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528 \ - -pre-seed 53391429126065232382402681707515137895470547057819816488254124798726362946635 \ - -block-hash 0xc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8 \ + -pre-seed 93724884573574303181157854277074121673523280784530506403108144933983063023487 \ + -block-hash 0x000000000000000000000000000000000000000000000000000000000000000a \ -block-num 10 \ -sender 0x90A8820424CC8a819d14cBdE54D12fD3fbFa9bb2 \ -native-payment true @@ -301,22 +301,22 @@ contract VRFV2Plus is BaseTest { 62070622898698443831883535403436258712770888294397026493185421712108624767191 ], gamma: [ - 2973102176083872659982988645522968133664529102555885971868619302367987919116, - 43610558806647181042154132372309425100765955827430056035281841579494767100593 + 51111463251706978184511913295560024261167135799300172382907308330135472647507, + 41885656274025752055847945432737871864088659248922821023734315208027501951872 ], - c: 44558436621153210954487996771157467729629491520915192177070584116261579650304, - s: 18447217702001910909971999949841419857536434117467121546901211519652998560328, - seed: 53391429126065232382402681707515137895470547057819816488254124798726362946635, - uWitness: 0x61e70839187C12Fe136bdcC78D1D3765BecA245d, + c: 96917856581077810363012153828220232197567408835708926581335248000925197916153, + s: 103298896676233752268329042222773891728807677368628421408380318882272184455566, + seed: 93724884573574303181157854277074121673523280784530506403108144933983063023487, + uWitness: 0xFCaA10875C6692f6CcC86c64300eb0b52f2D4323, cGammaWitness: [ - 57868024672571504735938309170346165090467827794150592801232968679608710558443, - 19249635816589941728350586356475545703589085434839461964712223344491075318152 + 61463607927970680172418313129927007099021056249775757132623753443657677198526, + 48686021866486086188742596461341782400160109177829661164208082534005682984658 ], sHashWitness: [ - 61151023867440095994162103308586528914977848168432699421313437043942463394142, - 107161674609768447269383119603000260750848712436031813376573304048979100187696 + 91508089836242281395929619352465003226819385335975246221498243754781593857533, + 63571625936444669399167157725633389238098818902162172059681813608664564703308 ], - zInv: 92231836131549905872346812799402691650433126386650679876913933650318463342041 + zInv: 97568175302326019383632009699686265453584842953005404815285123863099260038246 }); VRFCoordinatorV2_5.RequestCommitment memory rc = VRFCoordinatorV2_5.RequestCommitment({ blockNum: requestBlock, @@ -399,15 +399,15 @@ contract VRFV2Plus is BaseTest { // Store the previous block's blockhash, and assert that it is as expected. vm.roll(requestBlock + 1); s_bhs.store(requestBlock); - assertEq(hex"ce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec", s_bhs.getBlockhash(requestBlock)); + assertEq(hex"0000000000000000000000000000000000000000000000000000000000000014", s_bhs.getBlockhash(requestBlock)); // Fulfill the request. // Proof generated via the generate-proof-v2-plus script command. Example usage: /* go run . generate-proof-v2-plus \ -key-hash 0x9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528 \ - -pre-seed 14817911724325909152780695848148728017190840227899344848185245004944693487904 \ - -block-hash 0xce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec \ + -pre-seed 108233140904510496268355288815996296196427471042093167619305836589216327096601 \ + -block-hash 0x0000000000000000000000000000000000000000000000000000000000000014 \ -block-num 20 \ -sender 0x90A8820424CC8a819d14cBdE54D12fD3fbFa9bb2 */ @@ -417,22 +417,22 @@ contract VRFV2Plus is BaseTest { 62070622898698443831883535403436258712770888294397026493185421712108624767191 ], gamma: [ - 33866404953216897461413961842321788789902210776565180957857448351149268461878, - 115311460432520855364215812517921508651759645277579047898967111537639679255245 + 49785247270467418393187938018746488660500261614113251546613288843777654841004, + 8320717868018488740308781441198484312662094766876176838868269181386589318272 ], - c: 32561838617228634441320154326890637858849550728945663611942735469609183032389, - s: 55806041637816588920133401262818662941786708593795051215322306020699218819370, - seed: 14817911724325909152780695848148728017190840227899344848185245004944693487904, - uWitness: 0x917554f18dB75eac206Ae5366B80c0b6A87b5996, + c: 41596204381278553342984662603150353549780558761307588910860350083645227536604, + s: 81592778991188138734863787790226463602813498664606420860910885269124681994753, + seed: 108233140904510496268355288815996296196427471042093167619305836589216327096601, + uWitness: 0x56920892EE71E624d369dCc8dc63B6878C85Ca70, cGammaWitness: [ - 84076069514674055711740813040098459867759972960517070154541804330775196519927, - 23456142794899412334950030002327578074149212885334118042147040122102091306080 + 28250667431035633903490940933503696927659499415200427260709034207157951953043, + 105660182690338773283351292037478192732977803900032569393220726139772041021018 ], sHashWitness: [ - 67919054534004130885903575144858988177160334233773664996450084407340736891592, - 82934864721844704662104532515068228502043057799129930869203380251475000254135 + 18420263847278540234821121001488166570853056146131705862117248292063859054211, + 15740432967529684573970722302302642068194042971767150190061244675457227502736 ], - zInv: 37397948970756055003892765560695914630264479979131589134478580629419519112029 + zInv: 100579074451139970455673776933943662313989441807178260211316504761358492254052 }); VRFCoordinatorV2_5.RequestCommitment memory rc = VRFCoordinatorV2_5.RequestCommitment({ blockNum: requestBlock, diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol b/contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol index db9e11e059e..335e64ff7ef 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol +++ b/contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol @@ -1,8 +1,8 @@ pragma solidity 0.8.6; import "../BaseTest.t.sol"; -import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2_5.sol"; -import {SubscriptionAPI} from "../../../../src/v0.8/dev/vrf/SubscriptionAPI.sol"; +import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; +import {SubscriptionAPI} from "../../../../src/v0.8/vrf/dev/SubscriptionAPI.sol"; import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; // for Strings.toString diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper.t.sol b/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper.t.sol index 4cb02991da1..462db4447fd 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper.t.sol +++ b/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper.t.sol @@ -4,12 +4,12 @@ import "../BaseTest.t.sol"; import {VRF} from "../../../../src/v0.8/vrf/VRF.sol"; import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; -import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2_5.sol"; -import {VRFV2PlusWrapperConsumerBase} from "../../../../src/v0.8/dev/vrf/VRFV2PlusWrapperConsumerBase.sol"; -import {VRFV2PlusWrapperConsumerExample} from "../../../../src/v0.8/dev/vrf/testhelpers/VRFV2PlusWrapperConsumerExample.sol"; -import {VRFCoordinatorV2_5} from "../../../../src/v0.8/dev/vrf/VRFCoordinatorV2_5.sol"; -import {VRFV2PlusWrapper} from "../../../../src/v0.8/dev/vrf/VRFV2PlusWrapper.sol"; -import {VRFV2PlusClient} from "../../../../src/v0.8/dev/vrf/libraries/VRFV2PlusClient.sol"; +import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; +import {VRFV2PlusWrapperConsumerBase} from "../../../../src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol"; +import {VRFV2PlusWrapperConsumerExample} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol"; +import {VRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol"; +import {VRFV2PlusWrapper} from "../../../../src/v0.8/vrf/dev/VRFV2PlusWrapper.sol"; +import {VRFV2PlusClient} from "../../../../src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; import {console} from "forge-std/console.sol"; contract VRFV2PlusWrapperTest is BaseTest { diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper_Migration.t.sol b/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper_Migration.t.sol index e4c8a40172f..91eedb585e9 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper_Migration.t.sol +++ b/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper_Migration.t.sol @@ -4,14 +4,14 @@ import "../BaseTest.t.sol"; import {VRF} from "../../../../src/v0.8/vrf/VRF.sol"; import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; -import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2_5.sol"; -import {VRFCoordinatorV2Plus_V2Example} from "../../../../src/v0.8/dev/vrf/testhelpers/VRFCoordinatorV2Plus_V2Example.sol"; -import {VRFV2PlusWrapperConsumerBase} from "../../../../src/v0.8/dev/vrf/VRFV2PlusWrapperConsumerBase.sol"; -import {VRFV2PlusWrapperConsumerExample} from "../../../../src/v0.8/dev/vrf/testhelpers/VRFV2PlusWrapperConsumerExample.sol"; -import {SubscriptionAPI} from "../../../../src/v0.8/dev/vrf/SubscriptionAPI.sol"; -import {VRFCoordinatorV2_5} from "../../../../src/v0.8/dev/vrf/VRFCoordinatorV2_5.sol"; -import {VRFV2PlusWrapper} from "../../../../src/v0.8/dev/vrf/VRFV2PlusWrapper.sol"; -import {VRFV2PlusClient} from "../../../../src/v0.8/dev/vrf/libraries/VRFV2PlusClient.sol"; +import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; +import {VRFCoordinatorV2Plus_V2Example} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol"; +import {VRFV2PlusWrapperConsumerBase} from "../../../../src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol"; +import {VRFV2PlusWrapperConsumerExample} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol"; +import {SubscriptionAPI} from "../../../../src/v0.8/vrf/dev/SubscriptionAPI.sol"; +import {VRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol"; +import {VRFV2PlusWrapper} from "../../../../src/v0.8/vrf/dev/VRFV2PlusWrapper.sol"; +import {VRFV2PlusClient} from "../../../../src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; contract VRFV2PlusWrapperTest is BaseTest { address internal constant LINK_WHALE = 0xD883a6A1C22fC4AbFE938a5aDF9B2Cc31b1BF18B; diff --git a/core/chains/evm/client/node_lifecycle.go b/core/chains/evm/client/node_lifecycle.go index d55df58d6ef..609d1522ea5 100644 --- a/core/chains/evm/client/node_lifecycle.go +++ b/core/chains/evm/client/node_lifecycle.go @@ -97,6 +97,7 @@ func (n *node) aliveLoop() { n.declareUnreachable() return } + n.aliveLoopSub = sub defer sub.Unsubscribe() var outOfSyncT *time.Ticker diff --git a/core/chains/evm/log/orm_test.go b/core/chains/evm/log/orm_test.go index 70f400da457..365bb354338 100644 --- a/core/chains/evm/log/orm_test.go +++ b/core/chains/evm/log/orm_test.go @@ -26,7 +26,7 @@ func TestORM_broadcasts(t *testing.T) { orm := log.NewORM(db, lggr, cfg.Database(), cltest.FixtureChainID) - _, addr := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, addr := cltest.MustInsertRandomKey(t, ethKeyStore) specV2 := cltest.MustInsertV2JobSpec(t, db, addr) const selectQuery = `SELECT consumed FROM log_broadcasts @@ -165,10 +165,10 @@ func TestORM_MarkUnconsumed(t *testing.T) { orm := log.NewORM(db, lggr, cfg.Database(), cltest.FixtureChainID) - _, addr1 := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, addr1 := cltest.MustInsertRandomKey(t, ethKeyStore) job1 := cltest.MustInsertV2JobSpec(t, db, addr1) - _, addr2 := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, addr2 := cltest.MustInsertRandomKey(t, ethKeyStore) job2 := cltest.MustInsertV2JobSpec(t, db, addr2) logBefore := cltest.RandomLog(t) diff --git a/core/chains/evm/logpoller/log_poller_test.go b/core/chains/evm/logpoller/log_poller_test.go index e21fc0f3838..f6be57aa6e7 100644 --- a/core/chains/evm/logpoller/log_poller_test.go +++ b/core/chains/evm/logpoller/log_poller_test.go @@ -1152,3 +1152,63 @@ func TestTooManyLogResults(t *testing.T) { require.Len(t, crit, 1) assert.Contains(t, crit[0].Message, "Too many log results in a single block") } + +func Test_CreatedAfterQueriesWithBackfill(t *testing.T) { + emittedLogs := 60 + finalityDepth := 10 + ctx := testutils.Context(t) + th := SetupTH(t, int64(finalityDepth), 3, 2) + + header, err := th.Client.HeaderByNumber(ctx, nil) + require.NoError(t, err) + + genesisBlockTime := time.UnixMilli(int64(header.Time)) + + // Emit some logs in blocks + for i := 0; i < emittedLogs; i++ { + _, err := th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err) + th.Client.Commit() + } + + // First PollAndSave, no filters are registered + currentBlock := th.PollAndSaveLogs(ctx, 1) + + err = th.LogPoller.RegisterFilter(logpoller.Filter{ + Name: "Test Emitter", + EventSigs: []common.Hash{EmitterABI.Events["Log1"].ID}, + Addresses: []common.Address{th.EmitterAddress1}, + }) + require.NoError(t, err) + + // Emit blocks to cover finality depth, because backup always backfill up to the one block before last finalized + for i := 0; i < finalityDepth+1; i++ { + th.Client.Commit() + } + + // LogPoller should backfill entire history + th.LogPoller.BackupPollAndSaveLogs(ctx, 100) + require.NoError(t, err) + + // Make sure that all logs are backfilled + logs, err := th.LogPoller.Logs( + 0, + currentBlock, + EmitterABI.Events["Log1"].ID, + th.EmitterAddress1, + pg.WithParentCtx(testutils.Context(t)), + ) + require.NoError(t, err) + require.Len(t, logs, emittedLogs) + + // We should get all the logs by the block_timestamp + logs, err = th.LogPoller.LogsCreatedAfter( + EmitterABI.Events["Log1"].ID, + th.EmitterAddress1, + genesisBlockTime, + 0, + pg.WithParentCtx(testutils.Context(t)), + ) + require.NoError(t, err) + require.Len(t, logs, emittedLogs) +} diff --git a/core/chains/evm/logpoller/orm.go b/core/chains/evm/logpoller/orm.go index 95db7c24255..f8d0e618762 100644 --- a/core/chains/evm/logpoller/orm.go +++ b/core/chains/evm/logpoller/orm.go @@ -315,27 +315,25 @@ func (o *DbORM) SelectLogs(start, end int64, address common.Address, eventSig co // SelectLogsCreatedAfter finds logs created after some timestamp. func (o *DbORM) SelectLogsCreatedAfter(address common.Address, eventSig common.Hash, after time.Time, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { - startBlock, endBlock, err := o.blocksRangeAfterTimestamp(after, confs, qopts...) - if err != nil { - return nil, err - } args, err := newQueryArgsForEvent(o.chainID, address, eventSig). - withStartBlock(startBlock). - withEndBlock(endBlock). + withBlockTimestampAfter(after). + withConfs(confs). toArgs() if err != nil { return nil, err } - var logs []Log - err = o.q.WithOpts(qopts...).SelectNamed(&logs, ` + + query := fmt.Sprintf(` SELECT * FROM evm.logs WHERE evm_chain_id = :evm_chain_id AND address = :address AND event_sig = :event_sig - AND block_number > :start_block - AND block_number <= :end_block - ORDER BY (block_number, log_index)`, args) - if err != nil { + AND block_timestamp > :block_timestamp_after + AND block_number <= %s + ORDER BY (block_number, log_index)`, nestedBlockNumberQuery()) + + var logs []Log + if err = o.q.WithOpts(qopts...).SelectNamed(&logs, query, args); err != nil { return nil, err } return logs, nil @@ -594,30 +592,28 @@ func (o *DbORM) SelectIndexedLogsByBlockRange(start, end int64, address common.A } func (o *DbORM) SelectIndexedLogsCreatedAfter(address common.Address, eventSig common.Hash, topicIndex int, topicValues []common.Hash, after time.Time, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { - startBlock, endBlock, err := o.blocksRangeAfterTimestamp(after, confs, qopts...) - if err != nil { - return nil, err - } args, err := newQueryArgsForEvent(o.chainID, address, eventSig). - withStartBlock(startBlock). - withEndBlock(endBlock). + withBlockTimestampAfter(after). + withConfs(confs). withTopicIndex(topicIndex). withTopicValues(topicValues). toArgs() if err != nil { return nil, err } - var logs []Log - err = o.q.WithOpts(qopts...).SelectNamed(&logs, ` + + query := fmt.Sprintf(` SELECT * FROM evm.logs WHERE evm_chain_id = :evm_chain_id AND address = :address AND event_sig = :event_sig AND topics[:topic_index] = ANY(:topic_values) - AND block_number > :start_block - AND block_number <= :end_block - ORDER BY (block_number, log_index)`, args) - if err != nil { + AND block_timestamp > :block_timestamp_after + AND block_number <= %s + ORDER BY (block_number, log_index)`, nestedBlockNumberQuery()) + + var logs []Log + if err = o.q.WithOpts(qopts...).SelectNamed(&logs, query, args); err != nil { return nil, err } return logs, nil @@ -685,32 +681,6 @@ func (o *DbORM) SelectIndexedLogsWithSigsExcluding(sigA, sigB common.Hash, topic return logs, nil } -func (o *DbORM) blocksRangeAfterTimestamp(after time.Time, confs Confirmations, qopts ...pg.QOpt) (int64, int64, error) { - args, err := newQueryArgs(o.chainID). - withBlockTimestampAfter(after). - toArgs() - if err != nil { - return 0, 0, err - } - - var blocks []LogPollerBlock - err = o.q.WithOpts(qopts...).SelectNamed(&blocks, ` - SELECT * FROM evm.log_poller_blocks - WHERE evm_chain_id = :evm_chain_id - AND block_number in ( - SELECT unnest(array[min(block_number), max(block_number)]) FROM evm.log_poller_blocks - WHERE evm_chain_id = :evm_chain_id - AND block_timestamp > :block_timestamp_after) - order by block_number`, args) - if err != nil { - return 0, 0, err - } - if len(blocks) != 2 { - return 0, 0, nil - } - return blocks[0].BlockNumber, blocks[1].BlockNumber - int64(confs), nil -} - func (o *DbORM) SelectLogsUntilBlockHashDataWordGreaterThan(address common.Address, eventSig common.Hash, wordIndex int, wordValueMin common.Hash, untilBlockHash common.Hash, qopts ...pg.QOpt) ([]Log, error) { var logs []Log q := o.q.WithOpts(qopts...) diff --git a/core/chains/evm/logpoller/orm_test.go b/core/chains/evm/logpoller/orm_test.go index e91baec60ec..1f43586548b 100644 --- a/core/chains/evm/logpoller/orm_test.go +++ b/core/chains/evm/logpoller/orm_test.go @@ -27,16 +27,21 @@ type block struct { } func GenLog(chainID *big.Int, logIndex int64, blockNum int64, blockHash string, topic1 []byte, address common.Address) logpoller.Log { + return GenLogWithTimestamp(chainID, logIndex, blockNum, blockHash, topic1, address, time.Now()) +} + +func GenLogWithTimestamp(chainID *big.Int, logIndex int64, blockNum int64, blockHash string, topic1 []byte, address common.Address, blockTimestamp time.Time) logpoller.Log { return logpoller.Log{ - EvmChainId: utils.NewBig(chainID), - LogIndex: logIndex, - BlockHash: common.HexToHash(blockHash), - BlockNumber: blockNum, - EventSig: common.BytesToHash(topic1), - Topics: [][]byte{topic1, topic1}, - Address: address, - TxHash: common.HexToHash("0x1234"), - Data: append([]byte("hello "), byte(blockNum)), + EvmChainId: utils.NewBig(chainID), + LogIndex: logIndex, + BlockHash: common.HexToHash(blockHash), + BlockNumber: blockNum, + EventSig: common.BytesToHash(topic1), + Topics: [][]byte{topic1, topic1}, + Address: address, + TxHash: common.HexToHash("0x1234"), + Data: append([]byte("hello "), byte(blockNum)), + BlockTimestamp: blockTimestamp, } } @@ -1182,10 +1187,10 @@ func TestSelectLogsCreatedAfter(t *testing.T) { future := time.Date(2030, 1, 1, 12, 12, 12, 0, time.UTC) require.NoError(t, th.ORM.InsertLogs([]logpoller.Log{ - GenLog(th.ChainID, 1, 1, utils.RandomAddress().String(), event[:], address), - GenLog(th.ChainID, 1, 2, utils.RandomAddress().String(), event[:], address), - GenLog(th.ChainID, 2, 2, utils.RandomAddress().String(), event[:], address), - GenLog(th.ChainID, 1, 3, utils.RandomAddress().String(), event[:], address), + GenLogWithTimestamp(th.ChainID, 1, 1, utils.RandomAddress().String(), event[:], address, past), + GenLogWithTimestamp(th.ChainID, 1, 2, utils.RandomAddress().String(), event[:], address, now), + GenLogWithTimestamp(th.ChainID, 2, 2, utils.RandomAddress().String(), event[:], address, now), + GenLogWithTimestamp(th.ChainID, 1, 3, utils.RandomAddress().String(), event[:], address, future), })) require.NoError(t, th.ORM.InsertBlock(utils.RandomAddress().Hash(), 1, past)) require.NoError(t, th.ORM.InsertBlock(utils.RandomAddress().Hash(), 2, now)) @@ -1205,7 +1210,7 @@ func TestSelectLogsCreatedAfter(t *testing.T) { { name: "picks logs after block 1", confs: 0, - after: past.Add(-time.Hour), + after: past, expectedLogs: []expectedLog{ {block: 2, log: 1}, {block: 2, log: 2}, @@ -1215,7 +1220,7 @@ func TestSelectLogsCreatedAfter(t *testing.T) { { name: "skips blocks with not enough confirmations", confs: 1, - after: past.Add(-time.Hour), + after: past, expectedLogs: []expectedLog{ {block: 2, log: 1}, {block: 2, log: 2}, @@ -1224,7 +1229,7 @@ func TestSelectLogsCreatedAfter(t *testing.T) { { name: "limits number of blocks by block_timestamp", confs: 0, - after: now.Add(-time.Hour), + after: now, expectedLogs: []expectedLog{ {block: 3, log: 1}, }, @@ -1238,7 +1243,7 @@ func TestSelectLogsCreatedAfter(t *testing.T) { { name: "returns empty dataset when too many confirmations are required", confs: 3, - after: past.Add(-time.Hour), + after: past, expectedLogs: []expectedLog{}, }, } diff --git a/core/chains/evm/monitor/balance_test.go b/core/chains/evm/monitor/balance_test.go index d6417381815..dbb2003b695 100644 --- a/core/chains/evm/monitor/balance_test.go +++ b/core/chains/evm/monitor/balance_test.go @@ -40,8 +40,8 @@ func TestBalanceMonitor_Start(t *testing.T) { db := pgtest.NewSqlxDB(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := newEthClientMock(t) - _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore, 0) - _, k1Addr := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, k1Addr := cltest.MustInsertRandomKey(t, ethKeyStore) + _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.TestLogger(t)) defer func() { assert.NoError(t, bm.Close()) }() @@ -69,7 +69,7 @@ func TestBalanceMonitor_Start(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := newEthClientMock(t) - _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.TestLogger(t)) defer func() { assert.NoError(t, bm.Close()) }() @@ -89,7 +89,7 @@ func TestBalanceMonitor_Start(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := newEthClientMock(t) - _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.TestLogger(t)) defer func() { assert.NoError(t, bm.Close()) }() @@ -119,7 +119,7 @@ func TestBalanceMonitor_Start(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := newEthClientMock(t) - _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.TestLogger(t)) defer func() { assert.NoError(t, bm.Close()) }() @@ -146,8 +146,8 @@ func TestBalanceMonitor_OnNewLongestChain_UpdatesBalance(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := newEthClientMock(t) - _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore, 0) - _, k1Addr := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) + _, k1Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.TestLogger(t)) k0bal := big.NewInt(42) @@ -197,7 +197,7 @@ func TestBalanceMonitor_FewerRPCCallsWhenBehind(t *testing.T) { cfg := configtest.NewGeneralConfig(t, nil) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + cltest.MustInsertRandomKey(t, ethKeyStore) ethClient := newEthClientMock(t) diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index e1133e8ef21..3865604a49d 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -32,6 +32,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" gasmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" @@ -69,7 +70,7 @@ func NewTestEthBroadcaster( ge := config.EVM().GasEstimator() estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(config.EVM().GasEstimator(), ge.BlockHistory(), lggr), ge.EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, keyStore, estimator) - txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient, keyStore) + txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient) ethBroadcaster := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), config.Database().Listener(), keyStore, eb, txBuilder, txNonceSyncer, lggr, checkerFactory, nonceAutoSync) // Mark instance as test @@ -89,10 +90,10 @@ func TestEthBroadcaster_Lifecycle(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) estimator := gasmocks.NewEvmFeeEstimator(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) - + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) eb := txmgr.NewEvmBroadcaster( txStore, txmgr.NewEvmTxmClient(ethClient), @@ -145,12 +146,15 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) checkerFactory := &txmgr.CheckerFactory{Client: ethClient} + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, otherAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false) toAddress := gethCommon.HexToAddress("0x6C03DDA95a2AEd917EeCc6eddD4b9D16E6380411") @@ -170,7 +174,6 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { }) t.Run("eth_txes exist for a different from address", func(t *testing.T) { - _, otherAddress := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) cltest.MustCreateUnstartedTx(t, txStore, otherAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) assert.NoError(t, err) @@ -351,11 +354,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { c.EVM[0].GasEstimator.PriceMax = assets.NewWeiI(rnd + 2) }) evmcfg = evmtest.NewChainScopedConfig(t, cfg) + ethClient.On("PendingNonceAt", mock.Anything, otherAddress).Return(uint64(1), nil).Once() eb = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false) t.Run("sends transactions with type 0x2 in EIP-1559 mode", func(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { - return tx.Nonce() == uint64(3) && tx.Value().Cmp(big.NewInt(242)) == 0 + return tx.Nonce() == uint64(343) && tx.Value().Cmp(big.NewInt(242)) == 0 }), fromAddress).Return(clienttypes.Successful, nil).Once() etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, []byte{42, 42, 0}, gasLimit, big.Int(assets.NewEthValue(242)), &cltest.FixtureChainID) @@ -374,7 +378,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { require.NotNil(t, etx.FromAddress) assert.Equal(t, fromAddress, etx.FromAddress) require.NotNil(t, etx.Sequence) - assert.Equal(t, evmtypes.Nonce(3), *etx.Sequence) + assert.Equal(t, evmtypes.Nonce(343), *etx.Sequence) assert.NotNil(t, etx.BroadcastAt) assert.NotNil(t, etx.InitialBroadcastAt) assert.Len(t, etx.TxAttempts, 1) @@ -406,7 +410,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { }, } ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { - return tx.Nonce() == uint64(4) && tx.Value().Cmp(big.NewInt(442)) == 0 + return tx.Nonce() == uint64(344) && tx.Value().Cmp(big.NewInt(442)) == 0 }), fromAddress).Return(clienttypes.Successful, nil).Once() ethClient.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", mock.MatchedBy(func(callarg map[string]interface{}) bool { if fmt.Sprintf("%s", callarg["value"]) == "0x1ba" { // 442 @@ -439,7 +443,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { t.Run("with unknown error, sends tx as normal", func(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { - return tx.Nonce() == uint64(5) && tx.Value().Cmp(big.NewInt(542)) == 0 + return tx.Nonce() == uint64(345) && tx.Value().Cmp(big.NewInt(542)) == 0 }), fromAddress).Return(clienttypes.Successful, nil).Once() ethClient.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", mock.MatchedBy(func(callarg map[string]interface{}) bool { return fmt.Sprintf("%s", callarg["value"]) == "0x21e" // 542 @@ -493,12 +497,12 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) checkerFactory := &testCheckerFactory{} - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false) checker := txmgr.TransmitCheckerSpec{ @@ -573,12 +577,15 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testing.T) { // non-transactional DB needed because we deliberately test for FK violation cfg, db := heavyweight.FullTestDBV2(t, "eth_broadcaster_optimistic_locking", nil) + eventBroadcaster := cltest.NewEventBroadcaster(t, cfg.Database().URL()) + require.NoError(t, eventBroadcaster.Start(testutils.Context(t))) + t.Cleanup(func() { assert.NoError(t, eventBroadcaster.Close()) }) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ccfg := evmtest.NewChainScopedConfig(t, cfg) evmcfg := txmgr.NewEvmTxmConfig(ccfg.EVM()) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) estimator := gasmocks.NewEvmFeeEstimator(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ccfg.EVM().GasEstimator(), ethKeyStore, estimator) @@ -588,8 +595,8 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi estimator.On("GetFee", mock.Anything, mock.Anything, mock.Anything, ccfg.EVM().GasEstimator().PriceMaxKey(fromAddress)).Return(gas.EvmFee{Legacy: assets.GWei(32)}, uint32(500), nil).Run(func(_ mock.Arguments) { close(chStartEstimate) <-chBlock - }) - + }).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil) eb := txmgr.NewEvmBroadcaster( txStore, txmgr.NewEvmTxmClient(ethClient), @@ -598,7 +605,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi ccfg.EVM().Transactions(), cfg.Database().Listener(), ethKeyStore, - &pg.NullEventBroadcaster{}, + eventBroadcaster, txBuilder, nil, logger.TestLogger(t), @@ -607,6 +614,10 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi ) eb.XXXTestDisableUnstartedTxAutoProcessing() + // Start instance of broadcaster + require.NoError(t, eb.Start(testutils.Context(t))) + t.Cleanup(func() { assert.NoError(t, eb.Close()) }) + cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) go func() { @@ -619,7 +630,6 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi // Simulate a "PruneQueue" call assert.NoError(t, utils.JustError(db.Exec(`DELETE FROM evm.txes WHERE state = 'unstarted'`))) - close(chBlock) }() @@ -640,12 +650,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success_WithMultiplier(t *testing txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -687,7 +697,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, nextNonce) + _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) firstInProgress := txmgr.Tx{ FromAddress: fromAddress, @@ -722,10 +732,10 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, nextNonce) + _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) // Crashed right after we commit the database transaction that saved @@ -760,15 +770,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, nextNonce) + _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - // Crashed right after we commit the database transaction that saved - // the nonce to the eth_tx so keys.next_nonce has not been - // incremented yet + // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -798,15 +806,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, nextNonce) + _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - // Crashed right after we commit the database transaction that saved - // the nonce to the eth_tx so keys.next_nonce has not been - // incremented yet + // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -835,15 +841,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, nextNonce) + _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - // Crashed right after we commit the database transaction that saved - // the nonce to the eth_tx so keys.next_nonce has not been - // incremented yet + // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -874,15 +878,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, nextNonce) + _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - // Crashed right after we commit the database transaction that saved - // the nonce to the eth_tx so keys.next_nonce has not been - // incremented yet + // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -911,7 +913,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, nextNonce) + _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { // Configured gas price changed @@ -920,12 +922,10 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - // Crashed right after we commit the database transaction that saved - // the nonce to the eth_tx so keys.next_nonce has not been - // incremented yet + // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) require.Len(t, inProgressEthTx.TxAttempts, 1) attempt := inProgressEthTx.TxAttempts[0] @@ -960,8 +960,8 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { }) } -func getLocalNextNonce(t *testing.T, kst keystore.Eth, fromAddress gethCommon.Address) uint64 { - n, err := kst.NextSequence(fromAddress, &cltest.FixtureChainID) +func getLocalNextNonce(t *testing.T, eb *txmgr.Broadcaster, fromAddress gethCommon.Address) uint64 { + n, err := eb.GetNextSequence(fromAddress) require.NoError(t, err) require.NotNil(t, n) return uint64(n) @@ -982,11 +982,11 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) require.NoError(t, utils.JustError(db.Exec(`SET CONSTRAINTS pipeline_runs_pipeline_spec_id_fkey DEFERRED`))) @@ -1021,7 +1021,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.Len(t, etx1.TxAttempts, 1) // Check that the local nonce was incremented by one - finalNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + finalNextNonce := getLocalNextNonce(t, eb, fromAddress) require.NoError(t, err) require.NotNil(t, finalNextNonce) require.Equal(t, int64(1), int64(finalNextNonce)) @@ -1029,7 +1029,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("geth Client returns an error in the fatal errors category", func(t *testing.T) { fatalErrorExample := "exceeds block gas limit" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) t.Run("without callback", func(t *testing.T) { etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) @@ -1055,12 +1055,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.Len(t, etx.TxAttempts, 0) // Check that the key had its nonce reset - var nonce int64 - err = db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) + var nonce evmtypes.Nonce + nonce, err = eb.GetNextSequence(fromAddress) require.NoError(t, err) // Saved NextNonce must be the same as before because this transaction // was not accepted by the eth node and never can be - require.Equal(t, int64(localNextNonce), nonce) + require.Equal(t, int64(localNextNonce), int64(nonce)) }) @@ -1125,9 +1125,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { lggr := logger.TestLogger(t) estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr), evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) - eb = txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), evmcfg.Database().Listener(), ethKeyStore, eventBroadcaster, txBuilder, nil, lggr, &testCheckerFactory{}, false) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(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, eventBroadcaster, txBuilder, nil, lggr, &testCheckerFactory{}, false) + require.NoError(t, err) { - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + retryable, err := eb2.ProcessUnstartedTxs(testutils.Context(t), fromAddress) assert.NoError(t, err) assert.False(t, retryable) } @@ -1140,7 +1143,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("geth Client fails with error indicating that the transaction was too expensive", func(t *testing.T) { TxFeeExceedsCapError := "tx fee (1.10 ether) exceeds the configured cap (1.00 ether)" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) etx := cltest.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() == localNextNonce @@ -1149,7 +1152,6 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // of multiple RPC nodes, it is possible that it can be accepted by // another node even if the primary one returns "exceeds the configured // cap" - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() { retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -1172,15 +1174,15 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.Equal(t, txmgrtypes.TxAttemptInProgress, attempt.State) // Check that the key had its nonce reset - var nonce int64 - err = db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) + var nonce evmtypes.Nonce + nonce, err = eb.GetNextSequence(fromAddress) require.NoError(t, err) // Saved NextNonce must be the same as before because this transaction // was not accepted by the eth node and never can be - require.Equal(t, int64(localNextNonce), nonce) + 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(localNextNonce+1, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce+1), nil).Once() { retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -1203,13 +1205,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("eth Client call fails with an unexpected random error, and transaction was not accepted into mempool", func(t *testing.T) { retryableErrorExample := "some unknown error" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) etx := cltest.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() == localNextNonce + return tx.Nonce() == uint64(localNextNonce) }), fromAddress).Return(clienttypes.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(localNextNonce, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() // Do the thing retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -1257,10 +1259,10 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("eth client call fails with an unexpected random error, and the nonce check also subsequently fails", func(t *testing.T) { retryableErrorExample := "some unknown error" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) etx := cltest.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() == localNextNonce + return tx.Nonce() == uint64(localNextNonce) }), fromAddress).Return(clienttypes.Unknown, errors.New(retryableErrorExample)).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), errors.New("pending nonce fetch failed")).Once() @@ -1311,13 +1313,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("eth Client call fails with an unexpected random error, and transaction was accepted into mempool", func(t *testing.T) { retryableErrorExample := "some strange RPC returns an unexpected thing" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) etx := cltest.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() == localNextNonce }), fromAddress).Return(clienttypes.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(localNextNonce+1, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce+1), nil).Once() // Do the thing retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -1343,7 +1345,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // configured for the transaction pool. // This is a configuration error by the node operator, since it means they set the base gas level too low. underpricedError := "transaction underpriced" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) // First was underpriced @@ -1393,7 +1395,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("failed to reach node for some reason", func(t *testing.T) { failedToReachNodeError := context.DeadlineExceeded - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce @@ -1422,7 +1424,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // This happens if parity is rejecting transactions that are not priced high enough to even get into the mempool at all // It should pretend it was accepted into the mempool and hand off to ethConfirmer to bump gas as normal temporarilyUnderpricedError := "There are too many transactions in the queue. Your transaction was dropped due to limit. Try increasing the fee." - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) // Re-use the previously unfinished transaction, no need to insert new @@ -1455,7 +1457,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // configured for the transaction pool. // This is a configuration error by the node operator, since it means they set the base gas level too low. underpricedError := "transaction underpriced" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) // In this scenario the node operator REALLY fucked up and set the bump // to zero (even though that should not be possible due to config // validation) @@ -1463,6 +1465,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() eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) @@ -1483,7 +1486,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("eth tx is left in progress if eth node returns insufficient eth", func(t *testing.T) { insufficientEthError := "insufficient funds for transfer" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) etx := cltest.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() == localNextNonce @@ -1512,7 +1515,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { pgtest.MustExec(t, db, `DELETE FROM evm.txes`) t.Run("eth tx is left in progress if nonce is too high", func(t *testing.T) { - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) nonceGapError := "NonceGap, Future nonce. Expected nonce: " + strconv.FormatUint(localNextNonce, 10) etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -1553,10 +1556,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.BumpMin = assets.NewWeiI(0) c.EVM[0].GasEstimator.BumpPercent = ptr[uint16](0) })) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) underpricedError := "transaction underpriced" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce = getLocalNextNonce(t, eb, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce && tx.GasTipCap().Cmp(big.NewInt(1)) == 0 }), fromAddress).Return(clienttypes.Underpriced, errors.New(underpricedError)).Once() @@ -1575,7 +1580,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // configured for the transaction pool. // This is a configuration error by the node operator, since it means they set the base gas level too low. underpricedError := "transaction underpriced" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) // Check gas tip cap verification @@ -1583,6 +1588,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) c.EVM[0].GasEstimator.TipCapDefault = assets.NewWeiI(0) })) + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) retryable, err := eb2.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -1596,6 +1602,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) c.EVM[0].GasEstimator.TipCapDefault = gasTipCapDefault })) + localNextNonce = getLocalNextNonce(t, eb, fromAddress) eb2 = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) // Second was underpriced but above minimum @@ -1640,11 +1647,11 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { kst := ksmocks.NewEth(t) addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil) - next, err := realKeystore.Eth().NextSequence(fromAddress, testutils.FixtureChainID) - require.NoError(t, err) - kst.On("NextSequence", fromAddress, testutils.FixtureChainID, mock.Anything).Return(next, nil).Once() + kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false) + _, err := eb.GetNextSequence(fromAddress) + require.NoError(t, err) t.Run("tx signing fails", func(t *testing.T) { etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) @@ -1670,21 +1677,27 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { assert.Len(t, etx.TxAttempts, 0) // Check that the key did not have its nonce incremented - var nonce int64 - err = db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) + var nonce types.Nonce + nonce, err = eb.GetNextSequence(fromAddress) require.NoError(t, err) - require.Equal(t, int64(localNonce), nonce) + require.Equal(t, int64(localNonce), int64(nonce)) }) } func TestEthBroadcaster_GetNextNonce(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + fromAddress := testutils.NewAddress() + evmcfg := evmtest.NewChainScopedConfig(t, cfg) + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - keyState, _ := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) - - nonce := getLocalNextNonce(t, ethKeyStore, keyState.Address.Address()) + kst := ksmocks.NewEth(t) + addresses := []gethCommon.Address{fromAddress} + kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() + eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false) + nonce := getLocalNextNonce(t, eb, fromAddress) require.NotNil(t, nonce) assert.Equal(t, int64(0), int64(nonce)) } @@ -1692,20 +1705,25 @@ func TestEthBroadcaster_GetNextNonce(t *testing.T) { func TestEthBroadcaster_IncrementNextNonce(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + kst := ksmocks.NewEth(t) + fromAddress := testutils.NewAddress() + evmcfg := evmtest.NewChainScopedConfig(t, cfg) + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - keyState, _ := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) - - // Cannot increment if supplied nonce doesn't match existing - require.Error(t, ethKeyStore.IncrementNextSequence(keyState.Address.Address(), &cltest.FixtureChainID, evmtypes.Nonce(42))) + addresses := []gethCommon.Address{fromAddress} + kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() + eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false) - require.NoError(t, ethKeyStore.IncrementNextSequence(keyState.Address.Address(), &cltest.FixtureChainID, evmtypes.Nonce(0))) + nonce, err := eb.GetNextSequence(fromAddress) + require.NoError(t, err) + eb.IncrementNextSequence(fromAddress, nonce) // Nonce bumped to 1 - var nonce int64 - err := db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, keyState.Address.Address()) + nonce, err = eb.GetNextSequence(fromAddress) require.NoError(t, err) - require.Equal(t, int64(1), nonce) + require.Equal(t, int64(1), int64(nonce)) } func TestEthBroadcaster_Trigger(t *testing.T) { @@ -1733,7 +1751,7 @@ func TestEthBroadcaster_EthTxInsertEventCausesTriggerToFire(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) eventBroadcaster := cltest.NewEventBroadcaster(t, evmcfg.Database().URL()) require.NoError(t, eventBroadcaster.Start(testutils.Context(t))) t.Cleanup(func() { require.NoError(t, eventBroadcaster.Close()) }) @@ -1761,8 +1779,8 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) kst := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, kst, true) - _, disabledAddress := cltest.MustInsertRandomKeyReturningState(t, kst, false) + _, fromAddress := cltest.RandomKey{Disabled: false}.MustInsertWithState(t, kst) + _, disabledAddress := cltest.RandomKey{Disabled: true}.MustInsertWithState(t, kst) ethNodeNonce := uint64(22) @@ -1780,6 +1798,10 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, estimator) + kst := ksmocks.NewEth(t) + addresses := []gethCommon.Address{fromAddress} + kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, eventBroadcaster, txBuilder, nil, lggr, checkerFactory, false) err := eb.Start(testutils.Context(t)) assert.NoError(t, err) @@ -1789,68 +1811,208 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { testutils.WaitForLogMessage(t, observed, "Skipping sequence auto-sync") }) - t.Run("when eth node returns nonce, successfully sets nonce", func(t *testing.T) { + t.Run("when nonce syncer returns new nonce, successfully sets nonce", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, estimator) - txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient, kst) + txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient) + kst := ksmocks.NewEth(t) + addresses := []gethCommon.Address{fromAddress} + kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, eventBroadcaster, txBuilder, txNonceSyncer, lggr, checkerFactory, true) - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(account gethCommon.Address) bool { - return account.Hex() == fromAddress.Hex() - })).Return(ethNodeNonce, nil).Once() - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(ethNodeNonce), nil).Once() require.NoError(t, eb.Start(ctx)) defer func() { assert.NoError(t, eb.Close()) }() - testutils.WaitForLogMessage(t, observed, "Fast-forwarded nonce") + testutils.WaitForLogMessage(t, observed, "Fast-forward sequence") - // Check keyState to make sure it has correct nonce assigned - var nonce int64 - err := db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) + // Check nextSequenceMap to make sure it has correct nonce assigned + nonce, err := eb.GetNextSequence(fromAddress) require.NoError(t, err) - assert.Equal(t, int64(ethNodeNonce), nonce) + assert.Equal(t, strconv.FormatUint(ethNodeNonce, 10), nonce.String()) // The disabled key did not get updated - err = db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, disabledAddress) - require.NoError(t, err) - assert.Equal(t, int64(0), nonce) + _, err = eb.GetNextSequence(disabledAddress) + require.Error(t, err) }) ethNodeNonce++ observed.TakeAll() - t.Run("when eth node returns error, retries and successfully sets nonce", func(t *testing.T) { + t.Run("when nonce syncer returns error, retries and successfully sets nonce", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, estimator) - txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient, kst) + txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient) + + kst := ksmocks.NewEth(t) + addresses := []gethCommon.Address{fromAddress} + kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() + eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, eventBroadcaster, txBuilder, txNonceSyncer, lggr, checkerFactory, true) eb.XXXTestDisableUnstartedTxAutoProcessing() - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(account gethCommon.Address) bool { - return account.Hex() == fromAddress.Hex() - })).Return(uint64(0), errors.New("something exploded")).Once() - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(account gethCommon.Address) bool { - return account.Hex() == fromAddress.Hex() - })).Return(ethNodeNonce, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), errors.New("something exploded")).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(ethNodeNonce, nil) require.NoError(t, eb.Start(ctx)) defer func() { assert.NoError(t, eb.Close()) }() - testutils.WaitForLogMessage(t, observed, "Fast-forwarded nonce") + testutils.WaitForLogMessage(t, observed, "Fast-forward sequence") // Check keyState to make sure it has correct nonce assigned - var nonce int64 - err := db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) + nonce, err := eb.GetNextSequence(fromAddress) require.NoError(t, err) - assert.Equal(t, int64(ethNodeNonce), nonce) + assert.Equal(t, int64(ethNodeNonce), int64(nonce)) // The disabled key did not get updated - err = db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, disabledAddress) + _, err = eb.GetNextSequence(disabledAddress) + require.Error(t, err) + }) + +} + +func Test_LoadSequenceMap(t *testing.T) { + t.Parallel() + t.Run("set next nonce using entries from tx table", func(t *testing.T) { + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + evmcfg := evmtest.NewChainScopedConfig(t, cfg) + checkerFactory := &txmgr.CheckerFactory{Client: ethClient} + _, fromAddress := cltest.MustInsertRandomKey(t, ks) + cltest.MustInsertUnconfirmedEthTx(t, txStore, int64(0), fromAddress) + cltest.MustInsertUnconfirmedEthTx(t, txStore, int64(1), fromAddress) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) + + nonce, err := eb.GetNextSequence(fromAddress) require.NoError(t, err) - assert.Equal(t, int64(0), nonce) + assert.Equal(t, int64(2), int64(nonce)) }) + t.Run("set next nonce using client when not found in tx table", func(t *testing.T) { + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + evmcfg := evmtest.NewChainScopedConfig(t, cfg) + checkerFactory := &txmgr.CheckerFactory{Client: ethClient} + _, fromAddress := cltest.MustInsertRandomKey(t, ks) + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(10), nil).Once() + eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) + + nonce, err := eb.GetNextSequence(fromAddress) + require.NoError(t, err) + assert.Equal(t, int64(10), int64(nonce)) + }) +} + +func Test_NextNonce(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + evmcfg := evmtest.NewChainScopedConfig(t, cfg) + checkerFactory := &txmgr.CheckerFactory{Client: ethClient} + randNonce := testutils.NewRandomPositiveInt64() + _, addr1 := cltest.MustInsertRandomKey(t, ks) + ethClient.On("PendingNonceAt", mock.Anything, addr1).Return(uint64(randNonce), nil).Once() + eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) + + cltest.MustInsertRandomKey(t, ks, *utils.NewBig(testutils.FixtureChainID)) + + nonce, err := eb.GetNextSequence(addr1) + require.NoError(t, err) + assert.Equal(t, randNonce, int64(nonce)) + + randAddr1 := utils.RandomAddress() + _, err = eb.GetNextSequence(randAddr1) + require.Error(t, err) + assert.Contains(t, err.Error(), fmt.Sprintf("address not found in next sequence map: %s", randAddr1.Hex())) + + randAddr2 := utils.RandomAddress() + _, err = eb.GetNextSequence(randAddr2) + require.Error(t, err) + assert.Contains(t, err.Error(), fmt.Sprintf("address not found in next sequence map: %s", randAddr2.Hex())) + +} + +func Test_IncrementNextNonce(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + evmcfg := evmtest.NewChainScopedConfig(t, cfg) + checkerFactory := &txmgr.CheckerFactory{Client: ethClient} + randNonce := testutils.NewRandomPositiveInt64() + _, addr1 := cltest.MustInsertRandomKey(t, ks) + ethClient.On("PendingNonceAt", mock.Anything, addr1).Return(uint64(randNonce), nil).Once() + eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) + + nonce, err := eb.GetNextSequence(addr1) + require.NoError(t, err) + eb.IncrementNextSequence(addr1, nonce) + + nonce, err = eb.GetNextSequence(addr1) + require.NoError(t, err) + assert.Equal(t, randNonce+1, int64(nonce)) + + eb.IncrementNextSequence(addr1, nonce) + nonce, err = eb.GetNextSequence(addr1) + require.NoError(t, err) + assert.Equal(t, randNonce+2, int64(nonce)) + + randAddr1 := utils.RandomAddress() + _, err = eb.GetNextSequence(randAddr1) + require.Error(t, err) + assert.Contains(t, err.Error(), fmt.Sprintf("address not found in next sequence map: %s", randAddr1.Hex())) + + // verify it didnt get changed by any erroring calls + nonce, err = eb.GetNextSequence(addr1) + require.NoError(t, err) + assert.Equal(t, randNonce+2, int64(nonce)) +} + +func Test_SetNextNonce(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + evmcfg := evmtest.NewChainScopedConfig(t, cfg) + checkerFactory := &txmgr.CheckerFactory{Client: ethClient} + _, fromAddress := cltest.MustInsertRandomKey(t, ks) + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() + eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) + + t.Run("update next nonce", func(t *testing.T) { + nonce, err := eb.GetNextSequence(fromAddress) + require.NoError(t, err) + assert.Equal(t, int64(0), int64(nonce)) + eb.SetNextSequence(fromAddress, evmtypes.Nonce(24)) + + newNextNonce, err := eb.GetNextSequence(fromAddress) + require.NoError(t, err) + assert.Equal(t, int64(24), int64(newNextNonce)) + }) } type testCheckerFactory struct { diff --git a/core/chains/evm/txmgr/builder.go b/core/chains/evm/txmgr/builder.go index 464cf6f9c59..39781e83f4c 100644 --- a/core/chains/evm/txmgr/builder.go +++ b/core/chains/evm/txmgr/builder.go @@ -47,7 +47,7 @@ func NewTxm( // create tx attempt builder txAttemptBuilder := NewEvmTxAttemptBuilder(*client.ConfiguredChainID(), fCfg, keyStore, estimator) txStore := NewTxStore(db, lggr, dbConfig) - txNonceSyncer := NewNonceSyncer(txStore, lggr, client, keyStore) + txNonceSyncer := NewNonceSyncer(txStore, lggr, client) txmCfg := NewEvmTxmConfig(chainConfig) // wrap Evm specific config feeCfg := NewEvmTxmFeeConfig(fCfg) // wrap Evm specific config @@ -130,5 +130,5 @@ func NewEvmBroadcaster( checkerFactory TransmitCheckerFactory, autoSyncNonce bool, ) *Broadcaster { - return txmgr.NewBroadcaster(txStore, client, chainConfig, feeConfig, txConfig, listenerConfig, keystore, eventBroadcaster, txAttemptBuilder, nonceSyncer, logger, checkerFactory, autoSyncNonce, stringToGethAddress) + return txmgr.NewBroadcaster(txStore, client, chainConfig, feeConfig, txConfig, listenerConfig, keystore, eventBroadcaster, txAttemptBuilder, nonceSyncer, logger, checkerFactory, autoSyncNonce, stringToGethAddress, evmtypes.GenerateNextNonce) } diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index e0070e35b17..0a7b2b117b2 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -117,8 +117,8 @@ func TestEthConfirmer_Lifecycle(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() // Add some fromAddresses - cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) - cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + cltest.MustInsertRandomKey(t, ethKeyStore) + cltest.MustInsertRandomKey(t, ethKeyStore) estimator := gasmocks.NewEvmEstimator(t) lggr := logger.TestLogger(t) ge := config.EVM().GasEstimator() @@ -185,10 +185,9 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() - _, fromAddress := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) nonce := int64(0) ctx := testutils.Context(t) @@ -599,15 +598,13 @@ func TestEthConfirmer_CheckForReceipts_batching(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) - + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 0, fromAddress) @@ -666,9 +663,8 @@ func TestEthConfirmer_CheckForReceipts_HandlesNonFwdTxsWithForwardingEnabled(t * ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // tx is not forwarded and doesn't have meta set. EthConfirmer should handle nil meta values etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 0, fromAddress) @@ -715,15 +711,13 @@ func TestEthConfirmer_CheckForReceipts_only_likely_confirmed(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) - + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) var attempts []txmgr.TxAttempt @@ -773,13 +767,11 @@ func TestEthConfirmer_CheckForReceipts_should_not_check_for_likely_unconfirmed(t ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) - + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ctx := testutils.Context(t) etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 1, fromAddress) @@ -801,18 +793,16 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt_scoped_to_key(t cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - chainId1, chainId2 := 1, 2 - _, fromAddress1_1 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, chainId1) - _, fromAddress1_2 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, chainId1) - _, fromAddress2_1 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, chainId2) + _, fromAddress1_1 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + _, fromAddress1_2 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + _, fromAddress2_1 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("SequenceAt", mock.Anything, mock.Anything, mock.Anything).Return(evmtypes.Nonce(20), nil) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -873,15 +863,13 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) - + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -961,7 +949,8 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { // Expected state is that the "top" eth_tx is now confirmed, with the // two below it "confirmed_missing_receipt" and the "bottom" eth_tx also confirmed - etx3, err := txStore.FindTxWithAttempts(etx3.ID) + var err error + etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx3.State) @@ -1021,7 +1010,8 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { // Expected state is that the "top" two eth_txes are now confirmed, with the // one below it still "confirmed_missing_receipt" and the bottom one remains confirmed - etx3, err := txStore.FindTxWithAttempts(etx3.ID) + var err error + etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx3.State) etx2, err = txStore.FindTxWithAttempts(etx2.ID) @@ -1065,7 +1055,8 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { // Expected state is that the "top" two eth_txes are now confirmed, with the // one below it still "confirmed_missing_receipt" and the bottom one remains confirmed - etx3, err := txStore.FindTxWithAttempts(etx3.ID) + var err error + etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx3.State) etx2, err = txStore.FindTxWithAttempts(etx2.ID) @@ -1105,7 +1096,8 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { // Expected state is that the "top" two eth_txes are now confirmed, with the // one below it marked as "fatal_error" and the bottom one remains confirmed - etx3, err := txStore.FindTxWithAttempts(etx3.ID) + var err error + etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx3.State) etx2, err = txStore.FindTxWithAttempts(etx2.ID) @@ -1131,15 +1123,13 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) - + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -1182,6 +1172,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt(t *testing.T) { // Expected state is that the "top" eth_tx is untouched but the other two // are marked as unconfirmed + var err error etx0, err = txStore.FindTxWithAttempts(etx0.ID) assert.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, etx0.State) @@ -1211,15 +1202,13 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_batchSendTransactions_fails(t ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) - + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -1250,6 +1239,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_batchSendTransactions_fails(t require.NoError(t, ec.CheckConfirmedMissingReceipt(ctx)) // Expected state is that all txes are marked as unconfirmed, since the batch call had failed + var err error etx0, err = txStore.FindTxWithAttempts(etx0.ID) assert.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx0.State) @@ -1276,15 +1266,13 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_smallEvmRPCBatchSize_middleBa ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) - + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -1321,6 +1309,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_smallEvmRPCBatchSize_middleBa require.NoError(t, ec.CheckConfirmedMissingReceipt(ctx)) // Expected state is that all transactions since failed batch will be unconfirmed + var err error etx0, err = txStore.FindTxWithAttempts(etx0.ID) assert.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, etx0.State) @@ -1348,7 +1337,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) evmFromAddress := fromAddress currentHead := int64(30) gasBumpThreshold := int64(10) @@ -1360,13 +1349,12 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { mustInsertConfirmedEthTx(t, txStore, nonce, fromAddress) nonce++ - _, otherAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, otherAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) evmOtherAddress := otherAddress lggr := logger.TestLogger(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) t.Run("returns nothing when there are no transactions", func(t *testing.T) { etxs, err := ec.FindTxsRequiringRebroadcast(testutils.Context(t), lggr, evmFromAddress, currentHead, gasBumpThreshold, 10, 0, &cltest.FixtureChainID) @@ -1747,8 +1735,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Maybe() // Use a mock keystore for this test - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) currentHead := int64(30) oldEnough := int64(19) nonce := int64(0) @@ -1773,7 +1760,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { mock.Anything).Return(nil, errors.New("signing error")).Once() // Do the thing - err = ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead) + err := ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead) require.Error(t, err) require.Contains(t, err.Error(), "signing error") @@ -1804,7 +1791,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) @@ -1836,7 +1823,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) @@ -1875,7 +1862,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) @@ -1891,7 +1878,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Run("does nothing if there is an attempt without BroadcastBeforeBlockNum set", func(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) @@ -1921,7 +1908,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) @@ -1961,7 +1948,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) @@ -2012,7 +1999,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { }), fromAddress).Return(clienttypes.Unknown, errors.New("some network error")).Once() // Do the thing - err = ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead) + err := ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead) require.Error(t, err) require.Contains(t, err.Error(), "some network error") @@ -2080,6 +2067,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Creates new attempt as normal if currentHead is not high enough require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) + var err error etx2, err = txStore.FindTxWithAttempts(etx2.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, etx2.State) @@ -2120,7 +2108,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) @@ -2157,7 +2145,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) @@ -2196,7 +2184,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) @@ -2217,8 +2205,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { c.EVM[0].GasEstimator.PriceMax = assets.NewWeiI(60500000000) }) newCfg := evmtest.NewChainScopedConfig(t, gcfg) - ec2, err := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) - require.NoError(t, err) + ec2 := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx3.Sequence && gasPrice.Cmp(tx.GasPrice()) == 0 @@ -2226,7 +2213,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec2.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) @@ -2248,8 +2235,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { c.EVM[0].GasEstimator.PriceMax = assets.NewWeiI(60480000000) }) newCfg := evmtest.NewChainScopedConfig(t, gcfg) - ec2, err := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) - require.NoError(t, err) + ec2 := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx3.Sequence && gasPrice.Cmp(tx.GasPrice()) == 0 @@ -2257,7 +2243,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec2.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) @@ -2294,7 +2280,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { return evmtypes.Nonce(tx.Nonce()) == *etx4.Sequence && gasTipCap.ToInt().Cmp(tx.GasTipCap()) == 0 }), fromAddress).Return(clienttypes.Successful, nil).Once() require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx4, err = txStore.FindTxWithAttempts(etx4.ID) require.NoError(t, err) @@ -2317,8 +2303,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { c.EVM[0].GasEstimator.PriceMax = assets.GWei(1000) }) newCfg := evmtest.NewChainScopedConfig(t, gcfg) - ec2, err := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) - require.NoError(t, err) + ec2 := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) // Third attempt failed to bump, resubmits old one instead ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { @@ -2326,7 +2311,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { }), fromAddress).Return(clienttypes.Successful, nil).Once() require.NoError(t, ec2.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx4, err = txStore.FindTxWithAttempts(etx4.ID) require.NoError(t, err) @@ -2364,7 +2349,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do it require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx4, err = txStore.FindTxWithAttempts(etx4.ID) require.NoError(t, err) @@ -2405,8 +2390,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh t.Run("terminally underpriced transaction with in_progress attempt is retried with more gas", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) originalBroadcastAt := time.Unix(1616509100, 0) etx := cltest.MustInsertUnconfirmedEthTxWithAttemptState(t, txStore, nonce, fromAddress, txmgrtypes.TxAttemptInProgress, originalBroadcastAt) @@ -2432,8 +2416,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh t.Run("multiple gas bumps with existing broadcast attempts are retried with more gas until success in legacy mode", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, nonce, fromAddress) nonce++ @@ -2465,8 +2448,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh t.Run("multiple gas bumps with existing broadcast attempts are retried with more gas until success in EIP-1559 mode", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, nonce, fromAddress) nonce++ @@ -2507,7 +2489,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) _, err := ethKeyStore.EnabledKeysForChain(testutils.FixtureChainID) require.NoError(t, err) @@ -2531,8 +2513,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { insufficientEthError := errors.New("insufficient funds for gas * price + value") t.Run("saves attempt with state 'insufficient_eth' if eth node returns this error", func(t *testing.T) { - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) expectedBumpedGasPrice := big.NewInt(20000000000) require.Greater(t, expectedBumpedGasPrice.Int64(), attempt1_1.TxFee.Legacy.ToInt().Int64()) @@ -2558,8 +2539,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { }) t.Run("does not bump gas when previous error was 'out of eth', instead resubmits existing transaction", func(t *testing.T) { - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) expectedBumpedGasPrice := big.NewInt(20000000000) require.Greater(t, expectedBumpedGasPrice.Int64(), attempt1_1.TxFee.Legacy.ToInt().Int64()) @@ -2584,8 +2564,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { }) t.Run("saves the attempt as broadcast after node wallet has been topped up with sufficient balance", func(t *testing.T) { - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) expectedBumpedGasPrice := big.NewInt(20000000000) require.Greater(t, expectedBumpedGasPrice.Int64(), attempt1_1.TxFee.Legacy.ToInt().Int64()) @@ -2617,8 +2596,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { c.EVM[0].GasEstimator.BumpTxDepth = ptr(uint32(depth)) }) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) for i := 0; i < etxCount; i++ { n := nonce @@ -2648,13 +2626,12 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) config := newTestChainScopedConfig(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) head := evmtypes.Head{ Hash: utils.NewHash(), @@ -2822,7 +2799,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) config := newTestChainScopedConfig(t) cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, config.EVM().ChainID()) @@ -2835,8 +2812,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("rebroadcasts one eth_tx if it falls within in nonce range", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx1.Sequence) && @@ -2851,8 +2827,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("uses default gas limit if overrideGasLimit is 0", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx1.Sequence) && @@ -2867,8 +2842,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("rebroadcasts several eth_txes in nonce range", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx1.Sequence) && tx.GasPrice().Int64() == gasPriceWei.Legacy.Int64() && tx.Gas() == uint64(overrideGasLimit) @@ -2882,8 +2856,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("broadcasts zero transactions if eth_tx doesn't exist for that nonce", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(1) @@ -2909,8 +2882,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("zero transactions use default gas limit if override wasn't specified", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(0) && tx.GasPrice().Int64() == gasPriceWei.Legacy.Int64() && uint32(tx.Gas()) == config.EVM().GasEstimator().LimitDefault() @@ -2929,7 +2901,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() - _, fromAddress := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -2954,11 +2926,10 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { pgtest.MustExec(t, db, `SET CONSTRAINTS pipeline_runs_pipeline_spec_id_fkey DEFERRED`) t.Run("doesn't process task runs that are not suspended (possibly already previously resumed)", func(t *testing.T) { - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { t.Fatal("No value expected") return nil }) - require.NoError(t, err) run := cltest.MustInsertPipelineRun(t, db) tr := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run.ID) @@ -2967,17 +2938,16 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { cltest.MustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, etx.TxAttempts[0].Hash) pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) - err = ec.ResumePendingTaskRuns(testutils.Context(t), &head) + err := ec.ResumePendingTaskRuns(testutils.Context(t), &head) require.NoError(t, err) }) t.Run("doesn't process task runs where the receipt is younger than minConfirmations", func(t *testing.T) { - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { t.Fatal("No value expected") return nil }) - require.NoError(t, err) run := cltest.MustInsertPipelineRun(t, db) tr := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run.ID) @@ -2987,7 +2957,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) - err = ec.ResumePendingTaskRuns(testutils.Context(t), &head) + err := ec.ResumePendingTaskRuns(testutils.Context(t), &head) require.NoError(t, err) }) @@ -2995,12 +2965,11 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { t.Run("processes eth_txes with receipts older than minConfirmations", func(t *testing.T) { ch := make(chan interface{}) var err error - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, thisErr error) error { + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, thisErr error) error { err = thisErr ch <- value return nil }) - require.NoError(t, err) run := cltest.MustInsertPipelineRun(t, db) tr := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run.ID) @@ -3035,12 +3004,11 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { t.Run("processes eth_txes with receipt older than minConfirmations that reverted", func(t *testing.T) { ch := make(chan interface{}) var err error - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, thisErr error) error { + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, thisErr error) error { err = thisErr ch <- value return nil }) - require.NoError(t, err) run := cltest.MustInsertPipelineRun(t, db) tr := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run.ID) diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index 539c77dfee5..7b1ef8948c1 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -957,6 +957,16 @@ func (o *evmTxStore) FindReceiptsPendingConfirmation(ctx context.Context, blockN return } +func (o *evmTxStore) FindLatestSequence(ctx context.Context, fromAddress common.Address, chainId *big.Int) (nonce evmtypes.Nonce, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + sql := `SELECT nonce FROM evm.txes WHERE from_address = $1 AND evm_chain_id = $2 AND nonce IS NOT NULL ORDER BY nonce DESC LIMIT 1` + err = qq.Get(&nonce, sql, fromAddress, chainId.String()) + return +} + // FindTxWithIdempotencyKey returns any broadcast ethtx with the given idempotencyKey and chainID func (o *evmTxStore) FindTxWithIdempotencyKey(ctx context.Context, idempotencyKey string, chainID *big.Int) (etx *Tx, err error) { var cancel context.CancelFunc @@ -1413,11 +1423,12 @@ func (o *evmTxStore) UpdateTxFatalError(ctx context.Context, etx *Tx) error { } // Updates eth attempt from in_progress to broadcast. Also updates the eth tx to unconfirmed. -// Before it updates both tables though it increments the next nonce from the keystore // One of the more complicated signatures. We have to accept variable pg.QOpt and QueryerFunc arguments -func (o *evmTxStore) UpdateTxAttemptInProgressToBroadcast(etx *Tx, attempt TxAttempt, NewAttemptState txmgrtypes.TxAttemptState, incrNextNonceCallback txmgrtypes.QueryerFunc, qopts ...pg.QOpt) error { - qq := o.q.WithOpts(qopts...) - +func (o *evmTxStore) UpdateTxAttemptInProgressToBroadcast(ctx context.Context, etx *Tx, attempt TxAttempt, NewAttemptState txmgrtypes.TxAttemptState) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) if etx.BroadcastAt == nil { return errors.New("unconfirmed transaction must have broadcast_at time") } @@ -1436,9 +1447,6 @@ func (o *evmTxStore) UpdateTxAttemptInProgressToBroadcast(etx *Tx, attempt TxAtt etx.State = txmgr.TxUnconfirmed attempt.State = NewAttemptState return qq.Transaction(func(tx pg.Queryer) error { - if err := incrNextNonceCallback(tx); err != nil { - return pkgerrors.Wrap(err, "SaveEthTxAttempt failed on incrNextNonceCallback") - } var dbEtx DbEthTx dbEtx.FromTx(etx) if err := tx.Get(&dbEtx, `UPDATE evm.txes SET state=$1, error=$2, broadcast_at=$3, initial_broadcast_at=$4 WHERE id = $5 RETURNING *`, dbEtx.State, dbEtx.Error, dbEtx.BroadcastAt, dbEtx.InitialBroadcastAt, dbEtx.ID); err != nil { diff --git a/core/chains/evm/txmgr/evm_tx_store_test.go b/core/chains/evm/txmgr/evm_tx_store_test.go index cc990de1bd4..e1bf4880b2f 100644 --- a/core/chains/evm/txmgr/evm_tx_store_test.go +++ b/core/chains/evm/txmgr/evm_tx_store_test.go @@ -37,7 +37,7 @@ func TestORM_TransactionsWithAttempts(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, from := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, from := cltest.MustInsertRandomKey(t, ethKeyStore) cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) // tx1 tx2 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 1, 2, from) // tx2 @@ -82,7 +82,7 @@ func TestORM_Transactions(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, from := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, from := cltest.MustInsertRandomKey(t, ethKeyStore) cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) // tx1 tx2 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 1, 2, from) // tx2 @@ -120,7 +120,7 @@ func TestORM(t *testing.T) { cfg := configtest.NewGeneralConfig(t, nil) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) orm := cltest.NewTestTxStore(t, db, cfg.Database()) - _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth(), 0) + _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) var err error var etx txmgr.Tx @@ -191,7 +191,7 @@ func TestORM_FindTxAttemptConfirmedByTxIDs(t *testing.T) { orm := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, from := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, from := cltest.MustInsertRandomKey(t, ethKeyStore) tx1 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, orm, 0, 1, from) // tx1 tx2 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, orm, 1, 2, from) // tx2 @@ -328,7 +328,7 @@ func TestORM_UpdateBroadcastAts(t *testing.T) { cfg := configtest.NewGeneralConfig(t, nil) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) orm := cltest.NewTestTxStore(t, db, cfg.Database()) - _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth(), 0) + _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) t.Run("does not update when broadcast_at is NULL", func(t *testing.T) { t.Parallel() @@ -377,7 +377,7 @@ func TestORM_SetBroadcastBeforeBlockNum(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress) chainID := ethClient.ConfiguredChainID() @@ -445,7 +445,7 @@ func TestORM_FindTxAttemptsConfirmedMissingReceipt(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) originalBroadcastAt := time.Unix(1616509100, 0) etx0 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( @@ -467,7 +467,7 @@ func TestORM_UpdateTxsUnconfirmed(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) originalBroadcastAt := time.Unix(1616509100, 0) etx0 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( @@ -488,7 +488,7 @@ func TestORM_FindTxAttemptsRequiringReceiptFetch(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) originalBroadcastAt := time.Unix(1616509100, 0) etx0 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( @@ -509,7 +509,7 @@ func TestORM_SaveFetchedReceipts(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) originalBroadcastAt := time.Unix(1616509100, 0) etx0 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( @@ -542,7 +542,7 @@ func TestORM_MarkAllConfirmedMissingReceipt(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) // create transaction 0 (nonce 0) that is unconfirmed (block 7) @@ -572,7 +572,7 @@ func TestORM_PreloadTxes(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("loads eth transaction", func(t *testing.T) { // insert etx with attempt @@ -607,7 +607,7 @@ func TestORM_GetInProgressTxAttempts(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) // insert etx with attempt etx := cltest.MustInsertUnconfirmedEthTxWithAttemptState(t, txStore, int64(7), fromAddress, txmgrtypes.TxAttemptInProgress) @@ -628,7 +628,7 @@ func TestORM_FindReceiptsPendingConfirmation(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) pgtest.MustExec(t, db, `SET CONSTRAINTS pipeline_runs_pipeline_spec_id_fkey DEFERRED`) @@ -671,7 +671,7 @@ func Test_FindTxWithIdempotencyKey(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("returns nil if no results", func(t *testing.T) { idempotencyKey := "777" @@ -701,7 +701,7 @@ func TestORM_FindTxWithSequence(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("returns nil if no results", func(t *testing.T) { etx, err := txStore.FindTxWithSequence(testutils.Context(t), fromAddress, evmtypes.Nonce(777)) @@ -726,7 +726,7 @@ func TestORM_UpdateTxForRebroadcast(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("delete all receipts for eth transaction", func(t *testing.T) { etx := cltest.MustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 777, 1) @@ -767,7 +767,7 @@ func TestORM_FindTransactionsConfirmedInBlockRange(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) head := evmtypes.Head{ Hash: utils.NewHash(), @@ -802,7 +802,7 @@ func TestORM_SaveInsufficientEthAttempt(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) defaultDuration, err := time.ParseDuration("5s") require.NoError(t, err) @@ -826,7 +826,7 @@ func TestORM_SaveSentAttempt(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) defaultDuration, err := time.ParseDuration("5s") require.NoError(t, err) @@ -851,7 +851,7 @@ func TestORM_SaveConfirmedMissingReceiptAttempt(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) defaultDuration, err := time.ParseDuration("5s") require.NoError(t, err) @@ -876,7 +876,7 @@ func TestORM_DeleteInProgressAttempt(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("deletes in_progress attempt", func(t *testing.T) { etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 1, fromAddress) @@ -898,7 +898,7 @@ func TestORM_SaveInProgressAttempt(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("saves new in_progress attempt if attempt is new", func(t *testing.T) { etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 1, fromAddress) @@ -940,7 +940,7 @@ func TestORM_FindTxsRequiringGasBump(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) currentBlockNum := int64(10) @@ -981,8 +981,8 @@ func TestEthConfirmer_FindTxsRequiringResubmissionDueToInsufficientEth(t *testin ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) - _, otherAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + _, otherAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) // Insert order is mixed up to test sorting etx2 := cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 1, fromAddress) @@ -1041,7 +1041,7 @@ func TestORM_MarkOldTxesMissingReceiptAsErrored(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) // tx state should be confirmed missing receipt // attempt should be broadcast before cutoff time @@ -1075,7 +1075,7 @@ func TestORM_LoadEthTxesAttempts(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("load eth tx attempt", func(t *testing.T) { etx := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 1, 7, time.Now(), fromAddress) @@ -1124,7 +1124,7 @@ func TestORM_SaveReplacementInProgressAttempt(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("replace eth tx attempt", func(t *testing.T) { etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 123, fromAddress) @@ -1150,7 +1150,7 @@ func TestORM_FindNextUnstartedTransactionFromAddress(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("cannot find unstarted tx", func(t *testing.T) { cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 13, fromAddress) @@ -1176,7 +1176,7 @@ func TestORM_UpdateTxFatalError(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("update successful", func(t *testing.T) { etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 13, fromAddress) @@ -1199,7 +1199,7 @@ func TestORM_UpdateTxAttemptInProgressToBroadcast(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("update successful", func(t *testing.T) { etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 13, fromAddress) @@ -1210,12 +1210,10 @@ func TestORM_UpdateTxAttemptInProgressToBroadcast(t *testing.T) { i := int16(0) etx.BroadcastAt = &time1 etx.InitialBroadcastAt = &time1 - err := txStore.UpdateTxAttemptInProgressToBroadcast(&etx, attempt, txmgrtypes.TxAttemptBroadcast, func(_ pg.Queryer) error { - // dummy function because tests do not use keystore as source of truth for next nonce number - i++ - return nil - }) + err := txStore.UpdateTxAttemptInProgressToBroadcast(testutils.Context(t), &etx, attempt, txmgrtypes.TxAttemptBroadcast) require.NoError(t, err) + // Increment sequence + i++ attemptResult, err := txStore.FindTxAttempt(attempt.Hash) require.NoError(t, err) @@ -1232,7 +1230,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) q := pg.NewQ(db, logger.TestLogger(t), cfg.Database()) nonce := evmtypes.Nonce(123) @@ -1267,7 +1265,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { cfg = newTestChainScopedConfig(t) txStore = cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore = cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress = cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress = cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) q = pg.NewQ(db, logger.TestLogger(t), cfg.Database()) t.Run("update replaces abandoned tx with same hash", func(t *testing.T) { @@ -1300,7 +1298,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { require.NoError(t, err) }) - _, fromAddress = cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress = cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) // Same flow as previous test, but without calling txMgr.Abandon() t.Run("duplicate tx hash disallowed in tx_eth_attempts", func(t *testing.T) { @@ -1323,7 +1321,7 @@ func TestORM_GetTxInProgress(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("gets 0 in progress eth transaction", func(t *testing.T) { etxResult, err := txStore.GetTxInProgress(testutils.Context(t), fromAddress) @@ -1348,7 +1346,7 @@ func TestORM_HasInProgressTransaction(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("no in progress eth transaction", func(t *testing.T) { exists, err := txStore.HasInProgressTransaction(testutils.Context(t), fromAddress, ethClient.ConfiguredChainID()) @@ -1365,32 +1363,6 @@ func TestORM_HasInProgressTransaction(t *testing.T) { }) } -func TestORM_UpdateEthKeyNextNonce(t *testing.T) { - t.Parallel() - - db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTxStore(t, db, cfg.Database()) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyState, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) - - t.Run("update next nonce", func(t *testing.T) { - assert.Equal(t, int64(0), ethKeyState.NextNonce) - err := txStore.UpdateKeyNextSequence(evmtypes.Nonce(24), evmtypes.Nonce(0), fromAddress, ethClient.ConfiguredChainID()) - require.NoError(t, err) - - newNextNonce, err := ethKeyStore.NextSequence(fromAddress, ethClient.ConfiguredChainID()) - require.NoError(t, err) - assert.Equal(t, int64(24), newNextNonce.Int64()) - }) - - t.Run("no rows found", func(t *testing.T) { - err := txStore.UpdateKeyNextSequence(evmtypes.Nonce(100), evmtypes.Nonce(123), fromAddress, ethClient.ConfiguredChainID()) - require.Error(t, err) - }) -} - func TestORM_CountUnconfirmedTransactions(t *testing.T) { t.Parallel() @@ -1399,8 +1371,8 @@ func TestORM_CountUnconfirmedTransactions(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) - _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore) cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, otherAddress) cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress) @@ -1420,8 +1392,8 @@ func TestORM_CountUnstartedTransactions(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) - _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore) cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) @@ -1441,8 +1413,8 @@ func TestORM_CheckTxQueueCapacity(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) - _, otherAddress := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore) toAddress := testutils.NewAddress() encodedPayload := []byte{1, 2, 3} @@ -1537,7 +1509,7 @@ func TestORM_CreateTransaction(t *testing.T) { txStore := cltest.NewTxStore(t, db, cfg.Database()) kst := cltest.NewKeyStore(t, db, cfg.Database()) - _, fromAddress := cltest.MustInsertRandomKey(t, kst.Eth(), 0) + _, fromAddress := cltest.MustInsertRandomKey(t, kst.Eth()) toAddress := testutils.NewAddress() gasLimit := uint32(1000) payload := []byte{1, 2, 3} @@ -1610,7 +1582,7 @@ func TestORM_PruneUnstartedTxQueue(t *testing.T) { txStore := cltest.NewTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("does not prune if queue has not exceeded capacity", func(t *testing.T) { subject1 := uuid.New() diff --git a/core/chains/evm/txmgr/mocks/evm_tx_store.go b/core/chains/evm/txmgr/mocks/evm_tx_store.go index 8c078ba3d15..0b33be8178d 100644 --- a/core/chains/evm/txmgr/mocks/evm_tx_store.go +++ b/core/chains/evm/txmgr/mocks/evm_tx_store.go @@ -14,8 +14,6 @@ import ( mock "github.com/stretchr/testify/mock" - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - time "time" types "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -147,6 +145,30 @@ func (_m *EvmTxStore) DeleteInProgressAttempt(ctx context.Context, attempt types return r0 } +// FindLatestSequence provides a mock function with given fields: ctx, fromAddress, chainId +func (_m *EvmTxStore) FindLatestSequence(ctx context.Context, fromAddress common.Address, chainId *big.Int) (evmtypes.Nonce, error) { + ret := _m.Called(ctx, fromAddress, chainId) + + var r0 evmtypes.Nonce + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (evmtypes.Nonce, error)); ok { + return rf(ctx, fromAddress, chainId) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) evmtypes.Nonce); ok { + r0 = rf(ctx, fromAddress, chainId) + } else { + r0 = ret.Get(0).(evmtypes.Nonce) + } + + if rf, ok := ret.Get(1).(func(context.Context, common.Address, *big.Int) error); ok { + r1 = rf(ctx, fromAddress, chainId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // FindNextUnstartedTransactionFromAddress provides a mock function with given fields: ctx, etx, fromAddress, chainID func (_m *EvmTxStore) FindNextUnstartedTransactionFromAddress(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], fromAddress common.Address, chainID *big.Int) error { ret := _m.Called(ctx, etx, fromAddress, chainID) @@ -878,41 +900,13 @@ func (_m *EvmTxStore) UpdateBroadcastAts(ctx context.Context, now time.Time, etx return r0 } -// UpdateKeyNextSequence provides a mock function with given fields: newNextSequence, currentNextSequence, address, chainID, qopts -func (_m *EvmTxStore) UpdateKeyNextSequence(newNextSequence evmtypes.Nonce, currentNextSequence evmtypes.Nonce, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, newNextSequence, currentNextSequence, address, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 error - if rf, ok := ret.Get(0).(func(evmtypes.Nonce, evmtypes.Nonce, common.Address, *big.Int, ...pg.QOpt) error); ok { - r0 = rf(newNextSequence, currentNextSequence, address, chainID, qopts...) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// UpdateTxAttemptInProgressToBroadcast provides a mock function with given fields: etx, attempt, NewAttemptState, incrNextSequenceCallback, qopts -func (_m *EvmTxStore) UpdateTxAttemptInProgressToBroadcast(etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], attempt types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], NewAttemptState types.TxAttemptState, incrNextSequenceCallback func(pg.Queryer) error, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, etx, attempt, NewAttemptState, incrNextSequenceCallback) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// UpdateTxAttemptInProgressToBroadcast provides a mock function with given fields: ctx, etx, attempt, NewAttemptState +func (_m *EvmTxStore) UpdateTxAttemptInProgressToBroadcast(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], attempt types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], NewAttemptState types.TxAttemptState) error { + ret := _m.Called(ctx, etx, attempt, NewAttemptState) var r0 error - if rf, ok := ret.Get(0).(func(*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], types.TxAttemptState, func(pg.Queryer) error, ...pg.QOpt) error); ok { - r0 = rf(etx, attempt, NewAttemptState, incrNextSequenceCallback, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], types.TxAttemptState) error); ok { + r0 = rf(ctx, etx, attempt, NewAttemptState) } else { r0 = ret.Error(0) } diff --git a/core/chains/evm/txmgr/models.go b/core/chains/evm/txmgr/models.go index e87c54c2a3f..9044c52c9ae 100644 --- a/core/chains/evm/txmgr/models.go +++ b/core/chains/evm/txmgr/models.go @@ -25,7 +25,7 @@ type ( TransactionStore = txmgrtypes.TransactionStore[common.Address, *big.Int, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] KeyStore = txmgrtypes.KeyStore[common.Address, *big.Int, evmtypes.Nonce] TxAttemptBuilder = txmgrtypes.TxAttemptBuilder[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] - NonceSyncer = txmgr.SequenceSyncer[common.Address, common.Hash, common.Hash] + NonceSyncer = txmgr.SequenceSyncer[common.Address, common.Hash, common.Hash, evmtypes.Nonce] TransmitCheckerFactory = txmgr.TransmitCheckerFactory[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] Txm = txmgr.Txm[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, *evmtypes.Receipt, evmtypes.Nonce, gas.EvmFee] TxManager = txmgr.TxManager[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] diff --git a/core/chains/evm/txmgr/nonce_syncer.go b/core/chains/evm/txmgr/nonce_syncer.go index af982e062ac..dc0d27e6414 100644 --- a/core/chains/evm/txmgr/nonce_syncer.go +++ b/core/chains/evm/txmgr/nonce_syncer.go @@ -10,9 +10,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/common/txmgr" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) // NonceSyncer manages the delicate task of syncing the local nonce with the @@ -22,7 +21,7 @@ import ( // it to our local value. // // Usually the on-chain nonce will be the same as (or lower than) the -// next_nonce in the DB, in which case we do nothing. +// highest sequence in the DB, in which case we do nothing. // // If we are restoring from a backup however, or another wallet has used the // account, the chain nonce might be higher than our local one. In this @@ -47,14 +46,13 @@ import ( // // This gives us re-org protection up to EVM.FinalityDepth deep in the // worst case, which is in line with our other guarantees. -var _ txmgr.SequenceSyncer[common.Address, common.Hash, common.Hash] = &nonceSyncerImpl{} +var _ txmgr.SequenceSyncer[common.Address, common.Hash, common.Hash, types.Nonce] = &nonceSyncerImpl{} type nonceSyncerImpl struct { txStore EvmTxStore client TxmClient chainID *big.Int logger logger.Logger - kst KeyStore } // NewNonceSyncer returns a new syncer @@ -62,7 +60,6 @@ func NewNonceSyncer( txStore EvmTxStore, lggr logger.Logger, ethClient evmclient.Client, - kst KeyStore, ) NonceSyncer { lggr = lggr.Named("NonceSyncer") return &nonceSyncerImpl{ @@ -70,7 +67,6 @@ func NewNonceSyncer( client: NewEvmTxmClient(ethClient), chainID: ethClient.ConfiguredChainID(), logger: lggr, - kst: kst, } } @@ -78,64 +74,33 @@ func NewNonceSyncer( // // This should only be called once, before the EthBroadcaster has started. // Calling it later is not safe and could lead to races. -func (s nonceSyncerImpl) Sync(ctx context.Context, addr common.Address) (err error) { - err = s.fastForwardNonceIfNecessary(ctx, addr) - return errors.Wrap(err, "NonceSyncer#fastForwardNoncesIfNecessary failed") +func (s nonceSyncerImpl) Sync(ctx context.Context, addr common.Address, localNonce types.Nonce) (nonce types.Nonce, err error) { + nonce, err = s.fastForwardNonceIfNecessary(ctx, addr, localNonce) + return nonce, errors.Wrap(err, "NonceSyncer#fastForwardNoncesIfNecessary failed") } -func (s nonceSyncerImpl) fastForwardNonceIfNecessary(ctx context.Context, address common.Address) error { +func (s nonceSyncerImpl) fastForwardNonceIfNecessary(ctx context.Context, address common.Address, localNonce types.Nonce) (types.Nonce, error) { chainNonce, err := s.pendingNonceFromEthClient(ctx, address) if err != nil { - return errors.Wrap(err, "GetNextNonce failed to loadInitialNonceFromEthClient") + return localNonce, errors.Wrap(err, "GetNextNonce failed to loadInitialNonceFromEthClient") } if chainNonce == 0 { - return nil + return localNonce, nil } - - keyNextNonce, err := s.kst.NextSequence(address, s.chainID, pg.WithParentCtx(ctx)) - if err != nil { - return err - } - - localNonce := keyNextNonce - hasInProgressTransaction, err := s.txStore.HasInProgressTransaction(ctx, address, s.chainID) - - if err != nil { - return errors.Wrapf(err, "failed to query for in_progress transaction for address %s", address.String()) - } else if hasInProgressTransaction { - // If we have an 'in_progress' transaction, our keys.next_nonce will be - // one lower than it should because we must have crashed mid-execution. - // The EthBroadcaster will automatically take care of this and - // increment it by one later, for now we just increment by one here. - localNonce++ - } - if chainNonce <= uint64(localNonce) { - return nil + if chainNonce <= localNonce { + return localNonce, nil } s.logger.Warnw(fmt.Sprintf("address %s has been used before, either by an external wallet or a different Chainlink node. "+ "Local nonce is %v but the on-chain nonce for this account was %v. "+ "It's possible that this node was restored from a backup. If so, transactions sent by the previous node will NOT be re-org protected and in rare cases may need to be manually bumped/resubmitted. "+ "Please note that using the chainlink keys with an external wallet is NOT SUPPORTED and can lead to missed or stuck transactions. ", address, localNonce, chainNonce), - "address", address.String(), "keyNextNonce", keyNextNonce, "localNonce", localNonce, "chainNonce", chainNonce) - - // Need to remember to decrement the chain nonce by one to account for in_progress transaction - newNextNonce := int64(chainNonce) - if hasInProgressTransaction { - newNextNonce-- - } + "address", address.String(), "localNonce", localNonce, "chainNonce", chainNonce) - err = s.txStore.UpdateKeyNextSequence(evmtypes.Nonce(newNextNonce), keyNextNonce, address, s.chainID, pg.WithParentCtx(ctx)) - - if errors.Is(err, ErrKeyNotUpdated) { - return errors.Errorf("NonceSyncer#fastForwardNonceIfNecessary optimistic lock failure fastforwarding nonce %v to %v for key %s", localNonce, chainNonce, address.String()) - } else if err == nil { - s.logger.Infow("Fast-forwarded nonce", "address", address, "newNextNonce", newNextNonce, "oldNextNonce", keyNextNonce) - } - return err + return chainNonce, nil } -func (s nonceSyncerImpl) pendingNonceFromEthClient(ctx context.Context, account common.Address) (uint64, error) { +func (s nonceSyncerImpl) pendingNonceFromEthClient(ctx context.Context, account common.Address) (types.Nonce, error) { nextNonce, err := s.client.PendingSequenceAt(ctx, account) - return uint64(nextNonce), errors.WithStack(err) + return nextNonce, errors.WithStack(err) } diff --git a/core/chains/evm/txmgr/nonce_syncer_test.go b/core/chains/evm/txmgr/nonce_syncer_test.go index 05a6d4c8c7b..13e5fd02e8c 100644 --- a/core/chains/evm/txmgr/nonce_syncer_test.go +++ b/core/chains/evm/txmgr/nonce_syncer_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" @@ -11,9 +12,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -24,149 +23,92 @@ func Test_NonceSyncer_Sync(t *testing.T) { t.Run("returns error if PendingNonceAt fails", func(t *testing.T) { db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - cfg := configtest.NewGeneralConfig(t, nil) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - txStore := cltest.NewTxStore(t, db, cfg.Database()) - - _, from := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(addr common.Address) bool { - return from == addr - })).Return(uint64(0), errors.New("something exploded")) + _, from := cltest.MustInsertRandomKey(t, ethKeyStore) - ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient, ethKeyStore) + ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient) - sendingKeys := cltest.MustSendingKeyStates(t, ethKeyStore, testutils.FixtureChainID) - err := ns.Sync(testutils.Context(t), sendingKeys[0].Address.Address()) + ethClient.On("PendingNonceAt", mock.Anything, from).Return(uint64(0), errors.New("something exploded")) + _, err := ns.Sync(testutils.Context(t), from, types.Nonce(0)) require.Error(t, err) assert.Contains(t, err.Error(), "something exploded") cltest.AssertCount(t, db, "evm.txes", 0) cltest.AssertCount(t, db, "evm.tx_attempts", 0) - - assertDatabaseNonce(t, db, from, 0) }) t.Run("does nothing if chain nonce reflects local nonce", func(t *testing.T) { db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - cfg := configtest.NewGeneralConfig(t, nil) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - txStore := cltest.NewTxStore(t, db, cfg.Database()) - _, from := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, from := cltest.MustInsertRandomKey(t, ethKeyStore) - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(addr common.Address) bool { - return from == addr - })).Return(uint64(0), nil) + ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient) - ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient, ethKeyStore) + ethClient.On("PendingNonceAt", mock.Anything, from).Return(uint64(0), nil) - sendingKeys := cltest.MustSendingKeyStates(t, ethKeyStore, testutils.FixtureChainID) - require.NoError(t, ns.Sync(testutils.Context(t), sendingKeys[0].Address.Address())) + nonce, err := ns.Sync(testutils.Context(t), from, 0) + require.Equal(t, nonce.Int64(), int64(0)) + require.NoError(t, err) cltest.AssertCount(t, db, "evm.txes", 0) cltest.AssertCount(t, db, "evm.tx_attempts", 0) - - assertDatabaseNonce(t, db, from, 0) }) t.Run("does nothing if chain nonce is behind local nonce", func(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTxStore(t, db, cfg.Database()) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - - k1, _ := cltest.MustInsertRandomKey(t, ethKeyStore, int64(32)) - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(addr common.Address) bool { - return k1.Address == addr - })).Return(uint64(31), nil) + _, fromAddress := cltest.RandomKey{Nonce: 32}.MustInsert(t, ks) - ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient, ethKeyStore) + ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient) - sendingKeys := cltest.MustSendingKeyStates(t, ethKeyStore, testutils.FixtureChainID) - require.NoError(t, ns.Sync(testutils.Context(t), sendingKeys[0].Address.Address())) + // Used to mock the chain nonce + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(5), nil) + nonce, err := ns.Sync(testutils.Context(t), fromAddress, types.Nonce(32)) + require.Equal(t, nonce.Int64(), int64(32)) + require.NoError(t, err) cltest.AssertCount(t, db, "evm.txes", 0) cltest.AssertCount(t, db, "evm.tx_attempts", 0) - - assertDatabaseNonce(t, db, k1.Address, 32) }) t.Run("fast forwards if chain nonce is ahead of local nonce", func(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTxStore(t, db, cfg.Database()) - + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, key1 := cltest.MustInsertRandomKey(t, ethKeyStore, int64(0)) - _, key2 := cltest.MustInsertRandomKey(t, ethKeyStore, int64(32)) + _, key1 := cltest.MustInsertRandomKey(t, ethKeyStore) + _, key2 := cltest.RandomKey{Nonce: 32}.MustInsert(t, ethKeyStore) - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(addr common.Address) bool { - // Nothing to do for key2 - return key2 == addr - })).Return(uint64(32), nil) - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(addr common.Address) bool { - // key1 has chain nonce of 5 which is ahead of local nonce 0 - return key1 == addr - })).Return(uint64(5), nil) + key1LocalNonce := types.Nonce(0) + key2LocalNonce := types.Nonce(32) - ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient, ethKeyStore) + ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient) - sendingKeys := cltest.MustSendingKeyStates(t, ethKeyStore, testutils.FixtureChainID) - for _, k := range sendingKeys { - require.NoError(t, ns.Sync(testutils.Context(t), k.Address.Address())) - } + // Used to mock the chain nonce + ethClient.On("PendingNonceAt", mock.Anything, key1).Return(uint64(5), nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, key2).Return(uint64(32), nil).Once() - assertDatabaseNonce(t, db, key1, 5) - }) - - t.Run("counts 'in_progress' eth_tx as bumping the local next nonce by 1", func(t *testing.T) { - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - - _, key1 := cltest.MustInsertRandomKey(t, ethKeyStore, int64(0)) + syncerNonce, err := ns.Sync(testutils.Context(t), key1, key1LocalNonce) + require.NoError(t, err) + require.Greater(t, syncerNonce, key1LocalNonce) - cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 1, key1) - - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(addr common.Address) bool { - // key1 has chain nonce of 1 which is ahead of keys.next_nonce (0) - // by 1, but does not need to change when taking into account the in_progress tx - return key1 == addr - })).Return(uint64(1), nil) - ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient, ethKeyStore) - - sendingKeys := cltest.MustSendingKeyStates(t, ethKeyStore, testutils.FixtureChainID) - require.NoError(t, ns.Sync(testutils.Context(t), sendingKeys[0].Address.Address())) - assertDatabaseNonce(t, db, key1, 0) - - ethClient = evmtest.NewEthClientMockWithDefaultChain(t) - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(addr common.Address) bool { - // key1 has chain nonce of 2 which is ahead of keys.next_nonce (0) - // by 2, but only ahead by 1 if we count the in_progress tx as +1 - return key1 == addr - })).Return(uint64(2), nil) - ns = txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient, ethKeyStore) - - require.NoError(t, ns.Sync(testutils.Context(t), sendingKeys[0].Address.Address())) - assertDatabaseNonce(t, db, key1, 1) + syncerNonce, err = ns.Sync(testutils.Context(t), key2, key2LocalNonce) + require.NoError(t, err) + require.Equal(t, syncerNonce, key2LocalNonce) }) } - -func assertDatabaseNonce(t *testing.T, db *sqlx.DB, address common.Address, nonce int64) { - t.Helper() - - var nextNonce int64 - err := db.Get(&nextNonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1`, address) - require.NoError(t, err) - assert.Equal(t, nonce, nextNonce) -} diff --git a/core/chains/evm/txmgr/reaper_test.go b/core/chains/evm/txmgr/reaper_test.go index 11843222999..830ed1ac17f 100644 --- a/core/chains/evm/txmgr/reaper_test.go +++ b/core/chains/evm/txmgr/reaper_test.go @@ -47,7 +47,7 @@ func TestReaper_ReapTxes(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, from := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, from := cltest.MustInsertRandomKey(t, ethKeyStore) var nonce int64 oneDayAgo := time.Now().Add(-24 * time.Hour) diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index f16e6fecc85..5d2975e2db5 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "math/big" - "sync/atomic" "testing" "time" @@ -100,7 +99,7 @@ func TestTxm_CreateTransaction(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) kst := cltest.NewKeyStore(t, db, cfg.Database()) - _, fromAddress := cltest.MustInsertRandomKey(t, kst.Eth(), 0) + _, fromAddress := cltest.MustInsertRandomKey(t, kst.Eth()) toAddress := testutils.NewAddress() gasLimit := uint32(1000) payload := []byte{1, 2, 3} @@ -512,8 +511,8 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) etKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - thisKey, _ := cltest.MustInsertRandomKey(t, etKeyStore, 1) - otherKey, _ := cltest.MustInsertRandomKey(t, etKeyStore, 1) + thisKey, _ := cltest.RandomKey{Nonce: 1}.MustInsert(t, etKeyStore) + otherKey, _ := cltest.RandomKey{Nonce: 1}.MustInsert(t, etKeyStore) fromAddress := thisKey.Address evmFromAddress := fromAddress @@ -648,23 +647,6 @@ func TestTxm_Lifecycle(t *testing.T) { unsub.AwaitOrFail(t, 1*time.Second) } -type fnMock struct{ called atomic.Bool } - -func (fm *fnMock) Fn() { - swapped := fm.called.CompareAndSwap(false, true) - if !swapped { - panic("func called more than once") - } -} - -func (fm *fnMock) AssertNotCalled(t *testing.T) { - assert.False(t, fm.called.Load()) -} - -func (fm *fnMock) AssertCalled(t *testing.T) { - assert.True(t, fm.called.Load()) -} - func TestTxm_Reset(t *testing.T) { t.Parallel() @@ -674,8 +656,8 @@ func TestTxm_Reset(t *testing.T) { cfg := evmtest.NewChainScopedConfig(t, gcfg) kst := cltest.NewKeyStore(t, db, cfg.Database()) - _, addr := cltest.MustInsertRandomKey(t, kst.Eth(), 5) - _, addr2 := cltest.MustInsertRandomKey(t, kst.Eth(), 3) + _, addr := cltest.RandomKey{Nonce: 5}.MustInsert(t, kst.Eth()) + _, addr2 := cltest.RandomKey{Nonce: 3}.MustInsert(t, kst.Eth()) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) // 4 confirmed tx from addr1 for i := int64(0); i < 4; i++ { @@ -687,8 +669,6 @@ func TestTxm_Reset(t *testing.T) { } ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethClient.On("PendingNonceAt", mock.Anything, addr).Return(uint64(0), nil) - ethClient.On("PendingNonceAt", mock.Anything, addr2).Return(uint64(0), nil) ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(nil, nil) ethClient.On("BatchCallContextAll", mock.Anything, mock.Anything).Return(nil).Maybe() eventBroadcaster := pgmocks.NewEventBroadcaster(t) @@ -707,35 +687,23 @@ func TestTxm_Reset(t *testing.T) { } t.Run("returns error if not started", func(t *testing.T) { - f := new(fnMock) - - err := txm.Reset(f.Fn, addr, false) + err := txm.Reset(addr, false) require.Error(t, err) assert.EqualError(t, err, "not started") - - f.AssertNotCalled(t) }) require.NoError(t, txm.Start(testutils.Context(t))) defer func() { assert.NoError(t, txm.Close()) }() - t.Run("calls function if started", func(t *testing.T) { - f := new(fnMock) - - err := txm.Reset(f.Fn, addr, false) + t.Run("returns no error if started", func(t *testing.T) { + err := txm.Reset(addr, false) require.NoError(t, err) - - f.AssertCalled(t) }) - t.Run("calls function and deletes relevant evm.txes if abandon=true", func(t *testing.T) { - f := new(fnMock) - - err := txm.Reset(f.Fn, addr, true) + t.Run("deletes relevant evm.txes if abandon=true", func(t *testing.T) { + err := txm.Reset(addr, true) require.NoError(t, err) - f.AssertCalled(t) - var s string err = db.Get(&s, `SELECT error FROM evm.txes WHERE from_address = $1 AND state = 'fatal_error'`, addr) require.NoError(t, err) diff --git a/core/chains/evm/types/models_test.go b/core/chains/evm/types/models_test.go index a4625f6f1c0..683a49692b6 100644 --- a/core/chains/evm/types/models_test.go +++ b/core/chains/evm/types/models_test.go @@ -94,7 +94,7 @@ func TestEthTxAttempt_GetSignedTx(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) tx := gethTypes.NewTransaction(uint64(42), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) chainID := big.NewInt(3) diff --git a/core/chains/evm/types/nonce.go b/core/chains/evm/types/nonce.go index 0c3256dc545..e9caf98c763 100644 --- a/core/chains/evm/types/nonce.go +++ b/core/chains/evm/types/nonce.go @@ -17,3 +17,7 @@ func (n Nonce) Int64() int64 { func (n Nonce) String() string { return strconv.FormatInt(n.Int64(), 10) } + +func GenerateNextNonce(prev Nonce) Nonce { + return Nonce(prev + 1) +} diff --git a/core/cmd/admin_commands.go b/core/cmd/admin_commands.go index 6ff7a5f6312..5daf5b4b1e6 100644 --- a/core/cmd/admin_commands.go +++ b/core/cmd/admin_commands.go @@ -204,7 +204,7 @@ func (s *Shell) CreateUser(c *cli.Context) (err error) { }() var links jsonapi.Links var users AdminUsersPresenters - if err := s.deserializeAPIResponse(resp, &users, &links); err != nil { + if err = s.deserializeAPIResponse(resp, &users, &links); err != nil { return s.errorOut(err) } for _, user := range users { @@ -316,8 +316,7 @@ func (s *Shell) Profile(c *cli.Context) error { genDir := filepath.Join(baseDir, fmt.Sprintf("debuginfo-%s", time.Now().Format(time.RFC3339))) - err := os.Mkdir(genDir, 0o755) - if err != nil { + if err := os.Mkdir(genDir, 0o755); err != nil { return s.errorOut(err) } var wgPprof sync.WaitGroup diff --git a/core/cmd/eth_keys_commands.go b/core/cmd/eth_keys_commands.go index e5f1f025966..c13bea80f2f 100644 --- a/core/cmd/eth_keys_commands.go +++ b/core/cmd/eth_keys_commands.go @@ -41,7 +41,7 @@ func initEthKeysSubCmd(s *Shell) cli.Command { }, { Name: "list", - Usage: "List available Ethereum accounts with their ETH & LINK balances, nonces, and other metadata", + Usage: "List available Ethereum accounts with their ETH & LINK balances and other metadata", Action: s.ListETHKeys, }, { @@ -100,10 +100,6 @@ func initEthKeysSubCmd(s *Shell) cli.Command { Usage: "chain ID of the key", Required: true, }, - cli.Uint64Flag{ - Name: "set-next-nonce, setNextNonce", - Usage: "manually set the next nonce for the key on the given chain. This should not be necessary during normal operation. USE WITH CAUTION: Setting this incorrectly can break your node", - }, cli.BoolFlag{ Name: "enable", Usage: "enable the key for the given chain", @@ -130,7 +126,6 @@ func (p *EthKeyPresenter) ToRow() []string { return []string{ p.Address, p.EVMChainID.String(), - fmt.Sprintf("%d", p.NextNonce), p.EthBalance.String(), p.LinkBalance.String(), fmt.Sprintf("%v", p.Disabled), @@ -140,7 +135,7 @@ func (p *EthKeyPresenter) ToRow() []string { } } -var ethKeysTableHeaders = []string{"Address", "EVM Chain ID", "Next Nonce", "ETH", "LINK", "Disabled", "Created", "Updated", "Max Gas Price Wei"} +var ethKeysTableHeaders = []string{"Address", "EVM Chain ID", "ETH", "LINK", "Disabled", "Created", "Updated", "Max Gas Price Wei"} // RenderTable implements TableRenderer func (p *EthKeyPresenter) RenderTable(rt RendererTable) error { @@ -368,9 +363,6 @@ func (s *Shell) UpdateChainEVMKey(c *cli.Context) (err error) { abandon := c.String("abandon") query.Set("abandon", abandon) - if c.IsSet("set-next-nonce") { - query.Set("nextNonce", c.String("set-next-nonce")) - } if c.IsSet("enable") && c.IsSet("disable") { return s.errorOut(errors.New("cannot set both --enable and --disable simultaneously")) } else if c.Bool("enable") { diff --git a/core/cmd/eth_keys_commands_test.go b/core/cmd/eth_keys_commands_test.go index 30e115e9482..630e76783a2 100644 --- a/core/cmd/eth_keys_commands_test.go +++ b/core/cmd/eth_keys_commands_test.go @@ -90,6 +90,7 @@ func TestShell_ListETHKeys(t *testing.T) { ethClient := newEthMock(t) ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(42), nil) ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(assets.NewLinkFromJuels(13), nil) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) c.EVM[0].NonceAutoSync = ptr(false) @@ -114,6 +115,7 @@ func TestShell_ListETHKeys_Error(t *testing.T) { ethClient := newEthMock(t) ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("fake error")) ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("fake error")) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) c.EVM[0].NonceAutoSync = ptr(false) @@ -156,7 +158,7 @@ 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", "", "0", "false", + k.Address.String(), "0", "", "0", "false", balances[0].UpdatedAt.String(), balances[0].CreatedAt.String(), "", }, balances[0].ToRow()) } @@ -167,6 +169,8 @@ func TestShell_CreateETHKey(t *testing.T) { ethClient := newEthMock(t) ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(42), nil) ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(assets.NewLinkFromJuels(42), nil) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) + app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) c.EVM[0].NonceAutoSync = ptr(false) @@ -240,6 +244,7 @@ func TestShell_ImportExportETHKey_NoChains(t *testing.T) { ethClient := newEthMock(t) ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(42), nil) ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(assets.NewLinkFromJuels(42), nil) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) c.EVM[0].NonceAutoSync = ptr(false) @@ -343,6 +348,7 @@ func TestShell_ImportExportETHKey_WithChains(t *testing.T) { t.Cleanup(func() { deleteKeyExportFile(t) }) ethClient := newEthMock(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) c.EVM[0].NonceAutoSync = ptr(false) diff --git a/core/cmd/evm_transaction_commands_test.go b/core/cmd/evm_transaction_commands_test.go index eb421b03968..484b1ccd3da 100644 --- a/core/cmd/evm_transaction_commands_test.go +++ b/core/cmd/evm_transaction_commands_test.go @@ -29,7 +29,7 @@ func TestShell_IndexTransactions(t *testing.T) { app := startNewApplicationV2(t, nil) client, r := app.NewShellAndRenderer() - _, from := cltest.MustAddRandomKeyToKeystore(t, app.KeyStore.Eth()) + _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) tx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) @@ -70,7 +70,7 @@ func TestShell_ShowTransaction(t *testing.T) { client, r := app.NewShellAndRenderer() db := app.GetSqlxDB() - _, from := cltest.MustAddRandomKeyToKeystore(t, app.KeyStore.Eth()) + _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) txStore := cltest.NewTestTxStore(t, db, app.GetConfig().Database()) tx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) @@ -94,7 +94,7 @@ func TestShell_IndexTxAttempts(t *testing.T) { app := startNewApplicationV2(t, nil) client, r := app.NewShellAndRenderer() - _, from := cltest.MustAddRandomKeyToKeystore(t, app.KeyStore.Eth()) + _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) tx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) @@ -140,6 +140,7 @@ func TestShell_SendEther_From_Txm(t *testing.T) { ethMock.On("BalanceAt", mock.Anything, key.Address, (*big.Int)(nil)).Return(balance.ToInt(), nil) ethMock.On("SequenceAt", mock.Anything, mock.Anything, mock.Anything).Return(evmtypes.Nonce(0), nil).Maybe() + ethMock.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) @@ -199,6 +200,7 @@ func TestShell_SendEther_From_Txm_WEI(t *testing.T) { ethMock.On("BalanceAt", mock.Anything, key.Address, (*big.Int)(nil)).Return(balance.ToInt(), nil) ethMock.On("SequenceAt", mock.Anything, mock.Anything, mock.Anything).Return(evmtypes.Nonce(0), nil).Maybe() + ethMock.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) diff --git a/core/cmd/ocr2vrf_configure_commands.go b/core/cmd/ocr2vrf_configure_commands.go index 01bfd89c32b..c218485c96a 100644 --- a/core/cmd/ocr2vrf_configure_commands.go +++ b/core/cmd/ocr2vrf_configure_commands.go @@ -14,6 +14,8 @@ import ( "github.com/pkg/errors" "github.com/urfave/cli" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -202,47 +204,12 @@ func (s *Shell) ConfigureOCR2VRFNode(c *cli.Context, owner *bind.TransactOpts, e } if useForwarder { - // Replace the transmitter ID with the forwarder address. - forwarderAddress := c.String("forwarder-address") - - ks := app.GetKeyStore().Eth() - // Add extra sending keys if using a forwarder. - for i := 0; i < forwarderAdditionalEOACount; i++ { - - // Create the sending key in the keystore. - k, err := ks.Create() - if err != nil { - return nil, err - } - - // Enable the sending key for the current chain. - err = ks.Enable(k.Address, big.NewInt(chainID)) - if err != nil { - return nil, err - } - - sendingKeys = append(sendingKeys, k.Address.String()) - sendingKeysAddresses = append(sendingKeysAddresses, k.Address) - } - - // We have to set the authorized senders on-chain here, otherwise the job spawner will fail as the - // forwarder will not be recognized. - ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) - defer cancel() - f, err := authorized_forwarder.NewAuthorizedForwarder(common.HexToAddress(forwarderAddress), ec) - tx, err := f.SetAuthorizedSenders(owner, sendingKeysAddresses) + sendingKeys, sendingKeysAddresses, err = s.appendForwarders(chainID, app.GetKeyStore().Eth(), sendingKeys, sendingKeysAddresses) if err != nil { return nil, err } - _, err = bind.WaitMined(ctx, ec, tx) - if err != nil { - return nil, err - } - - // Create forwarder for management in forwarder_manager.go. - orm := forwarders.NewORM(ldb.DB(), lggr, s.Config.Database()) - _, err = orm.CreateForwarder(common.HexToAddress(forwarderAddress), *utils.NewBigI(chainID)) + err = s.authorizeForwarder(c, ldb.DB(), lggr, chainID, ec, owner, sendingKeysAddresses) if err != nil { return nil, err } @@ -331,6 +298,58 @@ func (s *Shell) ConfigureOCR2VRFNode(c *cli.Context, owner *bind.TransactOpts, e }, nil } +func (s *Shell) appendForwarders(chainID int64, ks keystore.Eth, sendingKeys []string, sendingKeysAddresses []common.Address) ([]string, []common.Address, error) { + for i := 0; i < forwarderAdditionalEOACount; i++ { + // Create the sending key in the keystore. + k, err := ks.Create() + if err != nil { + return nil, nil, err + } + + // Enable the sending key for the current chain. + err = ks.Enable(k.Address, big.NewInt(chainID)) + if err != nil { + return nil, nil, err + } + + sendingKeys = append(sendingKeys, k.Address.String()) + sendingKeysAddresses = append(sendingKeysAddresses, k.Address) + } + + return sendingKeys, sendingKeysAddresses, nil +} + +func (s *Shell) authorizeForwarder(c *cli.Context, db *sqlx.DB, lggr logger.Logger, chainID int64, ec *ethclient.Client, owner *bind.TransactOpts, sendingKeysAddresses []common.Address) error { + // Replace the transmitter ID with the forwarder address. + forwarderAddress := c.String("forwarder-address") + + // We have to set the authorized senders on-chain here, otherwise the job spawner will fail as the + // forwarder will not be recognized. + ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) + defer cancel() + f, err := authorized_forwarder.NewAuthorizedForwarder(common.HexToAddress(forwarderAddress), ec) + if err != nil { + return err + } + tx, err := f.SetAuthorizedSenders(owner, sendingKeysAddresses) + if err != nil { + return err + } + _, err = bind.WaitMined(ctx, ec, tx) + if err != nil { + return err + } + + // Create forwarder for management in forwarder_manager.go. + orm := forwarders.NewORM(db, lggr, s.Config.Database()) + _, err = orm.CreateForwarder(common.HexToAddress(forwarderAddress), *utils.NewBigI(chainID)) + if err != nil { + return err + } + + return nil +} + func setupKeystore(cli *Shell, app chainlink.Application, keyStore keystore.Master) error { err := cli.KeyStoreAuthenticator.authenticate(keyStore, cli.Config.Password()) if err != nil { diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index 372aad01384..613e8f5a6e0 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -292,8 +292,7 @@ func (s *Shell) runNode(c *cli.Context) error { s.Config.LogConfiguration(lggr.Debugf) - err := s.Config.Validate() - if err != nil { + if err := s.Config.Validate(); err != nil { return errors.Wrap(err, "config validation failed") } diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index 691e5faa923..fce9f01469b 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -370,7 +370,7 @@ func TestShell_RebroadcastTransactions_OutsideRange_Txm(t *testing.T) { keyStore := cltest.NewKeyStore(t, sqlxDB, config.Database()) - _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth(), 0) + _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) txStore := cltest.NewTestTxStore(t, sqlxDB, config.Database()) cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, int64(test.nonce), 42, fromAddress) @@ -448,7 +448,7 @@ func TestShell_RebroadcastTransactions_AddressCheck(t *testing.T) { keyStore := cltest.NewKeyStore(t, sqlxDB, config.Database()) - _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth(), 0) + _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) if !test.enableAddress { err := keyStore.Eth().Disable(fromAddress, testutils.FixtureChainID) diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 671d4072816..3a9c1724353 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -33,14 +33,15 @@ import ( p2ppeer "github.com/libp2p/go-libp2p-core/peer" "github.com/manyminds/api2go/jsonapi" "github.com/onsi/gomega" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" "github.com/urfave/cli" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink-relay/pkg/loop" clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" @@ -209,8 +210,7 @@ func NewEventBroadcaster(t testing.TB, dbURL url.URL) pg.EventBroadcaster { return pg.NewEventBroadcaster(dbURL, 0, 0, lggr, uuid.New()) } -func NewEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient evmclient.Client, config evmconfig.ChainScopedConfig, ks keystore.Eth, fn txmgrcommon.ResumeCallback) (*txmgr.Confirmer, error) { - t.Helper() +func NewEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient evmclient.Client, config evmconfig.ChainScopedConfig, ks keystore.Eth, fn txmgrcommon.ResumeCallback) *txmgr.Confirmer { lggr := logger.TestLogger(t) ge := config.EVM().GasEstimator() estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(ge, ge.BlockHistory(), lggr), ge.EIP1559DynamicFees(), nil) @@ -218,7 +218,7 @@ func NewEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient evmclient ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), config.Database(), ks, txBuilder, lggr) ec.SetResumeCallback(fn) require.NoError(t, ec.Start(testutils.Context(t))) - return ec, nil + return ec } // TestApplication holds the test application and test servers @@ -271,8 +271,6 @@ func NewApplicationWithKey(t *testing.T, flagsAndDeps ...interface{}) *TestAppli // NewApplicationWithConfigAndKey creates a new TestApplication with the given testorm // it will also provide an unlocked account on the keystore func NewApplicationWithConfigAndKey(t testing.TB, c chainlink.GeneralConfig, flagsAndDeps ...interface{}) *TestApplication { - t.Helper() - app := NewApplicationWithConfig(t, c, flagsAndDeps...) chainID := *utils.NewBig(&FixtureChainID) @@ -284,12 +282,14 @@ func NewApplicationWithConfigAndKey(t testing.TB, c chainlink.GeneralConfig, fla } if len(app.Keys) == 0 { - k, _ := MustInsertRandomKey(t, app.KeyStore.Eth(), 0, chainID) + k, _ := MustInsertRandomKey(t, app.KeyStore.Eth(), chainID) app.Keys = []ethkey.KeyV2{k} } else { id, ks := chainID.ToInt(), app.KeyStore.Eth() for _, k := range app.Keys { - MustAddKeyToKeystore(t, k, id, ks) + ks.XXXTestingOnlyAdd(k) + require.NoError(t, ks.Add(k.Address, id)) + require.NoError(t, ks.Enable(k.Address, id)) } } diff --git a/core/internal/cltest/factories.go b/core/internal/cltest/factories.go index 8b77da14380..a1a5d9db6be 100644 --- a/core/internal/cltest/factories.go +++ b/core/internal/cltest/factories.go @@ -472,75 +472,25 @@ func MustInsertFatalErrorEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, fromA return etx } -func MustAddRandomKeyToKeystore(t testing.TB, ethKeyStore keystore.Eth) (ethkey.KeyV2, common.Address) { - t.Helper() - - k := MustGenerateRandomKey(t) - MustAddKeyToKeystore(t, k, &FixtureChainID, ethKeyStore) - - return k, k.Address -} - -func MustAddRandomKeyToKeystoreWithChainID(t testing.TB, chainID *big.Int, ethKeyStore keystore.Eth) (ethkey.KeyV2, common.Address) { - t.Helper() - k := MustGenerateRandomKey(t) - MustAddKeyToKeystore(t, k, chainID, ethKeyStore) +type RandomKey struct { + Nonce int64 + Disabled bool - return k, k.Address + chainIDs []utils.Big // nil: Fixture, set empty for none } -func MustAddKeyToKeystore(t testing.TB, key ethkey.KeyV2, chainID *big.Int, ethKeyStore keystore.Eth) { - t.Helper() - ethKeyStore.XXXTestingOnlyAdd(key) - require.NoError(t, ethKeyStore.Add(key.Address, chainID)) - require.NoError(t, ethKeyStore.Enable(key.Address, chainID)) -} - -// MustInsertRandomKey inserts a randomly generated (not cryptographically -// secure) key for testing -// By default it is enabled for the fixture chain -func MustInsertRandomKey( - t testing.TB, - keystore keystore.Eth, - opts ...interface{}, -) (ethkey.KeyV2, common.Address) { - t.Helper() - - chainIDs := []utils.Big{*utils.NewBig(&FixtureChainID)} - for _, opt := range opts { - switch v := opt.(type) { - case utils.Big: - chainIDs[0] = v - case []utils.Big: - chainIDs = v - } +func (r RandomKey) MustInsert(t testing.TB, keystore keystore.Eth) (ethkey.KeyV2, common.Address) { + if r.chainIDs == nil { + r.chainIDs = []utils.Big{*utils.NewBig(&FixtureChainID)} } key := MustGenerateRandomKey(t) keystore.XXXTestingOnlyAdd(key) - for _, cid := range chainIDs { - var nonce int64 - enabled := true - for _, opt := range opts { - switch v := opt.(type) { - case int: - nonce = int64(v) - case int64: - nonce = v - case evmtypes.Nonce: - nonce = v.Int64() - case bool: - enabled = v - default: - t.Logf("ignoring unknown type in MustInsertRandomKey: %T, note: chain IDs are processed earlier", opt) - } - } + for _, cid := range r.chainIDs { require.NoError(t, keystore.Add(key.Address, cid.ToInt())) require.NoError(t, keystore.Enable(key.Address, cid.ToInt())) - err := keystore.Reset(key.Address, cid.ToInt(), nonce) - require.NoError(t, err) - if !enabled { + if r.Disabled { require.NoError(t, keystore.Disable(key.Address, cid.ToInt())) } } @@ -548,29 +498,29 @@ func MustInsertRandomKey( return key, key.Address } -func MustInsertRandomEnabledKey( - t testing.TB, - keystore keystore.Eth, - opts ...interface{}, -) (ethkey.KeyV2, common.Address) { - return MustInsertRandomKey(t, keystore, append(opts, true)) +func (r RandomKey) MustInsertWithState(t testing.TB, keystore keystore.Eth) (ethkey.State, common.Address) { + k, address := r.MustInsert(t, keystore) + state := MustGetStateForKey(t, keystore, k) + return state, address +} + +// MustInsertRandomKey inserts a randomly generated (not cryptographically secure) key for testing. +// By default, it is enabled for the fixture chain. Pass chainIDs to override. +// Use MustInsertRandomKeyNoChains for a key associate with no chains. +func MustInsertRandomKey(t testing.TB, keystore keystore.Eth, chainIDs ...utils.Big) (ethkey.KeyV2, common.Address) { + r := RandomKey{} + if len(chainIDs) > 0 { + r.chainIDs = chainIDs + } + return r.MustInsert(t, keystore) } -func MustInsertRandomDisabledKey( - t testing.TB, - keystore keystore.Eth, - opts ...interface{}, -) (key ethkey.KeyV2, address common.Address) { - return MustInsertRandomKey(t, keystore, append(opts, false)) +func MustInsertRandomKeyNoChains(t testing.TB, keystore keystore.Eth) (ethkey.KeyV2, common.Address) { + return RandomKey{chainIDs: []utils.Big{}}.MustInsert(t, keystore) } -func MustInsertRandomKeyReturningState(t testing.TB, - keystore keystore.Eth, - opts ...interface{}, -) (ethkey.State, common.Address) { - k, address := MustInsertRandomKey(t, keystore, opts...) - state := MustGetStateForKey(t, keystore, k) - return state, address +func MustInsertRandomKeyReturningState(t testing.TB, keystore keystore.Eth) (ethkey.State, common.Address) { + return RandomKey{}.MustInsertWithState(t, keystore) } func MustGenerateRandomKey(t testing.TB) ethkey.KeyV2 { @@ -579,7 +529,7 @@ func MustGenerateRandomKey(t testing.TB) ethkey.KeyV2 { return key } -func MustGenerateRandomKeyState(t testing.TB) ethkey.State { +func MustGenerateRandomKeyState(_ testing.TB) ethkey.State { return ethkey.State{Address: NewEIP55Address()} } @@ -676,7 +626,7 @@ func MustInsertKeeperJob(t *testing.T, db *sqlx.DB, korm keeper.ORM, from ethkey } func MustInsertKeeperRegistry(t *testing.T, db *sqlx.DB, korm keeper.ORM, ethKeyStore keystore.Eth, keeperIndex, numKeepers, blockCountPerTurn int32) (keeper.Registry, job.Job) { - key, _ := MustAddRandomKeyToKeystoreWithChainID(t, testutils.SimulatedChainID, ethKeyStore) + key, _ := MustInsertRandomKey(t, ethKeyStore, *utils.NewBig(testutils.SimulatedChainID)) from := key.EIP55Address t.Helper() contractAddress := NewEIP55Address() diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index 489f744cdef..82b335927cf 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/rpc" "github.com/google/uuid" + "github.com/hashicorp/consul/sdk/freeport" "github.com/onsi/gomega" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -670,7 +671,7 @@ func setupOCRContracts(t *testing.T) (*bind.TransactOpts, *backends.SimulatedBac return owner, b, ocrContractAddress, ocrContract, flagsContract, flagsContractAddress } -func setupNode(t *testing.T, owner *bind.TransactOpts, portV1, portV2 uint16, dbName string, +func setupNode(t *testing.T, owner *bind.TransactOpts, portV1, portV2 int, dbName string, b *backends.SimulatedBackend, ns ocrnetworking.NetworkingStack, overrides func(c *chainlink.Config, s *chainlink.Secrets), ) (*cltest.TestApplication, string, common.Address, ocrkey.KeyV2) { p2pKey, err := p2pkey.NewV2() @@ -743,7 +744,7 @@ func setupForwarderEnabledNode( t *testing.T, owner *bind.TransactOpts, portV1, - portV2 uint16, + portV2 int, dbName string, b *backends.SimulatedBackend, ns ocrnetworking.NetworkingStack, @@ -856,8 +857,9 @@ func TestIntegration_OCR(t *testing.T) { for _, tt := range tests { test := tt t.Run(test.name, func(t *testing.T) { - bootstrapNodePortV1 := testutils.GetFreePort(t) - bootstrapNodePortV2 := testutils.GetFreePort(t) + t.Parallel() + bootstrapNodePortV1 := freeport.GetOne(t) + bootstrapNodePortV2 := freeport.GetOne(t) g := gomega.NewWithT(t) owner, b, ocrContractAddress, ocrContract, flagsContract, flagsContractAddress := setupOCRContracts(t) @@ -870,9 +872,10 @@ func TestIntegration_OCR(t *testing.T) { keys []ocrkey.KeyV2 apps []*cltest.TestApplication ) + ports := freeport.GetN(t, 2*numOracles) for i := 0; i < numOracles; i++ { - portV1 := testutils.GetFreePort(t) - portV2 := testutils.GetFreePort(t) + portV1 := ports[2*i] + portV2 := ports[2*i+1] app, peerID, transmitter, key := setupNode(t, owner, portV1, portV2, fmt.Sprintf("o%d_%d", i, test.id), b, test.ns, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FlagsContractAddress = ptr(ethkey.EIP55AddressFromAddress(flagsContractAddress)) c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(test.eip1559) @@ -891,10 +894,10 @@ func TestIntegration_OCR(t *testing.T) { OracleIdentity: confighelper.OracleIdentity{ OnChainSigningAddress: ocrtypes.OnChainSigningAddress(key.OnChainSigning.Address()), TransmitAddress: transmitter, - OffchainPublicKey: ocrtypes.OffchainPublicKey(key.PublicKeyOffChain()), + OffchainPublicKey: key.PublicKeyOffChain(), PeerID: peerID, }, - SharedSecretEncryptionPublicKey: ocrtypes.SharedSecretEncryptionPublicKey(key.PublicKeyConfig()), + SharedSecretEncryptionPublicKey: key.PublicKeyConfig(), }) } @@ -1080,8 +1083,8 @@ func TestIntegration_OCR_ForwarderFlow(t *testing.T) { t.Parallel() numOracles := 4 t.Run("ocr_forwarder_flow", func(t *testing.T) { - bootstrapNodePortV1 := testutils.GetFreePort(t) - bootstrapNodePortV2 := testutils.GetFreePort(t) + bootstrapNodePortV1 := freeport.GetOne(t) + bootstrapNodePortV2 := freeport.GetOne(t) g := gomega.NewWithT(t) owner, b, ocrContractAddress, ocrContract, flagsContract, flagsContractAddress := setupOCRContracts(t) @@ -1096,9 +1099,10 @@ func TestIntegration_OCR_ForwarderFlow(t *testing.T) { keys []ocrkey.KeyV2 apps []*cltest.TestApplication ) + ports := freeport.GetN(t, 2*numOracles) for i := 0; i < numOracles; i++ { - portV1 := testutils.GetFreePort(t) - portV2 := testutils.GetFreePort(t) + portV1 := ports[2*i] + portV2 := ports[2*i+1] app, peerID, transmitter, forwarder, key := setupForwarderEnabledNode(t, owner, portV1, portV2, fmt.Sprintf("o%d_%d", i, 1), b, ocrnetworking.NetworkingStackV2, func(c *chainlink.Config, s *chainlink.Secrets) { c.Feature.LogPoller = ptr(true) c.EVM[0].FlagsContractAddress = ptr(ethkey.EIP55AddressFromAddress(flagsContractAddress)) @@ -1117,10 +1121,10 @@ func TestIntegration_OCR_ForwarderFlow(t *testing.T) { OracleIdentity: confighelper.OracleIdentity{ OnChainSigningAddress: ocrtypes.OnChainSigningAddress(key.OnChainSigning.Address()), TransmitAddress: forwarder, - OffchainPublicKey: ocrtypes.OffchainPublicKey(key.PublicKeyOffChain()), + OffchainPublicKey: key.PublicKeyOffChain(), PeerID: peerID, }, - SharedSecretEncryptionPublicKey: ocrtypes.SharedSecretEncryptionPublicKey(key.PublicKeyConfig()), + SharedSecretEncryptionPublicKey: key.PublicKeyConfig(), }) } diff --git a/core/internal/features/ocr2/features_ocr2_test.go b/core/internal/features/ocr2/features_ocr2_test.go index f31f19a4f2d..bde0fa3533f 100644 --- a/core/internal/features/ocr2/features_ocr2_test.go +++ b/core/internal/features/ocr2/features_ocr2_test.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/hashicorp/consul/sdk/freeport" "github.com/onsi/gomega" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -103,7 +104,7 @@ func setupOCR2Contracts(t *testing.T) (*bind.TransactOpts, *backends.SimulatedBa func setupNodeOCR2( t *testing.T, owner *bind.TransactOpts, - port uint16, + port int, dbName string, useForwarder bool, b *backends.SimulatedBackend, @@ -192,7 +193,7 @@ func TestIntegration_OCR2(t *testing.T) { owner, b, ocrContractAddress, ocrContract := setupOCR2Contracts(t) lggr := logger.TestLogger(t) - bootstrapNodePort := testutils.GetFreePort(t) + bootstrapNodePort := freeport.GetOne(t) bootstrapNode := setupNodeOCR2(t, owner, bootstrapNodePort, "bootstrap", false /* useForwarders */, b, nil) var ( @@ -201,8 +202,9 @@ func TestIntegration_OCR2(t *testing.T) { kbs []ocr2key.KeyBundle apps []*cltest.TestApplication ) - for i := uint16(0); i < 4; i++ { - node := setupNodeOCR2(t, owner, bootstrapNodePort+1+i, fmt.Sprintf("oracle%d", i), false /* useForwarders */, b, []commontypes.BootstrapperLocator{ + ports := freeport.GetN(t, 4) + for i := 0; i < 4; i++ { + node := setupNodeOCR2(t, owner, ports[i], fmt.Sprintf("oracle%d", i), false /* useForwarders */, b, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapNode.peerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, }) @@ -461,7 +463,7 @@ func TestIntegration_OCR2_ForwarderFlow(t *testing.T) { owner, b, ocrContractAddress, ocrContract := setupOCR2Contracts(t) lggr := logger.TestLogger(t) - bootstrapNodePort := testutils.GetFreePort(t) + bootstrapNodePort := freeport.GetOne(t) bootstrapNode := setupNodeOCR2(t, owner, bootstrapNodePort, "bootstrap", true /* useForwarders */, b, nil) var ( @@ -471,8 +473,9 @@ func TestIntegration_OCR2_ForwarderFlow(t *testing.T) { kbs []ocr2key.KeyBundle apps []*cltest.TestApplication ) + ports := freeport.GetN(t, 4) for i := uint16(0); i < 4; i++ { - node := setupNodeOCR2(t, owner, bootstrapNodePort+1+i, fmt.Sprintf("oracle%d", i), true /* useForwarders */, b, []commontypes.BootstrapperLocator{ + node := setupNodeOCR2(t, owner, ports[i], fmt.Sprintf("oracle%d", i), true /* useForwarders */, b, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapNode.peerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, }) diff --git a/core/internal/testutils/testutils.go b/core/internal/testutils/testutils.go index 0d4e710b497..938d814b9eb 100644 --- a/core/internal/testutils/testutils.go +++ b/core/internal/testutils/testutils.go @@ -10,7 +10,6 @@ import ( "math" "math/big" mrand "math/rand" - "net" "net/http" "net/http/httptest" "net/url" @@ -452,16 +451,3 @@ func MustDecodeBase64(s string) (b []byte) { } return } - -// GetFreePort returns a free port. -// NOTE: This approach is technically incorrect because the returned port -// can still be taken by the time the caller attempts to bind to it. -// Unfortunately, we can't specify zero port in P2P.V2.ListenAddresses at the moment. -func GetFreePort(t *testing.T) uint16 { - addr, err := net.ResolveTCPAddr("tcp", "localhost:0") - require.NoError(t, err) - listener, err := net.ListenTCP("tcp", addr) - require.NoError(t, err) - require.NoError(t, listener.Close()) - return uint16(listener.Addr().(*net.TCPAddr).Port) -} diff --git a/core/logger/zap.go b/core/logger/zap.go index 328b157a2a7..c739a80d45a 100644 --- a/core/logger/zap.go +++ b/core/logger/zap.go @@ -13,7 +13,6 @@ var _ Logger = &zapLogger{} type zapLogger struct { *zap.SugaredLogger level zap.AtomicLevel - name string fields []interface{} callerSkip int } @@ -49,16 +48,8 @@ func copyFields(fields []interface{}, add ...interface{}) []interface{} { return f } -func joinName(old, new string) string { - if old == "" { - return new - } - return old + "." + new -} - func (l *zapLogger) Named(name string) Logger { newLogger := *l - newLogger.name = joinName(l.name, name) newLogger.SugaredLogger = l.SugaredLogger.Named(name) newLogger.Trace("Named logger created") return &newLogger @@ -72,7 +63,7 @@ func (l *zapLogger) Helper(skip int) Logger { } func (l *zapLogger) Name() string { - return l.name + return l.Desugar().Name() } func (l *zapLogger) sugaredHelper(skip int) *zap.SugaredLogger { diff --git a/core/scripts/chaincli/README.md b/core/scripts/chaincli/README.md index 692287ee024..da7aa7cc777 100644 --- a/core/scripts/chaincli/README.md +++ b/core/scripts/chaincli/README.md @@ -15,8 +15,7 @@ Before starting, you will need: The example .env in this repo is for the Polygon Mumbai testnet. You can use [this faucet](https://faucets.chain.link/mumbai) to send testnet LINK to your wallet ahead of executing the next steps ->Note: Be careful with your key. When using testnets, it's best to use a separate ->account that does not hold real funds. +>Note: Be careful with your key. When using testnets, it's best to use a separate account that does not hold real funds. ## Run OCR2Keepers locally diff --git a/core/scripts/common/vrf/constants/constants.go b/core/scripts/common/vrf/constants/constants.go new file mode 100644 index 00000000000..b21f6b0b323 --- /dev/null +++ b/core/scripts/common/vrf/constants/constants.go @@ -0,0 +1,34 @@ +package constants + +import ( + "math/big" +) + +var ( + SubscriptionBalanceJuels = "1e19" + SubscriptionBalanceNativeWei = "1e18" + + // optional flags + FallbackWeiPerUnitLink = big.NewInt(6e16) + BatchFulfillmentEnabled = true + MinConfs = 3 + NodeSendingKeyFundingAmount = "1e17" + MaxGasLimit = int64(2.5e6) + StalenessSeconds = int64(86400) + GasAfterPayment = int64(33285) + + //vrfv2 + FlatFeeTier1 = int64(500) + FlatFeeTier2 = int64(500) + FlatFeeTier3 = int64(500) + FlatFeeTier4 = int64(500) + FlatFeeTier5 = int64(500) + ReqsForTier2 = int64(0) + ReqsForTier3 = int64(0) + ReqsForTier4 = int64(0) + ReqsForTier5 = int64(0) + + //vrfv2plus + FlatFeeLinkPPM = int64(500) + FlatFeeNativePPM = int64(500) +) diff --git a/core/scripts/vrfv2/testnet/docker/db/create-multiple-databases.sh b/core/scripts/common/vrf/docker/db/create-multiple-databases.sh similarity index 100% rename from core/scripts/vrfv2/testnet/docker/db/create-multiple-databases.sh rename to core/scripts/common/vrf/docker/db/create-multiple-databases.sh diff --git a/core/scripts/vrfv2/testnet/docker/docker-compose.yml b/core/scripts/common/vrf/docker/docker-compose.yml similarity index 98% rename from core/scripts/vrfv2/testnet/docker/docker-compose.yml rename to core/scripts/common/vrf/docker/docker-compose.yml index d31c50f3463..5c14c4670d8 100644 --- a/core/scripts/vrfv2/testnet/docker/docker-compose.yml +++ b/core/scripts/common/vrf/docker/docker-compose.yml @@ -132,9 +132,9 @@ services: secrets: node_password: - file: ./secrets/password.txt + file: secrets/password.txt apicredentials: - file: ./secrets/apicredentials + file: secrets/apicredentials volumes: docker-compose-db: diff --git a/core/scripts/vrfv2/testnet/docker/sample.env b/core/scripts/common/vrf/docker/sample.env similarity index 100% rename from core/scripts/vrfv2/testnet/docker/sample.env rename to core/scripts/common/vrf/docker/sample.env diff --git a/core/scripts/vrfv2/testnet/docker/secrets/apicredentials b/core/scripts/common/vrf/docker/secrets/apicredentials similarity index 100% rename from core/scripts/vrfv2/testnet/docker/secrets/apicredentials rename to core/scripts/common/vrf/docker/secrets/apicredentials diff --git a/core/scripts/vrfv2/testnet/docker/secrets/password.txt b/core/scripts/common/vrf/docker/secrets/password.txt similarity index 100% rename from core/scripts/vrfv2/testnet/docker/secrets/password.txt rename to core/scripts/common/vrf/docker/secrets/password.txt diff --git a/core/scripts/vrfv2/testnet/docker/toml-config/base.toml b/core/scripts/common/vrf/docker/toml-config/base.toml similarity index 100% rename from core/scripts/vrfv2/testnet/docker/toml-config/base.toml rename to core/scripts/common/vrf/docker/toml-config/base.toml diff --git a/core/scripts/vrfv2/testnet/docker/toml-config/bhf.toml b/core/scripts/common/vrf/docker/toml-config/bhf.toml similarity index 100% rename from core/scripts/vrfv2/testnet/docker/toml-config/bhf.toml rename to core/scripts/common/vrf/docker/toml-config/bhf.toml diff --git a/core/scripts/vrfv2/testnet/docker/toml-config/bhs.toml b/core/scripts/common/vrf/docker/toml-config/bhs.toml similarity index 100% rename from core/scripts/vrfv2/testnet/docker/toml-config/bhs.toml rename to core/scripts/common/vrf/docker/toml-config/bhs.toml diff --git a/core/scripts/vrfv2/testnet/docker/toml-config/rpc-nodes.toml b/core/scripts/common/vrf/docker/toml-config/rpc-nodes.toml similarity index 100% rename from core/scripts/vrfv2/testnet/docker/toml-config/rpc-nodes.toml rename to core/scripts/common/vrf/docker/toml-config/rpc-nodes.toml diff --git a/core/scripts/vrfv2/testnet/docker/toml-config/secrets.toml b/core/scripts/common/vrf/docker/toml-config/secrets.toml similarity index 100% rename from core/scripts/vrfv2/testnet/docker/toml-config/secrets.toml rename to core/scripts/common/vrf/docker/toml-config/secrets.toml diff --git a/core/scripts/vrfv2/testnet/docker/toml-config/vrf-backup-other-chains.toml b/core/scripts/common/vrf/docker/toml-config/vrf-backup-other-chains.toml similarity index 81% rename from core/scripts/vrfv2/testnet/docker/toml-config/vrf-backup-other-chains.toml rename to core/scripts/common/vrf/docker/toml-config/vrf-backup-other-chains.toml index a39c6b15c57..ba71abe92fc 100644 --- a/core/scripts/vrfv2/testnet/docker/toml-config/vrf-backup-other-chains.toml +++ b/core/scripts/common/vrf/docker/toml-config/vrf-backup-other-chains.toml @@ -1,5 +1,5 @@ [Feature] -LogPoller = false #VRF V2 uses Log Broadcast3er instead of Log poller +LogPoller = false #VRF V2 uses Log Broadcaster instead of Log poller [[EVM]] ChainID = '11155111' diff --git a/core/scripts/vrfv2/testnet/docker/toml-config/vrf-backup.toml b/core/scripts/common/vrf/docker/toml-config/vrf-backup.toml similarity index 100% rename from core/scripts/vrfv2/testnet/docker/toml-config/vrf-backup.toml rename to core/scripts/common/vrf/docker/toml-config/vrf-backup.toml diff --git a/core/scripts/vrfv2/testnet/docker/toml-config/vrf-primary.toml b/core/scripts/common/vrf/docker/toml-config/vrf-primary.toml similarity index 76% rename from core/scripts/vrfv2/testnet/docker/toml-config/vrf-primary.toml rename to core/scripts/common/vrf/docker/toml-config/vrf-primary.toml index 67cd33659fb..6cb78789b23 100644 --- a/core/scripts/vrfv2/testnet/docker/toml-config/vrf-primary.toml +++ b/core/scripts/common/vrf/docker/toml-config/vrf-primary.toml @@ -1,5 +1,5 @@ [Feature] -LogPoller = false #VRF V2 uses Log Broadcast3er instead of Log poller +LogPoller = false #VRF V2 uses Log Broadcaster instead of Log poller [[EVM]] ChainID = '11155111' diff --git a/core/scripts/vrfv2/testnet/docker/wait-for-others/docker-wait-for-it.sh b/core/scripts/common/vrf/docker/wait-for-others/docker-wait-for-it.sh similarity index 100% rename from core/scripts/vrfv2/testnet/docker/wait-for-others/docker-wait-for-it.sh rename to core/scripts/common/vrf/docker/wait-for-others/docker-wait-for-it.sh diff --git a/core/scripts/vrfv2/testnet/docker/wait-for-others/docker-wait-for-others.sh b/core/scripts/common/vrf/docker/wait-for-others/docker-wait-for-others.sh similarity index 100% rename from core/scripts/vrfv2/testnet/docker/wait-for-others/docker-wait-for-others.sh rename to core/scripts/common/vrf/docker/wait-for-others/docker-wait-for-others.sh diff --git a/core/scripts/vrfv2/testnet/jobs/jobs.go b/core/scripts/common/vrf/jobs/jobs.go similarity index 55% rename from core/scripts/vrfv2/testnet/jobs/jobs.go rename to core/scripts/common/vrf/jobs/jobs.go index 8ff0195bfa8..674cca175c8 100644 --- a/core/scripts/vrfv2/testnet/jobs/jobs.go +++ b/core/scripts/common/vrf/jobs/jobs.go @@ -1,7 +1,7 @@ package jobs var ( - VRFJobFormatted = `type = "vrf" + VRFV2JobFormatted = `type = "vrf" name = "vrf_v2" schemaVersion = 1 coordinatorAddress = "%s" @@ -38,6 +38,46 @@ simulate [type=ethcall decode_log->vrf->estimate_gas->simulate """` + VRFV2PlusJobFormatted = ` +type = "vrf" +name = "vrf_v2_plus" +schemaVersion = 1 +coordinatorAddress = "%s" +batchCoordinatorAddress = "%s" +batchFulfillmentEnabled = %t +batchFulfillmentGasMultiplier = 1.1 +publicKey = "%s" +minIncomingConfirmations = %d +evmChainID = "%d" +fromAddresses = ["%s"] +pollPeriod = "300ms" +requestTimeout = "30m0s" +observationSource = """ +decode_log [type=ethabidecodelog + abi="RandomWordsRequested(bytes32 indexed keyHash,uint256 requestId,uint256 preSeed,uint256 indexed subId,uint16 minimumRequestConfirmations,uint32 callbackGasLimit,uint32 numWords,bytes extraArgs,address indexed sender)" + data="$(jobRun.logData)" + topics="$(jobRun.logTopics)"] +generate_proof [type=vrfv2plus + publicKey="$(jobSpec.publicKey)" + requestBlockHash="$(jobRun.logBlockHash)" + requestBlockNumber="$(jobRun.logBlockNumber)" + topics="$(jobRun.logTopics)"] +estimate_gas [type=estimategaslimit + to="%s" + multiplier="1.1" + data="$(generate_proof.output)"] +simulate_fulfillment [type=ethcall + from="%s" + to="%s" + gas="$(estimate_gas)" + gasPrice="$(jobSpec.maxGasPrice)" + extractRevertReason=true + contract="%s" + data="$(generate_proof.output)"] +decode_log->generate_proof->estimate_gas->simulate_fulfillment +""" +` + BHSJobFormatted = `type = "blockhashstore" schemaVersion = 1 name = "blockhashstore" diff --git a/core/scripts/common/vrf/model/model.go b/core/scripts/common/vrf/model/model.go new file mode 100644 index 00000000000..bd0e3bbe364 --- /dev/null +++ b/core/scripts/common/vrf/model/model.go @@ -0,0 +1,46 @@ +package model + +import ( + "github.com/ethereum/go-ethereum/common" + "math/big" +) + +var ( + VRFPrimaryNodeName = "vrf-primary-node" + VRFBackupNodeName = "vrf-backup-node" + BHSNodeName = "bhs-node" + BHSBackupNodeName = "bhs-backup-node" + BHFNodeName = "bhf-node" +) + +type Node struct { + URL string + CredsFile string + SendingKeys []SendingKey + NumberOfSendingKeysToCreate int + SendingKeyFundingAmount *big.Int + VrfKeys []string + jobSpec string +} + +type SendingKey struct { + Address string + BalanceEth *big.Int +} + +type JobSpecs struct { + VRFPrimaryNode string + VRFBackupyNode string + BHSNode string + BHSBackupNode string + BHFNode string +} + +type ContractAddresses struct { + LinkAddress string + LinkEthAddress string + BhsContractAddress common.Address + BatchBHSAddress common.Address + CoordinatorAddress common.Address + BatchCoordinatorAddress common.Address +} diff --git a/core/scripts/vrfv2/testnet/setup-envs/README.md b/core/scripts/common/vrf/setup-envs/README.md similarity index 72% rename from core/scripts/vrfv2/testnet/setup-envs/README.md rename to core/scripts/common/vrf/setup-envs/README.md index a36e3829c43..33515338a24 100644 --- a/core/scripts/vrfv2/testnet/setup-envs/README.md +++ b/core/scripts/common/vrf/setup-envs/README.md @@ -4,8 +4,8 @@ * Currently possible to fund all nodes with one amount of native tokens ## Commands: 1. If using Docker Compose - 1. create `.env` file in `core/scripts/vrfv2/testnet/docker` (can use `sample.env` file as an example) - 2. go to `core/scripts/vrfv2/testnet/docker` folder and start containers - `docker compose up` + 1. create `.env` file in `core/scripts/common/vrf/docker` (can use `sample.env` file as an example) + 2. go to `core/scripts/common/vrf/docker` folder and start containers - `docker compose up` 2. Update [rpc-nodes.toml](..%2Fdocker%2Ftoml-config%2Frpc-nodes.toml) with relevant RPC nodes 3. Create files with credentials desirably outside `chainlink` repo (just not to push creds accidentally). Populate the files with relevant credentials for the nodes 4. Ensure that following env variables are set @@ -14,9 +14,10 @@ export ETH_URL= export ETH_CHAIN_ID= export ACCOUNT_KEY= ``` -5. execute from `core/scripts/vrfv2/testnet/setup-envs` folder +5. execute from `core/scripts/common/vrf/setup-envs` folder ``` go run . \ +--vrf-version="v2plus" \ --vrf-primary-node-url=http://localhost:6610 \ --vrf-primary-creds-file \ --vrf-backup-node-url=http://localhost:6611 \ @@ -27,13 +28,14 @@ go run . \ --bhs-bk-creds-file \ --bhf-node-url=http://localhost:6614 \ --bhf-creds-file \ ---deploy-contracts true \ ---batch-fulfillment-enabled true \ ---min-confs 1 \ ---num-eth-keys 5 \ ---num-vrf-keys 1 \ ---sending-key-funding-amount 100000000000000000 - +--deploy-contracts-and-create-jobs="true" \ +--subscription-balance="1e19" \ +--subscription-balance-native="1e18" \ +--batch-fulfillment-enabled="true" \ +--min-confs=3 \ +--num-eth-keys=1 \ +--num-vrf-keys=1 \ +--sending-key-funding-amount="1e17" ``` Optional parameters - will not be deployed if specified (NOT WORKING YET) diff --git a/core/scripts/vrfv2/testnet/setup-envs/main.go b/core/scripts/common/vrf/setup-envs/main.go similarity index 71% rename from core/scripts/vrfv2/testnet/setup-envs/main.go rename to core/scripts/common/vrf/setup-envs/main.go index 9e6edf725e5..6748408f476 100644 --- a/core/scripts/vrfv2/testnet/setup-envs/main.go +++ b/core/scripts/common/vrf/setup-envs/main.go @@ -5,18 +5,23 @@ import ( "encoding/json" "flag" "fmt" + "io" + "math/big" + "os" + "strings" + "github.com/ethereum/go-ethereum/common" + "github.com/shopspring/decimal" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" - "github.com/smartcontractkit/chainlink/core/scripts/vrfv2/testnet/constants" - "github.com/smartcontractkit/chainlink/core/scripts/vrfv2/testnet/scripts" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/constants" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/model" + "github.com/smartcontractkit/chainlink/core/scripts/vrfv2/testnet/v2scripts" + "github.com/smartcontractkit/chainlink/core/scripts/vrfv2plus/testnet/v2plusscripts" clcmd "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" "github.com/urfave/cli" - "io" - "math/big" - "os" - "strings" ) func newApp(remoteNodeURL string, writer io.Writer) (*clcmd.Shell, *cli.App) { @@ -54,7 +59,7 @@ func main() { bhsNodeURL := flag.String("bhs-node-url", "", "remote node URL") bhsBackupNodeURL := flag.String("bhs-backup-node-url", "", "remote node URL") bhfNodeURL := flag.String("bhf-node-url", "", "remote node URL") - nodeSendingKeyFundingAmount := flag.Int64("sending-key-funding-amount", constants.NodeSendingKeyFundingAmountGwei, "remote node URL") + nodeSendingKeyFundingAmount := flag.String("sending-key-funding-amount", constants.NodeSendingKeyFundingAmount, "sending key funding amount") vrfPrimaryCredsFile := flag.String("vrf-primary-creds-file", "", "Creds to authenticate to the node") vrfBackupCredsFile := flag.String("vrf-bk-creds-file", "", "Creds to authenticate to the node") @@ -65,12 +70,15 @@ func main() { numEthKeys := flag.Int("num-eth-keys", 5, "Number of eth keys to create") maxGasPriceGwei := flag.Int("max-gas-price-gwei", -1, "Max gas price gwei of the eth keys") numVRFKeys := flag.Int("num-vrf-keys", 1, "Number of vrf keys to create") + batchFulfillmentEnabled := flag.Bool("batch-fulfillment-enabled", constants.BatchFulfillmentEnabled, "whether to enable batch fulfillment on Cl node") - deployContracts := flag.Bool("deploy-contracts", true, "whether to deploy contracts and create jobs") + vrfVersion := flag.String("vrf-version", "v2", "VRF version to use") + deployContractsAndCreateJobs := flag.Bool("deploy-contracts-and-create-jobs", false, "whether to deploy contracts and create jobs") - batchFulfillmentEnabled := flag.Bool("batch-fulfillment-enabled", constants.BatchFulfillmentEnabled, "whether to enable batch fulfillment on Cl node") - minConfs := flag.Int("min-confs", constants.MinConfs, "minimum confirmations") + subscriptionBalanceJuelsString := flag.String("subscription-balance", constants.SubscriptionBalanceJuels, "amount to fund subscription with Link token (Juels)") + subscriptionBalanceNativeWeiString := flag.String("subscription-balance-native", constants.SubscriptionBalanceNativeWei, "amount to fund subscription with native token (Wei)") + minConfs := flag.Int("min-confs", constants.MinConfs, "minimum confirmations") linkAddress := flag.String("link-address", "", "address of link token") linkEthAddress := flag.String("link-eth-feed", "", "address of link eth feed") bhsContractAddressString := flag.String("bhs-address", "", "address of BHS contract") @@ -80,41 +88,50 @@ func main() { e := helpers.SetupEnv(false) flag.Parse() - nodesMap := make(map[string]scripts.Node) + nodesMap := make(map[string]model.Node) + + if *vrfVersion != "v2" && *vrfVersion != "v2plus" { + panic(fmt.Sprintf("Invalid VRF Version `%s`. Only `v2` and `v2plus` are supported", *vrfVersion)) + } + fmt.Println("Using VRF Version:", *vrfVersion) + + fundingAmount := decimal.RequireFromString(*nodeSendingKeyFundingAmount).BigInt() + subscriptionBalanceJuels := decimal.RequireFromString(*subscriptionBalanceJuelsString).BigInt() + subscriptionBalanceNativeWei := decimal.RequireFromString(*subscriptionBalanceNativeWeiString).BigInt() if *vrfPrimaryNodeURL != "" { - nodesMap[scripts.VRFPrimaryNodeName] = scripts.Node{ + nodesMap[model.VRFPrimaryNodeName] = model.Node{ URL: *vrfPrimaryNodeURL, - SendingKeyFundingAmount: *big.NewInt(*nodeSendingKeyFundingAmount), + SendingKeyFundingAmount: fundingAmount, CredsFile: *vrfPrimaryCredsFile, } } if *vrfBackupNodeURL != "" { - nodesMap[scripts.VRFBackupNodeName] = scripts.Node{ + nodesMap[model.VRFBackupNodeName] = model.Node{ URL: *vrfBackupNodeURL, - SendingKeyFundingAmount: *big.NewInt(*nodeSendingKeyFundingAmount), + SendingKeyFundingAmount: fundingAmount, CredsFile: *vrfBackupCredsFile, } } if *bhsNodeURL != "" { - nodesMap[scripts.BHSNodeName] = scripts.Node{ + nodesMap[model.BHSNodeName] = model.Node{ URL: *bhsNodeURL, - SendingKeyFundingAmount: *big.NewInt(*nodeSendingKeyFundingAmount), + SendingKeyFundingAmount: fundingAmount, CredsFile: *bhsCredsFile, } } if *bhsBackupNodeURL != "" { - nodesMap[scripts.BHSBackupNodeName] = scripts.Node{ + nodesMap[model.BHSBackupNodeName] = model.Node{ URL: *bhsBackupNodeURL, - SendingKeyFundingAmount: *big.NewInt(*nodeSendingKeyFundingAmount), + SendingKeyFundingAmount: fundingAmount, CredsFile: *bhsBackupCredsFile, } } if *bhfNodeURL != "" { - nodesMap[scripts.BHFNodeName] = scripts.Node{ + nodesMap[model.BHFNodeName] = model.Node{ URL: *bhfNodeURL, - SendingKeyFundingAmount: *big.NewInt(*nodeSendingKeyFundingAmount), + SendingKeyFundingAmount: fundingAmount, CredsFile: *bhfCredsFile, } } @@ -124,14 +141,14 @@ func main() { client, app := connectToNode(&node.URL, output, node.CredsFile) ethKeys := createETHKeysIfNeeded(client, app, output, numEthKeys, &node.URL, maxGasPriceGwei) - if key == scripts.VRFPrimaryNodeName { + if key == model.VRFPrimaryNodeName { vrfKeys := createVRFKeyIfNeeded(client, app, output, numVRFKeys, &node.URL) node.VrfKeys = mapVrfKeysToStringArr(vrfKeys) printVRFKeyData(vrfKeys) exportVRFKey(client, app, vrfKeys[0], output) } - if key == scripts.VRFBackupNodeName { + if key == model.VRFBackupNodeName { vrfKeys := getVRFKeys(client, app, output) node.VrfKeys = mapVrfKeysToStringArr(vrfKeys) } @@ -141,23 +158,11 @@ func main() { fundNodesIfNeeded(node, key, e) nodesMap[key] = node } - importVRFKeyToNodeIfSet(vrfBackupNodeURL, nodesMap, output, nodesMap[scripts.VRFBackupNodeName].CredsFile) - fmt.Println() + importVRFKeyToNodeIfSet(vrfBackupNodeURL, nodesMap, output, nodesMap[model.VRFBackupNodeName].CredsFile) - if *deployContracts { - feeConfig := vrf_coordinator_v2.VRFCoordinatorV2FeeConfig{ - FulfillmentFlatFeeLinkPPMTier1: uint32(constants.FlatFeeTier1), - FulfillmentFlatFeeLinkPPMTier2: uint32(constants.FlatFeeTier2), - FulfillmentFlatFeeLinkPPMTier3: uint32(constants.FlatFeeTier3), - FulfillmentFlatFeeLinkPPMTier4: uint32(constants.FlatFeeTier4), - FulfillmentFlatFeeLinkPPMTier5: uint32(constants.FlatFeeTier5), - ReqsForTier2: big.NewInt(constants.ReqsForTier2), - ReqsForTier3: big.NewInt(constants.ReqsForTier3), - ReqsForTier4: big.NewInt(constants.ReqsForTier4), - ReqsForTier5: big.NewInt(constants.ReqsForTier5), - } + if *deployContractsAndCreateJobs { - contractAddresses := scripts.ContractAddresses{ + contractAddresses := model.ContractAddresses{ LinkAddress: *linkAddress, LinkEthAddress: *linkEthAddress, BhsContractAddress: common.HexToAddress(*bhsContractAddressString), @@ -166,24 +171,65 @@ func main() { BatchCoordinatorAddress: common.HexToAddress(*batchCoordinatorAddressString), } - coordinatorConfig := scripts.CoordinatorConfig{ - MinConfs: minConfs, - MaxGasLimit: &constants.MaxGasLimit, - StalenessSeconds: &constants.StalenessSeconds, - GasAfterPayment: &constants.GasAfterPayment, - FallbackWeiPerUnitLink: constants.FallbackWeiPerUnitLink, - FeeConfig: feeConfig, - } + var jobSpecs model.JobSpecs + + switch *vrfVersion { + case "v2": + feeConfigV2 := vrf_coordinator_v2.VRFCoordinatorV2FeeConfig{ + FulfillmentFlatFeeLinkPPMTier1: uint32(constants.FlatFeeTier1), + FulfillmentFlatFeeLinkPPMTier2: uint32(constants.FlatFeeTier2), + FulfillmentFlatFeeLinkPPMTier3: uint32(constants.FlatFeeTier3), + FulfillmentFlatFeeLinkPPMTier4: uint32(constants.FlatFeeTier4), + FulfillmentFlatFeeLinkPPMTier5: uint32(constants.FlatFeeTier5), + ReqsForTier2: big.NewInt(constants.ReqsForTier2), + ReqsForTier3: big.NewInt(constants.ReqsForTier3), + ReqsForTier4: big.NewInt(constants.ReqsForTier4), + ReqsForTier5: big.NewInt(constants.ReqsForTier5), + } + + coordinatorConfigV2 := v2scripts.CoordinatorConfigV2{ + MinConfs: minConfs, + MaxGasLimit: &constants.MaxGasLimit, + StalenessSeconds: &constants.StalenessSeconds, + GasAfterPayment: &constants.GasAfterPayment, + FallbackWeiPerUnitLink: constants.FallbackWeiPerUnitLink, + FeeConfig: feeConfigV2, + } - jobSpecs := scripts.VRFV2DeployUniverse( - e, - constants.SubscriptionBalanceJuels, - &nodesMap[scripts.VRFPrimaryNodeName].VrfKeys[0], - contractAddresses, - coordinatorConfig, - *batchFulfillmentEnabled, - nodesMap, - ) + jobSpecs = v2scripts.VRFV2DeployUniverse( + e, + subscriptionBalanceJuels, + &nodesMap[model.VRFPrimaryNodeName].VrfKeys[0], + contractAddresses, + coordinatorConfigV2, + *batchFulfillmentEnabled, + nodesMap, + ) + case "v2plus": + feeConfigV2Plus := vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig{ + FulfillmentFlatFeeLinkPPM: uint32(constants.FlatFeeLinkPPM), + FulfillmentFlatFeeNativePPM: uint32(constants.FlatFeeNativePPM), + } + coordinatorConfigV2Plus := v2plusscripts.CoordinatorConfigV2Plus{ + MinConfs: minConfs, + MaxGasLimit: &constants.MaxGasLimit, + StalenessSeconds: &constants.StalenessSeconds, + GasAfterPayment: &constants.GasAfterPayment, + FallbackWeiPerUnitLink: constants.FallbackWeiPerUnitLink, + FeeConfig: feeConfigV2Plus, + } + + jobSpecs = v2plusscripts.VRFV2PlusDeployUniverse( + e, + subscriptionBalanceJuels, + subscriptionBalanceNativeWei, + &nodesMap[model.VRFPrimaryNodeName].VrfKeys[0], + contractAddresses, + coordinatorConfigV2Plus, + *batchFulfillmentEnabled, + nodesMap, + ) + } for key, node := range nodesMap { client, app := connectToNode(&node.URL, output, node.CredsFile) @@ -196,41 +242,43 @@ func main() { deleteJob(jobID, client, app, output) } //CREATE JOBS + switch key { - case scripts.VRFPrimaryNodeName: + case model.VRFPrimaryNodeName: createJob(jobSpecs.VRFPrimaryNode, client, app, output) - case scripts.VRFBackupNodeName: + case model.VRFBackupNodeName: createJob(jobSpecs.VRFBackupyNode, client, app, output) - case scripts.BHSNodeName: + case model.BHSNodeName: createJob(jobSpecs.BHSNode, client, app, output) - case scripts.BHSBackupNodeName: + case model.BHSBackupNodeName: createJob(jobSpecs.BHSBackupNode, client, app, output) - case scripts.BHFNodeName: + case model.BHFNodeName: createJob(jobSpecs.BHFNode, client, app, output) } } } - } -func fundNodesIfNeeded(node scripts.Node, key string, e helpers.Environment) { - if node.SendingKeyFundingAmount.Int64() > 0 { - fmt.Println("\nFunding", key, "Node's Sending Keys...") +func fundNodesIfNeeded(node model.Node, key string, e helpers.Environment) { + if node.SendingKeyFundingAmount.Cmp(big.NewInt(0)) == 1 { + fmt.Println("\nFunding", key, "Node's Sending Keys. Need to fund each key with", node.SendingKeyFundingAmount, "wei") for _, sendingKey := range node.SendingKeys { - fundingToSendWei := node.SendingKeyFundingAmount.Int64() - sendingKey.BalanceEth.Int64() - if fundingToSendWei > 0 { - helpers.FundNode(e, sendingKey.Address, big.NewInt(fundingToSendWei)) + fundingToSendWei := new(big.Int).Sub(node.SendingKeyFundingAmount, sendingKey.BalanceEth) + if fundingToSendWei.Cmp(big.NewInt(0)) == 1 { + helpers.FundNode(e, sendingKey.Address, fundingToSendWei) } else { - fmt.Println("\nSkipping Funding", sendingKey.Address, "since it has", sendingKey.BalanceEth.Int64(), "wei") + fmt.Println("\nSkipping Funding", sendingKey.Address, "since it has", sendingKey.BalanceEth.String(), "wei") } } + } else { + fmt.Println("\nSkipping Funding", key, "Node's Sending Keys since funding amount is 0 wei") } } -func importVRFKeyToNodeIfSet(vrfBackupNodeURL *string, nodes map[string]scripts.Node, output *bytes.Buffer, file string) { +func importVRFKeyToNodeIfSet(vrfBackupNodeURL *string, nodes map[string]model.Node, output *bytes.Buffer, file string) { if *vrfBackupNodeURL != "" { - vrfBackupNode := nodes[scripts.VRFBackupNodeName] - vrfPrimaryNode := nodes[scripts.VRFBackupNodeName] + vrfBackupNode := nodes[model.VRFBackupNodeName] + vrfPrimaryNode := nodes[model.VRFBackupNodeName] if len(vrfBackupNode.VrfKeys) == 0 || vrfPrimaryNode.VrfKeys[0] != vrfBackupNode.VrfKeys[0] { client, app := connectToNode(&vrfBackupNode.URL, output, file) @@ -330,15 +378,14 @@ func printETHKeyData(ethKeys []presenters.ETHKeyResource) { fmt.Println("Address: ", ethKey.Address) fmt.Println("MaxGasPriceWei: ", ethKey.MaxGasPriceWei) fmt.Println("EthBalance: ", ethKey.EthBalance) - fmt.Println("NextNonce: ", ethKey.NextNonce) fmt.Println("-----------------------------") } } -func mapEthKeysToSendingKeyArr(ethKeys []presenters.ETHKeyResource) []scripts.SendingKey { - var sendingKeys []scripts.SendingKey +func mapEthKeysToSendingKeyArr(ethKeys []presenters.ETHKeyResource) []model.SendingKey { + var sendingKeys []model.SendingKey for _, ethKey := range ethKeys { - sendingKey := scripts.SendingKey{Address: ethKey.Address, BalanceEth: *ethKey.EthBalance.ToInt()} + sendingKey := model.SendingKey{Address: ethKey.Address, BalanceEth: ethKey.EthBalance.ToInt()} sendingKeys = append(sendingKeys, sendingKey) } return sendingKeys diff --git a/core/scripts/common/vrf/util/util.go b/core/scripts/common/vrf/util/util.go new file mode 100644 index 00000000000..751aa013201 --- /dev/null +++ b/core/scripts/common/vrf/util/util.go @@ -0,0 +1,22 @@ +package util + +import ( + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/model" +) + +func MapToSendingKeyArr(nodeSendingKeys []string) []model.SendingKey { + var sendingKeys []model.SendingKey + + for _, key := range nodeSendingKeys { + sendingKeys = append(sendingKeys, model.SendingKey{Address: key}) + } + return sendingKeys +} + +func MapToAddressArr(sendingKeys []model.SendingKey) []string { + var sendingKeysString []string + for _, sendingKey := range sendingKeys { + sendingKeysString = append(sendingKeysString, sendingKey.Address) + } + return sendingKeysString +} diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 00ea273fbfa..8be75d4e7b9 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -8,7 +8,7 @@ replace github.com/smartcontractkit/chainlink/v2 => ../../ require ( github.com/ava-labs/coreth v0.12.1 github.com/avast/retry-go v3.0.0+incompatible - github.com/docker/docker v24.0.4+incompatible + github.com/docker/docker v24.0.6+incompatible github.com/docker/go-connections v0.4.0 github.com/ethereum/go-ethereum v1.12.0 github.com/google/go-cmp v0.5.9 @@ -57,7 +57,6 @@ require ( github.com/ava-labs/avalanchego v1.10.1 // indirect github.com/avast/retry-go/v4 v4.5.0 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect - github.com/benbjohnson/clock v1.3.4 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/blendle/zapdriver v1.3.1 // indirect @@ -151,8 +150,8 @@ require ( github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/sessions v1.2.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect - github.com/grafana/pyroscope-go v1.0.2 // indirect - github.com/grafana/pyroscope-go/godeltaprof v0.1.3 // indirect + github.com/grafana/pyroscope-go v1.0.4 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.4 // indirect github.com/graph-gophers/dataloader v5.0.0+incompatible // indirect github.com/graph-gophers/graphql-go v1.3.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect @@ -198,7 +197,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/compress v1.17.0 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/koron/go-ssdp v0.0.2 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -275,18 +274,18 @@ require ( github.com/mwitkow/grpc-proxy v0.0.0-20230212185441-f345521cb9c9 // indirect github.com/oklog/run v1.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc4 // indirect + github.com/opencontainers/image-spec v1.1.0-rc5 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/pressly/goose/v3 v3.15.0 // indirect - github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect + github.com/pressly/goose/v3 v3.15.1 // indirect + github.com/prometheus/client_golang v1.17.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.11.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/prometheus v0.46.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.4.4 // indirect @@ -297,12 +296,12 @@ require ( github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/scylladb/go-reflectx v1.0.1 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/shirou/gopsutil/v3 v3.23.8 // indirect + github.com/shirou/gopsutil/v3 v3.23.9 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 // indirect github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231003135342-5e581164f8dd // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231010203454-896f5c3c04d1 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect @@ -342,25 +341,24 @@ require ( go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 // indirect - go.opentelemetry.io/otel v1.16.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect + go.opentelemetry.io/otel v1.19.0 // indirect + go.opentelemetry.io/otel/metric v1.19.0 // indirect go.opentelemetry.io/otel/sdk v1.16.0 // indirect - go.opentelemetry.io/otel/trace v1.16.0 // indirect - go.uber.org/atomic v1.11.0 // indirect + go.opentelemetry.io/otel/trace v1.19.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect - go.uber.org/zap v1.24.0 // indirect + go.uber.org/zap v1.26.0 // indirect golang.org/x/arch v0.4.0 // indirect - golang.org/x/crypto v0.11.0 // indirect + golang.org/x/crypto v0.14.0 // indirect golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.12.0 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/term v0.10.0 // indirect - golang.org/x/text v0.11.0 // indirect + golang.org/x/mod v0.13.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sync v0.4.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.11.0 // indirect + golang.org/x/tools v0.14.0 // indirect gonum.org/v1/gonum v0.13.0 // indirect google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 640e5dd1982..5038435fa32 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -154,8 +154,6 @@ github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.4 h1:wj3BFPrTw8yYgA1OlMqvUk95nc8OMv3cvBSF5erT2W4= -github.com/benbjohnson/clock v1.3.4/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -244,8 +242,8 @@ github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0 github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= -github.com/containerd/continuity v0.4.1 h1:wQnVrjIyQ8vhU2sgOiL5T07jo+ouqc2bnKsv5/EqGhU= -github.com/containerd/continuity v0.4.1/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= +github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -335,8 +333,8 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v24.0.4+incompatible h1:s/LVDftw9hjblvqIeTiGYXBCD95nOEEl7qRsRrIOuQI= -github.com/docker/docker v24.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE= +github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -625,10 +623,10 @@ github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grafana/pyroscope-go v1.0.2 h1:dEFgO9VbhYTwuwpCC5coTpuW0JjISEWDZtvRAW9v5Tw= -github.com/grafana/pyroscope-go v1.0.2/go.mod h1:bShDKsVZdzxq+Ol6no0JKigU9y5FTWUcFditMXaH09o= -github.com/grafana/pyroscope-go/godeltaprof v0.1.3 h1:eunWpv1B3Z7ZK9o4499EmQGlY+CsDmSZ4FbxjRx37uk= -github.com/grafana/pyroscope-go/godeltaprof v0.1.3/go.mod h1:1HSPtjU8vLG0jE9JrTdzjgFqdJ/VgN7fvxBNq3luJko= +github.com/grafana/pyroscope-go v1.0.4 h1:oyQX0BOkL+iARXzHuCdIF5TQ7/sRSel1YFViMHC7Bm0= +github.com/grafana/pyroscope-go v1.0.4/go.mod h1:0d7ftwSMBV/Awm7CCiYmHQEG8Y44Ma3YSjt+nWcWztY= +github.com/grafana/pyroscope-go/godeltaprof v0.1.4 h1:mDsJ3ngul7UfrHibGQpV66PbZ3q1T8glz/tK3bQKKEk= +github.com/grafana/pyroscope-go/godeltaprof v0.1.4/go.mod h1:1HSPtjU8vLG0jE9JrTdzjgFqdJ/VgN7fvxBNq3luJko= github.com/graph-gophers/dataloader v5.0.0+incompatible h1:R+yjsbrNq1Mo3aPG+Z/EKYrXrXXUNJHOgbRt+U6jOug= github.com/graph-gophers/dataloader v5.0.0+incompatible/go.mod h1:jk4jk0c5ZISbKaMe8WsVopGB5/15GvGHMdMdPtwlRp4= github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= @@ -655,6 +653,8 @@ github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfm github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= +github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -883,8 +883,8 @@ github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0 github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= @@ -1322,10 +1322,10 @@ github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= -github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= -github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk= -github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= +github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/opencontainers/runc v1.1.9 h1:XR0VIHTGce5eWPkaPesqTBrhW2yAcaraWfsEalNwQLM= +github.com/opencontainers/runc v1.1.9/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= @@ -1360,20 +1360,20 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/pressly/goose/v3 v3.15.0 h1:6tY5aDqFknY6VZkorFGgZtWygodZQxfmmEF4rqyJW9k= -github.com/pressly/goose/v3 v3.15.0/go.mod h1:LlIo3zGccjb/YUgG+Svdb9Er14vefRdlDI7URCDrwYo= +github.com/pressly/goose/v3 v3.15.1 h1:dKaJ1SdLvS/+HtS8PzFT0KBEtICC1jewLXM+b3emlv8= +github.com/pressly/goose/v3 v3.15.1/go.mod h1:0E3Yg/+EwYzO6Rz2P98MlClFgIcoujbVRs575yi3iIM= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= +github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -1384,8 +1384,8 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk= -github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/prometheus/prometheus v0.46.0 h1:9JSdXnsuT6YsbODEhSQMwxNkGwPExfmzqG73vCMk/Kw= github.com/prometheus/prometheus v0.46.0/go.mod h1:10L5IJE5CEsjee1FnOcVswYXlPIscDWWt3IJ2UDYrz4= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= @@ -1438,8 +1438,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= -github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= +github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E= +github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -1458,8 +1458,8 @@ github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc4 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231003135342-5e581164f8dd h1:5r6SDRgZfi0kxc7D6sFV7h/bX+D7yewDq3FkyE0VMIM= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231003135342-5e581164f8dd/go.mod h1:agmAM21+teJkw0aj9KYj3q3s1sFkx3PXo5ibWJIrDfU= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca h1:x7M0m512gtXw5Z4B1WJPZ52VgshoIv+IvHqQ8hsH4AE= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231010203454-896f5c3c04d1 h1:Tabg69K9lvQsGiXBQ8tsK6aAKPsUc1e4DHiY8an1zMk= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231010203454-896f5c3c04d1/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 h1:ByVauKFXphRlSNG47lNuxZ9aicu+r8AoNp933VRPpCw= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918/go.mod h1:/yp/sqD8Iz5GU5fcercjrw0ivJF7HDcupYg+Gjr7EPg= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= @@ -1660,14 +1660,14 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= +go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= +go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= +go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1695,8 +1695,9 @@ go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= @@ -1736,8 +1737,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1776,8 +1777,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1837,8 +1838,8 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1863,8 +1864,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1957,15 +1958,17 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1976,8 +1979,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2052,8 +2055,8 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= -golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2252,20 +2255,20 @@ lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo= lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q= modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y= -modernc.org/ccgo/v3 v3.16.14 h1:af6KNtFgsVmnDYrWk3PQCS9XT6BXe7o3ZFJKkIKvXNQ= -modernc.org/ccgo/v3 v3.16.14/go.mod h1:mPDSujUIaTNWQSG4eqKw+atqLOEbma6Ncsa94WbC9zo= +modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0= +modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI= modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= -modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o= -modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= +modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA= -modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= -modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= -modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/sqlite v1.26.0 h1:SocQdLRSYlA8W99V8YH0NES75thx19d9sB/aFc4R8Lw= +modernc.org/sqlite v1.26.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= diff --git a/core/scripts/vrfv2/testnet/constants/constants.go b/core/scripts/vrfv2/testnet/constants/constants.go deleted file mode 100644 index 73356d48ffc..00000000000 --- a/core/scripts/vrfv2/testnet/constants/constants.go +++ /dev/null @@ -1,28 +0,0 @@ -package constants - -import ( - "github.com/smartcontractkit/chainlink/v2/core/assets" - "math/big" -) - -var ( - SubscriptionBalanceJuels = assets.Ether(10).ToInt() - - // optional flags - FallbackWeiPerUnitLink = big.NewInt(6e16) - BatchFulfillmentEnabled = true - MinConfs = 3 - NodeSendingKeyFundingAmountGwei = assets.GWei(0).Int64() //100000000 = 0.1 ETH - MaxGasLimit = int64(2.5e6) - StalenessSeconds = int64(86400) - GasAfterPayment = int64(33285) - FlatFeeTier1 = int64(500) - FlatFeeTier2 = int64(500) - FlatFeeTier3 = int64(500) - FlatFeeTier4 = int64(500) - FlatFeeTier5 = int64(500) - ReqsForTier2 = int64(0) - ReqsForTier3 = int64(0) - ReqsForTier4 = int64(0) - ReqsForTier5 = int64(0) -) diff --git a/core/scripts/vrfv2/testnet/main.go b/core/scripts/vrfv2/testnet/main.go index d418eb6d153..5b216776bd9 100644 --- a/core/scripts/vrfv2/testnet/main.go +++ b/core/scripts/vrfv2/testnet/main.go @@ -11,7 +11,7 @@ import ( "os" "strings" - "github.com/smartcontractkit/chainlink/core/scripts/vrfv2/testnet/scripts" + "github.com/smartcontractkit/chainlink/core/scripts/vrfv2/testnet/v2scripts" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner_test_consumer" "github.com/ethereum/go-ethereum" @@ -350,7 +350,7 @@ func main() { cmd := flag.NewFlagSet("batch-bhs-deploy", flag.ExitOnError) bhsAddr := cmd.String("bhs-address", "", "address of the blockhash store contract") helpers.ParseArgs(cmd, os.Args[2:], "bhs-address") - scripts.DeployBatchBHS(e, common.HexToAddress(*bhsAddr)) + v2scripts.DeployBatchBHS(e, common.HexToAddress(*bhsAddr)) case "batch-bhs-store": cmd := flag.NewFlagSet("batch-bhs-store", flag.ExitOnError) batchAddr := cmd.String("batch-bhs-address", "", "address of the batch bhs contract") @@ -418,7 +418,7 @@ func main() { } if *startBlock == -1 { - closestBlock, err2 := scripts.ClosestBlock(e, common.HexToAddress(*batchAddr), uint64(*endBlock), uint64(*batchSize)) + closestBlock, err2 := v2scripts.ClosestBlock(e, common.HexToAddress(*batchAddr), uint64(*endBlock), uint64(*batchSize)) // found a block with blockhash stored that's more recent that end block if err2 == nil { *startBlock = int64(closestBlock) @@ -491,14 +491,14 @@ func main() { helpers.PanicErr(err) fmt.Println("latest head number:", h.Number.String()) case "bhs-deploy": - scripts.DeployBHS(e) + v2scripts.DeployBHS(e) case "coordinator-deploy": coordinatorDeployCmd := flag.NewFlagSet("coordinator-deploy", flag.ExitOnError) coordinatorDeployLinkAddress := coordinatorDeployCmd.String("link-address", "", "address of link token") coordinatorDeployBHSAddress := coordinatorDeployCmd.String("bhs-address", "", "address of bhs") coordinatorDeployLinkEthFeedAddress := coordinatorDeployCmd.String("link-eth-feed", "", "address of link-eth-feed") helpers.ParseArgs(coordinatorDeployCmd, os.Args[2:], "link-address", "bhs-address", "link-eth-feed") - scripts.DeployCoordinator(e, *coordinatorDeployLinkAddress, *coordinatorDeployBHSAddress, *coordinatorDeployLinkEthFeedAddress) + v2scripts.DeployCoordinator(e, *coordinatorDeployLinkAddress, *coordinatorDeployBHSAddress, *coordinatorDeployLinkEthFeedAddress) case "coordinator-get-config": cmd := flag.NewFlagSet("coordinator-get-config", flag.ExitOnError) coordinatorAddress := cmd.String("coordinator-address", "", "coordinator address") @@ -507,7 +507,7 @@ func main() { coordinator, err := vrf_coordinator_v2.NewVRFCoordinatorV2(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - scripts.PrintCoordinatorConfig(coordinator) + v2scripts.PrintCoordinatorConfig(coordinator) case "coordinator-set-config": cmd := flag.NewFlagSet("coordinator-set-config", flag.ExitOnError) setConfigAddress := cmd.String("coordinator-address", "", "coordinator address") @@ -530,7 +530,7 @@ func main() { coordinator, err := vrf_coordinator_v2.NewVRFCoordinatorV2(common.HexToAddress(*setConfigAddress), e.Ec) helpers.PanicErr(err) - scripts.SetCoordinatorConfig( + v2scripts.SetCoordinatorConfig( e, *coordinator, uint16(*minConfs), @@ -564,7 +564,7 @@ func main() { *registerKeyUncompressedPubKey = strings.Replace(*registerKeyUncompressedPubKey, "0x", "04", 1) } - scripts.RegisterCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey, *registerKeyOracleAddress) + v2scripts.RegisterCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey, *registerKeyOracleAddress) case "coordinator-deregister-key": coordinatorDeregisterKey := flag.NewFlagSet("coordinator-deregister-key", flag.ExitOnError) deregisterKeyAddress := coordinatorDeregisterKey.String("address", "", "coordinator address") @@ -692,14 +692,14 @@ func main() { helpers.PanicErr(err) fmt.Printf("Request config %+v Rw %+v Rid %+v\n", rc, rw, rid) case "deploy-universe": - scripts.DeployUniverseViaCLI(e) + v2scripts.DeployUniverseViaCLI(e) case "eoa-consumer-deploy": consumerDeployCmd := flag.NewFlagSet("eoa-consumer-deploy", flag.ExitOnError) consumerCoordinator := consumerDeployCmd.String("coordinator-address", "", "coordinator address") consumerLinkAddress := consumerDeployCmd.String("link-address", "", "link-address") helpers.ParseArgs(consumerDeployCmd, os.Args[2:], "coordinator-address", "link-address") - scripts.EoaDeployConsumer(e, *consumerCoordinator, *consumerLinkAddress) + v2scripts.EoaDeployConsumer(e, *consumerCoordinator, *consumerLinkAddress) case "eoa-load-test-consumer-deploy": loadTestConsumerDeployCmd := flag.NewFlagSet("eoa-load-test-consumer-deploy", flag.ExitOnError) consumerCoordinator := loadTestConsumerDeployCmd.String("coordinator-address", "", "coordinator address") @@ -716,7 +716,7 @@ func main() { loadTestConsumerDeployCmd := flag.NewFlagSet("eoa-load-test-consumer-with-metrics-deploy", flag.ExitOnError) consumerCoordinator := loadTestConsumerDeployCmd.String("coordinator-address", "", "coordinator address") helpers.ParseArgs(loadTestConsumerDeployCmd, os.Args[2:], "coordinator-address") - scripts.EoaLoadTestConsumerWithMetricsDeploy(e, *consumerCoordinator) + v2scripts.EoaLoadTestConsumerWithMetricsDeploy(e, *consumerCoordinator) case "eoa-vrf-owner-test-consumer-deploy": loadTestConsumerDeployCmd := flag.NewFlagSet("eoa-vrf-owner-test-consumer-deploy", flag.ExitOnError) consumerCoordinator := loadTestConsumerDeployCmd.String("coordinator-address", "", "coordinator address") @@ -734,7 +734,7 @@ func main() { helpers.ParseArgs(createSubCmd, os.Args[2:], "coordinator-address") coordinator, err := vrf_coordinator_v2.NewVRFCoordinatorV2(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - scripts.EoaCreateSub(e, *coordinator) + v2scripts.EoaCreateSub(e, *coordinator) case "eoa-add-sub-consumer": addSubConsCmd := flag.NewFlagSet("eoa-add-sub-consumer", flag.ExitOnError) coordinatorAddress := addSubConsCmd.String("coordinator-address", "", "coordinator address") @@ -743,7 +743,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) - scripts.EoaAddConsumerToSub(e, *coordinator, uint64(*subID), *consumerAddress) + v2scripts.EoaAddConsumerToSub(e, *coordinator, uint64(*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) @@ -1029,7 +1029,7 @@ func main() { coordinator, err := vrf_coordinator_v2.NewVRFCoordinatorV2(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - scripts.EoaFundSubscription(e, *coordinator, *consumerLinkAddress, amount, uint64(*subID)) + v2scripts.EoaFundSubscription(e, *coordinator, *consumerLinkAddress, amount, uint64(*subID)) case "eoa-read": cmd := flag.NewFlagSet("eoa-read", flag.ExitOnError) consumerAddress := cmd.String("consumer", "", "consumer address") @@ -1197,7 +1197,7 @@ func main() { linkETHFeedAddress := cmd.String("link-eth-feed", "", "address of link-eth-feed") coordinatorAddress := cmd.String("coordinator-address", "", "address of the vrf coordinator v2 contract") helpers.ParseArgs(cmd, os.Args[2:], "link-address", "link-eth-feed", "coordinator-address") - scripts.WrapperDeploy(e, + v2scripts.WrapperDeploy(e, common.HexToAddress(*linkAddress), common.HexToAddress(*linkETHFeedAddress), common.HexToAddress(*coordinatorAddress)) @@ -1235,7 +1235,7 @@ func main() { maxNumWords := cmd.Uint("max-num-words", 10, "the keyhash that wrapper requests should use") helpers.ParseArgs(cmd, os.Args[2:], "wrapper-address", "key-hash") - scripts.WrapperConfigure(e, + v2scripts.WrapperConfigure(e, common.HexToAddress(*wrapperAddress), *wrapperGasOverhead, *coordinatorGasOverhead, @@ -1267,7 +1267,7 @@ func main() { wrapperAddress := cmd.String("wrapper-address", "", "address of the VRFV2Wrapper contract") helpers.ParseArgs(cmd, os.Args[2:], "link-address", "wrapper-address") - scripts.WrapperConsumerDeploy(e, + v2scripts.WrapperConsumerDeploy(e, common.HexToAddress(*linkAddress), common.HexToAddress(*wrapperAddress)) case "wrapper-consumer-request": @@ -1344,10 +1344,10 @@ func main() { batchBHSAddress := cmd.String("batch-bhs-address", "", "address of the batch blockhash store") batchSize := cmd.Uint64("batch-size", 100, "batch size") helpers.ParseArgs(cmd, os.Args[2:], "block-number", "batch-bhs-address") - _, err := scripts.ClosestBlock(e, common.HexToAddress(*batchBHSAddress), *blockNumber, *batchSize) + _, err := v2scripts.ClosestBlock(e, common.HexToAddress(*batchBHSAddress), *blockNumber, *batchSize) helpers.PanicErr(err) case "wrapper-universe-deploy": - scripts.DeployWrapperUniverse(e) + v2scripts.DeployWrapperUniverse(e) default: panic("unrecognized subcommand: " + os.Args[1]) } diff --git a/core/scripts/vrfv2/testnet/scripts/super_scripts.go b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go similarity index 83% rename from core/scripts/vrfv2/testnet/scripts/super_scripts.go rename to core/scripts/vrfv2/testnet/v2scripts/super_scripts.go index 3594636a604..f5e37005690 100644 --- a/core/scripts/vrfv2/testnet/scripts/super_scripts.go +++ b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go @@ -1,12 +1,14 @@ -package scripts +package v2scripts import ( "context" "encoding/hex" "flag" "fmt" - "github.com/smartcontractkit/chainlink/core/scripts/vrfv2/testnet/constants" - "github.com/smartcontractkit/chainlink/core/scripts/vrfv2/testnet/jobs" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/constants" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/jobs" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/model" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/util" "math/big" "os" "strings" @@ -22,47 +24,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" ) -var ( - VRFPrimaryNodeName = "vrf-primary-node" - VRFBackupNodeName = "vrf-backup-node" - BHSNodeName = "bhs-node" - BHSBackupNodeName = "bhs-backup-node" - BHFNodeName = "bhf-node" -) - -type Node struct { - URL string - CredsFile string - SendingKeys []SendingKey - NumberOfSendingKeysToCreate int - SendingKeyFundingAmount big.Int - VrfKeys []string - jobSpec string -} - -type SendingKey struct { - Address string - BalanceEth big.Int -} - -type JobSpecs struct { - VRFPrimaryNode string - VRFBackupyNode string - BHSNode string - BHSBackupNode string - BHFNode string -} - -type ContractAddresses struct { - LinkAddress string - LinkEthAddress string - BhsContractAddress common.Address - BatchBHSAddress common.Address - CoordinatorAddress common.Address - BatchCoordinatorAddress common.Address -} - -type CoordinatorConfig struct { +type CoordinatorConfigV2 struct { MinConfs *int MaxGasLimit *int64 StalenessSeconds *int64 @@ -82,8 +44,8 @@ func DeployUniverseViaCLI(e helpers.Environment) { coordinatorAddressString := *deployCmd.String("coordinator-address", "", "address of VRF Coordinator contract") batchCoordinatorAddressString := *deployCmd.String("batch-coordinator-address", "", "address Batch VRF Coordinator contract") - subscriptionBalanceJuelsString := deployCmd.String("subscription-balance", constants.SubscriptionBalanceJuels.String(), "amount to fund subscription") - nodeSendingKeyFundingAmount := deployCmd.Int64("sending-key-funding-amount", constants.NodeSendingKeyFundingAmountGwei, "CL node sending key funding amount") + subscriptionBalanceJuelsString := deployCmd.String("subscription-balance", constants.SubscriptionBalanceJuels, "amount to fund subscription") + nodeSendingKeyFundingAmount := deployCmd.String("sending-key-funding-amount", constants.NodeSendingKeyFundingAmount, "CL node sending key funding amount") batchFulfillmentEnabled := deployCmd.Bool("batch-fulfillment-enabled", constants.BatchFulfillmentEnabled, "whether send randomness fulfillments in batches inside one tx from CL node") @@ -127,11 +89,15 @@ func DeployUniverseViaCLI(e helpers.Environment) { vrfPrimaryNodeSendingKeys := strings.Split(*vrfPrimaryNodeSendingKeysString, ",") - nodesMap := make(map[string]Node) + nodesMap := make(map[string]model.Node) - nodesMap[VRFPrimaryNodeName] = Node{ - SendingKeys: mapToSendingKeyArr(vrfPrimaryNodeSendingKeys), - SendingKeyFundingAmount: *big.NewInt(*nodeSendingKeyFundingAmount), + fundingAmount, ok := new(big.Int).SetString(*nodeSendingKeyFundingAmount, 10) + if !ok { + panic(fmt.Sprintf("failed to parse node sending key funding amount '%s'", *nodeSendingKeyFundingAmount)) + } + nodesMap[model.VRFPrimaryNodeName] = model.Node{ + SendingKeys: util.MapToSendingKeyArr(vrfPrimaryNodeSendingKeys), + SendingKeyFundingAmount: fundingAmount, } bhsContractAddress := common.HexToAddress(bhsContractAddressString) @@ -139,7 +105,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { coordinatorAddress := common.HexToAddress(coordinatorAddressString) batchCoordinatorAddress := common.HexToAddress(batchCoordinatorAddressString) - contractAddresses := ContractAddresses{ + contractAddresses := model.ContractAddresses{ LinkAddress: linkAddress, LinkEthAddress: linkEthAddress, BhsContractAddress: bhsContractAddress, @@ -148,7 +114,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { BatchCoordinatorAddress: batchCoordinatorAddress, } - coordinatorConfig := CoordinatorConfig{ + coordinatorConfig := CoordinatorConfigV2{ MinConfs: minConfs, MaxGasLimit: maxGasLimit, StalenessSeconds: stalenessSeconds, @@ -167,31 +133,22 @@ func DeployUniverseViaCLI(e helpers.Environment) { nodesMap, ) - vrfPrimaryNode := nodesMap[VRFPrimaryNodeName] + vrfPrimaryNode := nodesMap[model.VRFPrimaryNodeName] fmt.Println("Funding node's sending keys...") for _, sendingKey := range vrfPrimaryNode.SendingKeys { - helpers.FundNode(e, sendingKey.Address, &vrfPrimaryNode.SendingKeyFundingAmount) + helpers.FundNode(e, sendingKey.Address, vrfPrimaryNode.SendingKeyFundingAmount) } } -func mapToSendingKeyArr(nodeSendingKeys []string) []SendingKey { - var sendingKeys []SendingKey - - for _, key := range nodeSendingKeys { - sendingKeys = append(sendingKeys, SendingKey{Address: key}) - } - return sendingKeys -} - func VRFV2DeployUniverse( e helpers.Environment, subscriptionBalanceJuels *big.Int, registerKeyUncompressedPubKey *string, - contractAddresses ContractAddresses, - coordinatorConfig CoordinatorConfig, + contractAddresses model.ContractAddresses, + coordinatorConfig CoordinatorConfigV2, batchFulfillmentEnabled bool, - nodesMap map[string]Node, -) JobSpecs { + nodesMap map[string]model.Node, +) model.JobSpecs { // Put key in ECDSA format if strings.HasPrefix(*registerKeyUncompressedPubKey, "0x") { @@ -246,7 +203,7 @@ func VRFV2DeployUniverse( if contractAddresses.BatchCoordinatorAddress.String() == "0x0000000000000000000000000000000000000000" { fmt.Println("\nDeploying Batch Coordinator...") - contractAddresses.BatchCoordinatorAddress = deployBatchCoordinatorV2(e, contractAddresses.CoordinatorAddress) + contractAddresses.BatchCoordinatorAddress = DeployBatchCoordinatorV2(e, contractAddresses.CoordinatorAddress) } fmt.Println("\nSetting Coordinator Config...") @@ -302,31 +259,31 @@ func VRFV2DeployUniverse( fmt.Printf("Subscription %+v\n", s) formattedVrfPrimaryJobSpec := fmt.Sprintf( - jobs.VRFJobFormatted, + jobs.VRFV2JobFormatted, contractAddresses.CoordinatorAddress, //coordinatorAddress contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress batchFulfillmentEnabled, //batchFulfillmentEnabled compressedPkHex, //publicKey *coordinatorConfig.MinConfs, //minIncomingConfirmations e.ChainID, //evmChainID - strings.Join(mapToAddressArr(nodesMap[VRFPrimaryNodeName].SendingKeys), "\",\""), //fromAddresses + strings.Join(util.MapToAddressArr(nodesMap[model.VRFPrimaryNodeName].SendingKeys), "\",\""), //fromAddresses contractAddresses.CoordinatorAddress, - nodesMap[VRFPrimaryNodeName].SendingKeys[0].Address, + nodesMap[model.VRFPrimaryNodeName].SendingKeys[0].Address, contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, ) formattedVrfBackupJobSpec := fmt.Sprintf( - jobs.VRFJobFormatted, + jobs.VRFV2JobFormatted, contractAddresses.CoordinatorAddress, //coordinatorAddress contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress batchFulfillmentEnabled, //batchFulfillmentEnabled compressedPkHex, //publicKey 100, //minIncomingConfirmations e.ChainID, //evmChainID - strings.Join(mapToAddressArr(nodesMap[VRFBackupNodeName].SendingKeys), "\",\""), //fromAddresses + strings.Join(util.MapToAddressArr(nodesMap[model.VRFBackupNodeName].SendingKeys), "\",\""), //fromAddresses contractAddresses.CoordinatorAddress, - nodesMap[VRFPrimaryNodeName].SendingKeys[0], + nodesMap[model.VRFPrimaryNodeName].SendingKeys[0], contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, ) @@ -338,7 +295,7 @@ func VRFV2DeployUniverse( 200, //lookbackBlocks contractAddresses.BhsContractAddress, //bhs address e.ChainID, //chain id - strings.Join(mapToAddressArr(nodesMap[BHSNodeName].SendingKeys), "\",\""), //sending addresses + strings.Join(util.MapToAddressArr(nodesMap[model.BHSNodeName].SendingKeys), "\",\""), //sending addresses ) formattedBHSBackupJobSpec := fmt.Sprintf( @@ -348,7 +305,7 @@ func VRFV2DeployUniverse( 200, //lookbackBlocks contractAddresses.BhsContractAddress, //bhs adreess e.ChainID, //chain id - strings.Join(mapToAddressArr(nodesMap[BHSBackupNodeName].SendingKeys), "\",\""), //sending addresses + strings.Join(util.MapToAddressArr(nodesMap[model.BHSBackupNodeName].SendingKeys), "\",\""), //sending addresses ) formattedBHFJobSpec := fmt.Sprintf( @@ -357,7 +314,7 @@ func VRFV2DeployUniverse( contractAddresses.BhsContractAddress, //bhs adreess contractAddresses.BatchBHSAddress, //batchBHS e.ChainID, //chain id - strings.Join(mapToAddressArr(nodesMap[BHFNodeName].SendingKeys), "\",\""), //sending addresses + strings.Join(util.MapToAddressArr(nodesMap[model.BHFNodeName].SendingKeys), "\",\""), //sending addresses ) fmt.Println( @@ -379,7 +336,7 @@ func VRFV2DeployUniverse( formattedVrfPrimaryJobSpec, ) - return JobSpecs{ + return model.JobSpecs{ VRFPrimaryNode: formattedVrfPrimaryJobSpec, VRFBackupyNode: formattedVrfBackupJobSpec, BHSNode: formattedBHSJobSpec, @@ -388,14 +345,6 @@ func VRFV2DeployUniverse( } } -func mapToAddressArr(sendingKeys []SendingKey) []string { - var sendingKeysString []string - for _, sendingKey := range sendingKeys { - sendingKeysString = append(sendingKeysString, sendingKey.Address) - } - return sendingKeysString -} - func DeployWrapperUniverse(e helpers.Environment) { cmd := flag.NewFlagSet("wrapper-universe-deploy", flag.ExitOnError) linkAddress := cmd.String("link-address", "", "address of link token") diff --git a/core/scripts/vrfv2/testnet/scripts/util.go b/core/scripts/vrfv2/testnet/v2scripts/util.go similarity index 99% rename from core/scripts/vrfv2/testnet/scripts/util.go rename to core/scripts/vrfv2/testnet/v2scripts/util.go index a55a78adb58..0e348e9c01c 100644 --- a/core/scripts/vrfv2/testnet/scripts/util.go +++ b/core/scripts/vrfv2/testnet/v2scripts/util.go @@ -1,4 +1,4 @@ -package scripts +package v2scripts import ( "context" @@ -53,7 +53,7 @@ func DeployCoordinator( return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) } -func deployBatchCoordinatorV2(e helpers.Environment, coordinatorAddress common.Address) (batchCoordinatorAddress common.Address) { +func DeployBatchCoordinatorV2(e helpers.Environment, coordinatorAddress common.Address) (batchCoordinatorAddress common.Address) { _, tx, _, err := batch_vrf_coordinator_v2.DeployBatchVRFCoordinatorV2(e.Owner, e.Ec, coordinatorAddress) helpers.PanicErr(err) return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) diff --git a/core/scripts/vrfv2plus/testnet/main.go b/core/scripts/vrfv2plus/testnet/main.go index 889350a61dd..0d1bf9a9481 100644 --- a/core/scripts/vrfv2plus/testnet/main.go +++ b/core/scripts/vrfv2plus/testnet/main.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "flag" "fmt" + "github.com/smartcontractkit/chainlink/core/scripts/vrfv2plus/testnet/v2plusscripts" "log" "math/big" "os" @@ -50,7 +51,6 @@ import ( var ( batchCoordinatorV2PlusABI = evmtypes.MustGetABI(batch_vrf_coordinator_v2plus.BatchVRFCoordinatorV2PlusABI) - coordinatorV2PlusABI = evmtypes.MustGetABI(vrf_coordinator_v2plus_interface.IVRFCoordinatorV2PlusInternalABI) ) func main() { @@ -102,9 +102,9 @@ func main() { helpers.PanicErr(err) fmt.Println("gas cost:", gasCost) case "smoke": - smokeTestVRF(e) + v2plusscripts.SmokeTestVRF(e) case "smoke-bhs": - smokeTestBHS(e) + v2plusscripts.SmokeTestBHS(e) case "manual-fulfill": cmd := flag.NewFlagSet("manual-fulfill", flag.ExitOnError) // In order to get the tx data for a fulfillment transaction, you can grep the @@ -337,7 +337,7 @@ func main() { cmd := flag.NewFlagSet("batch-bhs-deploy", flag.ExitOnError) bhsAddr := cmd.String("bhs-address", "", "address of the blockhash store contract") helpers.ParseArgs(cmd, os.Args[2:], "bhs-address") - deployBatchBHS(e, common.HexToAddress(*bhsAddr)) + v2plusscripts.DeployBatchBHS(e, common.HexToAddress(*bhsAddr)) case "batch-bhs-store": cmd := flag.NewFlagSet("batch-bhs-store", flag.ExitOnError) batchAddr := cmd.String("batch-bhs-address", "", "address of the batch bhs contract") @@ -513,14 +513,14 @@ func main() { helpers.PanicErr(err) fmt.Println("latest head number:", h.Number.String()) case "bhs-deploy": - deployBHS(e) + v2plusscripts.DeployBHS(e) case "coordinator-deploy": coordinatorDeployCmd := flag.NewFlagSet("coordinator-deploy", flag.ExitOnError) coordinatorDeployLinkAddress := coordinatorDeployCmd.String("link-address", "", "address of link token") coordinatorDeployBHSAddress := coordinatorDeployCmd.String("bhs-address", "", "address of bhs") coordinatorDeployLinkEthFeedAddress := coordinatorDeployCmd.String("link-eth-feed", "", "address of link-eth-feed") helpers.ParseArgs(coordinatorDeployCmd, os.Args[2:], "link-address", "bhs-address", "link-eth-feed") - deployCoordinator(e, *coordinatorDeployLinkAddress, *coordinatorDeployBHSAddress, *coordinatorDeployLinkEthFeedAddress) + v2plusscripts.DeployCoordinator(e, *coordinatorDeployLinkAddress, *coordinatorDeployBHSAddress, *coordinatorDeployLinkEthFeedAddress) case "coordinator-get-config": cmd := flag.NewFlagSet("coordinator-get-config", flag.ExitOnError) coordinatorAddress := cmd.String("coordinator-address", "", "coordinator address") @@ -529,7 +529,7 @@ func main() { coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - printCoordinatorConfig(coordinator) + v2plusscripts.PrintCoordinatorConfig(coordinator) case "coordinator-set-config": cmd := flag.NewFlagSet("coordinator-set-config", flag.ExitOnError) setConfigAddress := cmd.String("coordinator-address", "", "coordinator address") @@ -545,7 +545,7 @@ func main() { coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*setConfigAddress), e.Ec) helpers.PanicErr(err) - setCoordinatorConfig( + v2plusscripts.SetCoordinatorConfig( e, *coordinator, uint16(*minConfs), @@ -572,7 +572,7 @@ func main() { *registerKeyUncompressedPubKey = strings.Replace(*registerKeyUncompressedPubKey, "0x", "04", 1) } - registerCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey, *registerKeyOracleAddress) + v2plusscripts.RegisterCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey, *registerKeyOracleAddress) case "coordinator-deregister-key": coordinatorDeregisterKey := flag.NewFlagSet("coordinator-deregister-key", flag.ExitOnError) deregisterKeyAddress := coordinatorDeregisterKey.String("address", "", "coordinator address") @@ -704,7 +704,7 @@ func main() { helpers.PanicErr(err) fmt.Printf("Request config %+v Rw %+v Rid %+v\n", rc, rw, rid) case "deploy-universe": - deployUniverse(e) + v2plusscripts.DeployUniverseViaCLI(e) case "generate-proof-v2-plus": generateProofForV2Plus(e) case "eoa-consumer-deploy": @@ -713,7 +713,7 @@ func main() { consumerLinkAddress := consumerDeployCmd.String("link-address", "", "link-address") helpers.ParseArgs(consumerDeployCmd, os.Args[2:], "coordinator-address", "link-address", "key-hash") - eoaDeployConsumer(e, *consumerCoordinator, *consumerLinkAddress) + v2plusscripts.EoaDeployConsumer(e, *consumerCoordinator, *consumerLinkAddress) case "eoa-load-test-consumer-deploy": loadTestConsumerDeployCmd := flag.NewFlagSet("eoa-load-test-consumer-deploy", flag.ExitOnError) consumerCoordinator := loadTestConsumerDeployCmd.String("coordinator-address", "", "coordinator address") @@ -743,7 +743,7 @@ func main() { helpers.ParseArgs(createSubCmd, os.Args[2:], "coordinator-address") coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - eoaCreateSub(e, *coordinator) + v2plusscripts.EoaCreateSub(e, *coordinator) case "eoa-add-sub-consumer": addSubConsCmd := flag.NewFlagSet("eoa-add-sub-consumer", flag.ExitOnError) coordinatorAddress := addSubConsCmd.String("coordinator-address", "", "coordinator address") @@ -753,7 +753,7 @@ func main() { coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) parsedSubID := parseSubID(*subID) - eoaAddConsumerToSub(e, *coordinator, parsedSubID, *consumerAddress) + v2plusscripts.EoaAddConsumerToSub(e, *coordinator, parsedSubID, *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) @@ -969,12 +969,9 @@ func main() { if !s { panic(fmt.Sprintf("failed to parse top up amount '%s'", *amountStr)) } - coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) - helpers.PanicErr(err) - e.Owner.Value = amount - tx, err := coordinator.FundSubscriptionWithNative(e.Owner, parseSubID(*subID)) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) + parsedSubID := parseSubID(*subID) + + v2plusscripts.EoaFundSubWithNative(e, common.HexToAddress(*coordinatorAddress), parsedSubID, amount) case "eoa-fund-sub": fund := flag.NewFlagSet("eoa-fund-sub", flag.ExitOnError) coordinatorAddress := fund.String("coordinator-address", "", "coordinator address") @@ -989,7 +986,7 @@ func main() { coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - eoaFundSubscription(e, *coordinator, *consumerLinkAddress, amount, parseSubID(*subID)) + v2plusscripts.EoaFundSubWithLink(e, *coordinator, *consumerLinkAddress, amount, parseSubID(*subID)) case "eoa-read": cmd := flag.NewFlagSet("eoa-read", flag.ExitOnError) consumerAddress := cmd.String("consumer", "", "consumer address") @@ -1122,7 +1119,7 @@ func main() { linkETHFeedAddress := cmd.String("link-eth-feed", "", "address of link-eth-feed") coordinatorAddress := cmd.String("coordinator-address", "", "address of the vrf coordinator v2 contract") helpers.ParseArgs(cmd, os.Args[2:], "link-address", "link-eth-feed", "coordinator-address") - wrapperDeploy(e, + v2plusscripts.WrapperDeploy(e, common.HexToAddress(*linkAddress), common.HexToAddress(*linkETHFeedAddress), common.HexToAddress(*coordinatorAddress)) @@ -1164,7 +1161,7 @@ func main() { fulfillmentFlatFeeNativePPM := cmd.Uint("fulfillment-flat-fee-native-ppm", 500, "the native flat fee in ppm to charge for fulfillment") helpers.ParseArgs(cmd, os.Args[2:], "wrapper-address", "key-hash", "fallback-wei-per-unit-link") - wrapperConfigure(e, + v2plusscripts.WrapperConfigure(e, common.HexToAddress(*wrapperAddress), *wrapperGasOverhead, *coordinatorGasOverhead, @@ -1200,7 +1197,7 @@ func main() { wrapperAddress := cmd.String("wrapper-address", "", "address of the VRFV2Wrapper contract") helpers.ParseArgs(cmd, os.Args[2:], "link-address", "wrapper-address") - wrapperConsumerDeploy(e, + v2plusscripts.WrapperConsumerDeploy(e, common.HexToAddress(*linkAddress), common.HexToAddress(*wrapperAddress)) case "wrapper-consumer-request": @@ -1272,7 +1269,7 @@ func main() { helpers.ParseArgs(cmd, os.Args[2:]) _ = helpers.CalculateLatestBlockHeader(e, *blockNumber) case "wrapper-universe-deploy": - deployWrapperUniverse(e) + v2plusscripts.DeployWrapperUniverse(e) default: panic("unrecognized subcommand: " + os.Args[1]) } diff --git a/core/scripts/vrfv2plus/testnet/super_scripts.go b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go similarity index 61% rename from core/scripts/vrfv2plus/testnet/super_scripts.go rename to core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go index 24a737be111..f805e7b74f0 100644 --- a/core/scripts/vrfv2plus/testnet/super_scripts.go +++ b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go @@ -1,4 +1,4 @@ -package main +package v2plusscripts import ( "bytes" @@ -6,6 +6,12 @@ import ( "encoding/hex" "flag" "fmt" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/constants" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/jobs" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/model" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/util" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2plus_interface" "math/big" "os" "strings" @@ -18,7 +24,6 @@ import ( "github.com/shopspring/decimal" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" - "github.com/smartcontractkit/chainlink/v2/core/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" @@ -30,46 +35,18 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/vrf/proof" ) -const formattedVRFJob = ` -type = "vrf" -name = "vrf_v2_plus" -schemaVersion = 1 -coordinatorAddress = "%s" -batchCoordinatorAddress = "%s" -batchFulfillmentEnabled = %t -batchFulfillmentGasMultiplier = 1.1 -publicKey = "%s" -minIncomingConfirmations = 3 -evmChainID = "%d" -fromAddresses = ["%s"] -pollPeriod = "5s" -requestTimeout = "24h" -observationSource = """ -decode_log [type=ethabidecodelog - abi="RandomWordsRequested(bytes32 indexed keyHash,uint256 requestId,uint256 preSeed,uint256 indexed subId,uint16 minimumRequestConfirmations,uint32 callbackGasLimit,uint32 numWords,bytes extraArgs,address indexed sender)" - data="$(jobRun.logData)" - topics="$(jobRun.logTopics)"] -generate_proof [type=vrfv2plus - publicKey="$(jobSpec.publicKey)" - requestBlockHash="$(jobRun.logBlockHash)" - requestBlockNumber="$(jobRun.logBlockNumber)" - topics="$(jobRun.logTopics)"] -estimate_gas [type=estimategaslimit - to="%s" - multiplier="1.1" - data="$(generate_proof.output)"] -simulate_fulfillment [type=ethcall - to="%s" - gas="$(estimate_gas)" - gasPrice="$(jobSpec.maxGasPrice)" - extractRevertReason=true - contract="%s" - data="$(generate_proof.output)"] -decode_log->generate_proof->estimate_gas->simulate_fulfillment -""" -` - -func smokeTestVRF(e helpers.Environment) { +var coordinatorV2PlusABI = evmtypes.MustGetABI(vrf_coordinator_v2plus_interface.IVRFCoordinatorV2PlusInternalABI) + +type CoordinatorConfigV2Plus struct { + MinConfs *int + MaxGasLimit *int64 + StalenessSeconds *int64 + GasAfterPayment *int64 + FallbackWeiPerUnitLink *big.Int + FeeConfig vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig +} + +func SmokeTestVRF(e helpers.Environment) { smokeCmd := flag.NewFlagSet("smoke", flag.ExitOnError) // required flags @@ -120,7 +97,7 @@ func smokeTestVRF(e helpers.Environment) { var bhsContractAddress common.Address if len(*bhsAddressStr) == 0 { fmt.Println("\nDeploying BHS...") - bhsContractAddress = deployBHS(e) + bhsContractAddress = DeployBHS(e) } else { bhsContractAddress = common.HexToAddress(*bhsAddressStr) } @@ -128,7 +105,7 @@ func smokeTestVRF(e helpers.Environment) { var batchBHSAddress common.Address if len(*batchBHSAddressStr) == 0 { fmt.Println("\nDeploying Batch BHS...") - batchBHSAddress = deployBatchBHS(e, bhsContractAddress) + batchBHSAddress = DeployBatchBHS(e, bhsContractAddress) } else { batchBHSAddress = common.HexToAddress(*batchBHSAddressStr) } @@ -136,7 +113,7 @@ func smokeTestVRF(e helpers.Environment) { var coordinatorAddress common.Address if len(*coordinatorAddressStr) == 0 { fmt.Println("\nDeploying Coordinator...") - coordinatorAddress = deployCoordinator(e, *linkAddress, bhsContractAddress.String(), *linkEthAddress) + coordinatorAddress = DeployCoordinator(e, *linkAddress, bhsContractAddress.String(), *linkEthAddress) } else { coordinatorAddress = common.HexToAddress(*coordinatorAddressStr) } @@ -147,14 +124,14 @@ func smokeTestVRF(e helpers.Environment) { var batchCoordinatorAddress common.Address if len(*batchCoordinatorAddressStr) == 0 { fmt.Println("\nDeploying Batch Coordinator...") - batchCoordinatorAddress = deployBatchCoordinatorV2(e, coordinatorAddress) + batchCoordinatorAddress = DeployBatchCoordinatorV2(e, coordinatorAddress) } else { batchCoordinatorAddress = common.HexToAddress(*batchCoordinatorAddressStr) } if !*skipConfig { fmt.Println("\nSetting Coordinator Config...") - setCoordinatorConfig( + SetCoordinatorConfig( e, *coordinator, uint16(*minConfs), @@ -170,7 +147,7 @@ func smokeTestVRF(e helpers.Environment) { } fmt.Println("\nConfig set, getting current config from deployed contract...") - printCoordinatorConfig(coordinator) + PrintCoordinatorConfig(coordinator) // Generate compressed public key and key hash uncompressed, err := key.PublicKey.StringUncompressed() @@ -250,20 +227,20 @@ func smokeTestVRF(e helpers.Environment) { } fmt.Println("\nDeploying consumer...") - consumerAddress := eoaDeployConsumer(e, coordinatorAddress.String(), *linkAddress) + consumerAddress := EoaDeployConsumer(e, coordinatorAddress.String(), *linkAddress) fmt.Println("\nAdding subscription...") - eoaCreateSub(e, *coordinator) + EoaCreateSub(e, *coordinator) - subID := findSubscriptionID(e, coordinator) + subID := FindSubscriptionID(e, coordinator) helpers.PanicErr(err) fmt.Println("\nAdding consumer to subscription...") - eoaAddConsumerToSub(e, *coordinator, subID, consumerAddress.String()) + EoaAddConsumerToSub(e, *coordinator, subID, consumerAddress.String()) if subscriptionBalance.Cmp(big.NewInt(0)) > 0 { fmt.Println("\nFunding subscription with", subscriptionBalance, "juels...") - eoaFundSubscription(e, *coordinator, *linkAddress, subscriptionBalance, subID) + EoaFundSubWithLink(e, *coordinator, *linkAddress, subscriptionBalance, subID) } else { fmt.Println("Subscription", subID, "NOT getting funded. You must fund the subscription in order to use it!") } @@ -378,7 +355,7 @@ func smokeTestVRF(e helpers.Environment) { fmt.Println("\nfulfillment successful") } -func smokeTestBHS(e helpers.Environment) { +func SmokeTestBHS(e helpers.Environment) { smokeCmd := flag.NewFlagSet("smoke-bhs", flag.ExitOnError) // optional args @@ -390,7 +367,7 @@ func smokeTestBHS(e helpers.Environment) { var bhsContractAddress common.Address if len(*bhsAddress) == 0 { fmt.Println("\nDeploying BHS...") - bhsContractAddress = deployBHS(e) + bhsContractAddress = DeployBHS(e) } else { bhsContractAddress = common.HexToAddress(*bhsAddress) } @@ -398,7 +375,7 @@ func smokeTestBHS(e helpers.Environment) { var batchBHSContractAddress common.Address if len(*batchBHSAddress) == 0 { fmt.Println("\nDeploying Batch BHS...") - batchBHSContractAddress = deployBatchBHS(e, bhsContractAddress) + batchBHSContractAddress = DeployBatchBHS(e, bhsContractAddress) } else { batchBHSContractAddress = common.HexToAddress(*batchBHSAddress) } @@ -486,117 +463,183 @@ func sendTx(e helpers.Environment, to common.Address, data []byte) (*types.Recei e.ChainID, "send tx", signedTx.Hash().String(), "to", to.String()), signedTx.Hash() } -func deployUniverse(e helpers.Environment) { +func DeployUniverseViaCLI(e helpers.Environment) { deployCmd := flag.NewFlagSet("deploy-universe", flag.ExitOnError) // required flags - linkAddress := deployCmd.String("link-address", "", "address of link token") - linkEthAddress := deployCmd.String("link-eth-feed", "", "address of link eth feed") - bhsAddress := deployCmd.String("bhs-address", "", "address of blockhash store") - batchBHSAddress := deployCmd.String("batch-bhs-address", "", "address of batch blockhash store") - subscriptionBalanceString := deployCmd.String("subscription-balance", "1e19", "amount to fund subscription") + linkAddress := *deployCmd.String("link-address", "", "address of link token") + linkEthAddress := *deployCmd.String("link-eth-feed", "", "address of link eth feed") + bhsContractAddressString := *deployCmd.String("bhs-address", "", "address of BHS contract") + batchBHSAddressString := *deployCmd.String("batch-bhs-address", "", "address of Batch BHS contract") + coordinatorAddressString := *deployCmd.String("coordinator-address", "", "address of VRF Coordinator contract") + batchCoordinatorAddressString := *deployCmd.String("batch-coordinator-address", "", "address Batch VRF Coordinator contract") + subscriptionBalanceJuelsString := deployCmd.String("subscription-balance", "1e19", "amount to fund subscription with Link token (Juels)") + subscriptionBalanceNativeWeiString := deployCmd.String("subscription-balance-native", "1e18", "amount to fund subscription with native token (Wei)") + + batchFulfillmentEnabled := deployCmd.Bool("batch-fulfillment-enabled", constants.BatchFulfillmentEnabled, "whether send randomness fulfillments in batches inside one tx from CL node") // optional flags fallbackWeiPerUnitLinkString := deployCmd.String("fallback-wei-per-unit-link", "6e16", "fallback wei/link ratio") registerKeyUncompressedPubKey := deployCmd.String("uncompressed-pub-key", "", "uncompressed public key") - registerKeyOracleAddress := deployCmd.String("oracle-address", "", "oracle sender address") - minConfs := deployCmd.Int("min-confs", 3, "min confs") - oracleFundingAmount := deployCmd.Int64("oracle-funding-amount", assets.GWei(100_000_000).Int64(), "amount to fund sending oracle") - maxGasLimit := deployCmd.Int64("max-gas-limit", 2.5e6, "max gas limit") - stalenessSeconds := deployCmd.Int64("staleness-seconds", 86400, "staleness in seconds") - gasAfterPayment := deployCmd.Int64("gas-after-payment", 33285, "gas after payment calculation") - flatFeeLinkPPM := deployCmd.Int64("flat-fee-link-ppm", 500, "fulfillment flat fee LINK ppm") - flatFeeEthPPM := deployCmd.Int64("flat-fee-eth-ppm", 500, "fulfillment flat fee ETH ppm") + vrfPrimaryNodeSendingKeysString := deployCmd.String("vrf-primary-node-sending-keys", "", "VRF Primary Node sending keys") + minConfs := deployCmd.Int("min-confs", constants.MinConfs, "min confs") + nodeSendingKeyFundingAmount := deployCmd.String("sending-key-funding-amount", constants.NodeSendingKeyFundingAmount, "CL node sending key funding amount") + maxGasLimit := deployCmd.Int64("max-gas-limit", constants.MaxGasLimit, "max gas limit") + stalenessSeconds := deployCmd.Int64("staleness-seconds", constants.StalenessSeconds, "staleness in seconds") + gasAfterPayment := deployCmd.Int64("gas-after-payment", constants.GasAfterPayment, "gas after payment calculation") + flatFeeLinkPPM := deployCmd.Int64("flat-fee-link-ppm", constants.FlatFeeLinkPPM, "fulfillment flat fee LINK ppm") + flatFeeEthPPM := deployCmd.Int64("flat-fee-eth-ppm", constants.FlatFeeNativePPM, "fulfillment flat fee ETH ppm") - helpers.ParseArgs(deployCmd, os.Args[2:]) + helpers.ParseArgs( + deployCmd, os.Args[2:], + ) fallbackWeiPerUnitLink := decimal.RequireFromString(*fallbackWeiPerUnitLinkString).BigInt() - subscriptionBalance := decimal.RequireFromString(*subscriptionBalanceString).BigInt() + subscriptionBalanceJuels := decimal.RequireFromString(*subscriptionBalanceJuelsString).BigInt() + subscriptionBalanceNativeWei := decimal.RequireFromString(*subscriptionBalanceNativeWeiString).BigInt() + fundingAmount := decimal.RequireFromString(*nodeSendingKeyFundingAmount).BigInt() + + feeConfig := vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig{ + FulfillmentFlatFeeLinkPPM: uint32(*flatFeeLinkPPM), + FulfillmentFlatFeeNativePPM: uint32(*flatFeeEthPPM), + } + vrfPrimaryNodeSendingKeys := strings.Split(*vrfPrimaryNodeSendingKeysString, ",") + + nodesMap := make(map[string]model.Node) + + nodesMap[model.VRFPrimaryNodeName] = model.Node{ + SendingKeys: util.MapToSendingKeyArr(vrfPrimaryNodeSendingKeys), + SendingKeyFundingAmount: fundingAmount, + } + + bhsContractAddress := common.HexToAddress(bhsContractAddressString) + batchBHSAddress := common.HexToAddress(batchBHSAddressString) + coordinatorAddress := common.HexToAddress(coordinatorAddressString) + batchCoordinatorAddress := common.HexToAddress(batchCoordinatorAddressString) + + contractAddresses := model.ContractAddresses{ + LinkAddress: linkAddress, + LinkEthAddress: linkEthAddress, + BhsContractAddress: bhsContractAddress, + BatchBHSAddress: batchBHSAddress, + CoordinatorAddress: coordinatorAddress, + BatchCoordinatorAddress: batchCoordinatorAddress, + } + + coordinatorConfig := CoordinatorConfigV2Plus{ + MinConfs: minConfs, + MaxGasLimit: maxGasLimit, + StalenessSeconds: stalenessSeconds, + GasAfterPayment: gasAfterPayment, + FallbackWeiPerUnitLink: fallbackWeiPerUnitLink, + FeeConfig: feeConfig, + } + + VRFV2PlusDeployUniverse( + e, + subscriptionBalanceJuels, + subscriptionBalanceNativeWei, + registerKeyUncompressedPubKey, + contractAddresses, + coordinatorConfig, + *batchFulfillmentEnabled, + nodesMap, + ) + + vrfPrimaryNode := nodesMap[model.VRFPrimaryNodeName] + fmt.Println("Funding node's sending keys...") + for _, sendingKey := range vrfPrimaryNode.SendingKeys { + helpers.FundNode(e, sendingKey.Address, vrfPrimaryNode.SendingKeyFundingAmount) + } +} + +func VRFV2PlusDeployUniverse(e helpers.Environment, + subscriptionBalanceJuels *big.Int, + subscriptionBalanceNativeWei *big.Int, + registerKeyUncompressedPubKey *string, + contractAddresses model.ContractAddresses, + coordinatorConfig CoordinatorConfigV2Plus, + batchFulfillmentEnabled bool, + nodesMap map[string]model.Node, +) model.JobSpecs { // Put key in ECDSA format if strings.HasPrefix(*registerKeyUncompressedPubKey, "0x") { *registerKeyUncompressedPubKey = strings.Replace(*registerKeyUncompressedPubKey, "0x", "04", 1) } - if len(*linkAddress) == 0 { + // Generate compressed public key and key hash + pubBytes, err := hex.DecodeString(*registerKeyUncompressedPubKey) + helpers.PanicErr(err) + pk, err := crypto.UnmarshalPubkey(pubBytes) + helpers.PanicErr(err) + var pkBytes []byte + if big.NewInt(0).Mod(pk.Y, big.NewInt(2)).Uint64() != 0 { + pkBytes = append(pk.X.Bytes(), 1) + } else { + pkBytes = append(pk.X.Bytes(), 0) + } + var newPK secp256k1.PublicKey + copy(newPK[:], pkBytes) + + compressedPkHex := hexutil.Encode(pkBytes) + keyHash, err := newPK.Hash() + helpers.PanicErr(err) + + if len(contractAddresses.LinkAddress) == 0 { fmt.Println("\nDeploying LINK Token...") - address := helpers.DeployLinkToken(e).String() - linkAddress = &address + contractAddresses.LinkAddress = helpers.DeployLinkToken(e).String() } - if len(*linkEthAddress) == 0 { + if len(contractAddresses.LinkEthAddress) == 0 { fmt.Println("\nDeploying LINK/ETH Feed...") - address := helpers.DeployLinkEthFeed(e, *linkAddress, fallbackWeiPerUnitLink).String() - linkEthAddress = &address + contractAddresses.LinkEthAddress = helpers.DeployLinkEthFeed(e, contractAddresses.LinkAddress, coordinatorConfig.FallbackWeiPerUnitLink).String() } - var bhsContractAddress common.Address - if len(*bhsAddress) == 0 { + if contractAddresses.BhsContractAddress.String() == "0x0000000000000000000000000000000000000000" { fmt.Println("\nDeploying BHS...") - bhsContractAddress = deployBHS(e) - } else { - bhsContractAddress = common.HexToAddress(*bhsAddress) + contractAddresses.BhsContractAddress = DeployBHS(e) } - var batchBHSContractAddress common.Address - if len(*batchBHSAddress) == 0 { + if contractAddresses.BatchBHSAddress.String() == "0x0000000000000000000000000000000000000000" { fmt.Println("\nDeploying Batch BHS...") - batchBHSContractAddress = deployBatchBHS(e, bhsContractAddress) - } else { - batchBHSContractAddress = common.HexToAddress(*batchBHSAddress) + contractAddresses.BatchBHSAddress = DeployBatchBHS(e, contractAddresses.BhsContractAddress) } - var coordinatorAddress common.Address - fmt.Println("\nDeploying Coordinator...") - coordinatorAddress = deployCoordinator(e, *linkAddress, bhsContractAddress.String(), *linkEthAddress) + if contractAddresses.CoordinatorAddress.String() == "0x0000000000000000000000000000000000000000" { + fmt.Println("\nDeploying Coordinator...") + contractAddresses.CoordinatorAddress = DeployCoordinator(e, contractAddresses.LinkAddress, contractAddresses.BhsContractAddress.String(), contractAddresses.LinkEthAddress) + } - coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(coordinatorAddress, e.Ec) + coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(contractAddresses.CoordinatorAddress, e.Ec) helpers.PanicErr(err) - fmt.Println("\nDeploying Batch Coordinator...") - batchCoordinatorAddress := deployBatchCoordinatorV2(e, coordinatorAddress) + if contractAddresses.BatchCoordinatorAddress.String() == "0x0000000000000000000000000000000000000000" { + fmt.Println("\nDeploying Batch Coordinator...") + contractAddresses.BatchCoordinatorAddress = DeployBatchCoordinatorV2(e, contractAddresses.CoordinatorAddress) + } fmt.Println("\nSetting Coordinator Config...") - setCoordinatorConfig( + SetCoordinatorConfig( e, *coordinator, - uint16(*minConfs), - uint32(*maxGasLimit), - uint32(*stalenessSeconds), - uint32(*gasAfterPayment), - fallbackWeiPerUnitLink, - vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig{ - FulfillmentFlatFeeLinkPPM: uint32(*flatFeeLinkPPM), - FulfillmentFlatFeeNativePPM: uint32(*flatFeeEthPPM), - }, + uint16(*coordinatorConfig.MinConfs), + uint32(*coordinatorConfig.MaxGasLimit), + uint32(*coordinatorConfig.StalenessSeconds), + uint32(*coordinatorConfig.GasAfterPayment), + coordinatorConfig.FallbackWeiPerUnitLink, + coordinatorConfig.FeeConfig, ) fmt.Println("\nConfig set, getting current config from deployed contract...") - printCoordinatorConfig(coordinator) - - var compressedPkHex string - var keyHash common.Hash - if len(*registerKeyUncompressedPubKey) > 0 && len(*registerKeyOracleAddress) > 0 { - // Generate compressed public key and key hash - pubBytes, err := hex.DecodeString(*registerKeyUncompressedPubKey) - helpers.PanicErr(err) - pk, err := crypto.UnmarshalPubkey(pubBytes) - helpers.PanicErr(err) - var pkBytes []byte - if big.NewInt(0).Mod(pk.Y, big.NewInt(2)).Uint64() != 0 { - pkBytes = append(pk.X.Bytes(), 1) - } else { - pkBytes = append(pk.X.Bytes(), 0) - } - var newPK secp256k1.PublicKey - copy(newPK[:], pkBytes) - - compressedPkHex = hexutil.Encode(pkBytes) - keyHash, err = newPK.Hash() - helpers.PanicErr(err) + PrintCoordinatorConfig(coordinator) + if len(*registerKeyUncompressedPubKey) > 0 { fmt.Println("\nRegistering proving key...") - registerCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey, *registerKeyOracleAddress) + + //NOTE - register proving key against EOA account, and not against Oracle's sending address in other to be able + // easily withdraw funds from Coordinator contract back to EOA account + RegisterCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey, e.Owner.From.String()) fmt.Println("\nProving key registered, getting proving key hashes from deployed contract...") _, _, provingKeyHashes, configErr := coordinator.GetRequestConfig(nil) @@ -607,22 +650,28 @@ func deployUniverse(e helpers.Environment) { } fmt.Println("\nDeploying consumer...") - consumerAddress := eoaDeployConsumer(e, coordinatorAddress.String(), *linkAddress) + consumerAddress := EoaV2PlusLoadTestConsumerWithMetricsDeploy(e, contractAddresses.CoordinatorAddress.String()) fmt.Println("\nAdding subscription...") - eoaCreateSub(e, *coordinator) + EoaCreateSub(e, *coordinator) - subID := findSubscriptionID(e, coordinator) + subID := FindSubscriptionID(e, coordinator) helpers.PanicErr(err) fmt.Println("\nAdding consumer to subscription...") - eoaAddConsumerToSub(e, *coordinator, subID, consumerAddress.String()) + EoaAddConsumerToSub(e, *coordinator, subID, consumerAddress.String()) - if subscriptionBalance.Cmp(big.NewInt(0)) > 0 { - fmt.Println("\nFunding subscription with", subscriptionBalance, "juels...") - eoaFundSubscription(e, *coordinator, *linkAddress, subscriptionBalance, subID) + if subscriptionBalanceJuels.Cmp(big.NewInt(0)) > 0 { + fmt.Println("\nFunding subscription with Link Token.", subscriptionBalanceJuels, "juels...") + EoaFundSubWithLink(e, *coordinator, contractAddresses.LinkAddress, subscriptionBalanceJuels, subID) } else { - fmt.Println("Subscription", subID, "NOT getting funded. You must fund the subscription in order to use it!") + fmt.Println("Subscription", subID, "NOT getting funded with Link Token. You must fund the subscription in order to use it!") + } + if subscriptionBalanceNativeWei.Cmp(big.NewInt(0)) > 0 { + fmt.Println("\nFunding subscription with Native Token.", subscriptionBalanceNativeWei, "wei...") + EoaFundSubWithNative(e, coordinator.Address(), subID, subscriptionBalanceNativeWei) + } else { + fmt.Println("Subscription", subID, "NOT getting funded with Native Token. You must fund the subscription in order to use it!") } fmt.Println("\nSubscribed and (possibly) funded, retrieving subscription from deployed contract...") @@ -630,45 +679,95 @@ func deployUniverse(e helpers.Environment) { helpers.PanicErr(err) fmt.Printf("Subscription %+v\n", s) - if len(*registerKeyOracleAddress) > 0 && *oracleFundingAmount > 0 { - fmt.Println("\nFunding oracle...") - helpers.FundNodes(e, []string{*registerKeyOracleAddress}, big.NewInt(*oracleFundingAmount)) - } - - formattedJobSpec := fmt.Sprintf( - formattedVRFJob, - coordinatorAddress, - batchCoordinatorAddress, - false, - compressedPkHex, - e.ChainID, - *registerKeyOracleAddress, - coordinatorAddress, - coordinatorAddress, - coordinatorAddress, + formattedVrfV2PlusPrimaryJobSpec := fmt.Sprintf( + jobs.VRFV2PlusJobFormatted, + contractAddresses.CoordinatorAddress, //coordinatorAddress + contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress + batchFulfillmentEnabled, //batchFulfillmentEnabled + compressedPkHex, //publicKey + *coordinatorConfig.MinConfs, //minIncomingConfirmations + e.ChainID, //evmChainID + strings.Join(util.MapToAddressArr(nodesMap[model.VRFPrimaryNodeName].SendingKeys), "\",\""), //fromAddresses + contractAddresses.CoordinatorAddress, + nodesMap[model.VRFPrimaryNodeName].SendingKeys[0].Address, + contractAddresses.CoordinatorAddress, + contractAddresses.CoordinatorAddress, + ) + + formattedVrfV2PlusBackupJobSpec := fmt.Sprintf( + jobs.VRFV2PlusJobFormatted, + contractAddresses.CoordinatorAddress, //coordinatorAddress + contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress + batchFulfillmentEnabled, //batchFulfillmentEnabled + compressedPkHex, //publicKey + 100, //minIncomingConfirmations + e.ChainID, //evmChainID + strings.Join(util.MapToAddressArr(nodesMap[model.VRFBackupNodeName].SendingKeys), "\",\""), //fromAddresses + contractAddresses.CoordinatorAddress, + nodesMap[model.VRFPrimaryNodeName].SendingKeys[0], + contractAddresses.CoordinatorAddress, + contractAddresses.CoordinatorAddress, + ) + + formattedBHSJobSpec := fmt.Sprintf( + jobs.BHSJobFormatted, + contractAddresses.CoordinatorAddress, //coordinatorAddress + 30, //waitBlocks + 200, //lookbackBlocks + contractAddresses.BhsContractAddress, //bhs address + e.ChainID, //chain id + strings.Join(util.MapToAddressArr(nodesMap[model.BHSNodeName].SendingKeys), "\",\""), //sending addresses + ) + + formattedBHSBackupJobSpec := fmt.Sprintf( + jobs.BHSJobFormatted, + contractAddresses.CoordinatorAddress, //coordinatorAddress + 100, //waitBlocks + 200, //lookbackBlocks + contractAddresses.BhsContractAddress, //bhs adreess + e.ChainID, //chain id + strings.Join(util.MapToAddressArr(nodesMap[model.BHSBackupNodeName].SendingKeys), "\",\""), //sending addresses + ) + + formattedBHFJobSpec := fmt.Sprintf( + jobs.BHFJobFormatted, + contractAddresses.CoordinatorAddress, //coordinatorAddress + contractAddresses.BhsContractAddress, //bhs adreess + contractAddresses.BatchBHSAddress, //batchBHS + e.ChainID, //chain id + strings.Join(util.MapToAddressArr(nodesMap[model.BHFNodeName].SendingKeys), "\",\""), //sending addresses ) fmt.Println( - "\n----------------------------", "\nDeployment complete.", - "\nLINK Token contract address:", *linkAddress, - "\nLINK/ETH Feed contract address:", *linkEthAddress, - "\nBlockhash Store contract address:", bhsContractAddress, - "\nBatch Blockhash Store contract address:", batchBHSContractAddress, - "\nVRF Coordinator Address:", coordinatorAddress, - "\nBatch VRF Coordinator Address:", batchCoordinatorAddress, + "\nLINK Token contract address:", contractAddresses.LinkAddress, + "\nLINK/ETH Feed contract address:", contractAddresses.LinkEthAddress, + "\nBlockhash Store contract address:", contractAddresses.BhsContractAddress, + "\nBatch Blockhash Store contract address:", contractAddresses.BatchBHSAddress, + "\nVRF Coordinator Address:", contractAddresses.CoordinatorAddress, + "\nBatch VRF Coordinator Address:", contractAddresses.BatchCoordinatorAddress, "\nVRF Consumer Address:", consumerAddress, "\nVRF Subscription Id:", subID, - "\nVRF Subscription Balance:", *subscriptionBalanceString, + "\nVRF Subscription LINK Balance:", *subscriptionBalanceJuels, + "\nVRF Subscription Native Balance:", *subscriptionBalanceNativeWei, "\nPossible VRF Request command: ", - fmt.Sprintf("go run . eoa-request --consumer-address %s --sub-id %d --key-hash %s", consumerAddress, subID, keyHash), + fmt.Sprintf("go run . eoa-load-test-request-with-metrics --consumer-address=%s --sub-id=%d --key-hash=%s --request-confirmations %d --requests 1 --runs 1 --cb-gas-limit 1_000_000", consumerAddress, subID, keyHash, *coordinatorConfig.MinConfs), + "\nRetrieve Request Status: ", + fmt.Sprintf("go run . eoa-load-test-read-metrics --consumer-address=%s", consumerAddress), "\nA node can now be configured to run a VRF job with the below job spec :\n", - formattedJobSpec, - "\n----------------------------", + formattedVrfV2PlusPrimaryJobSpec, ) + + return model.JobSpecs{ + VRFPrimaryNode: formattedVrfV2PlusPrimaryJobSpec, + VRFBackupyNode: formattedVrfV2PlusBackupJobSpec, + BHSNode: formattedBHSJobSpec, + BHSBackupNode: formattedBHSBackupJobSpec, + BHFNode: formattedBHFJobSpec, + } } -func deployWrapperUniverse(e helpers.Environment) { +func DeployWrapperUniverse(e helpers.Environment) { cmd := flag.NewFlagSet("wrapper-universe-deploy", flag.ExitOnError) linkAddress := cmd.String("link-address", "", "address of link token") linkETHFeedAddress := cmd.String("link-eth-feed", "", "address of link-eth-feed") @@ -691,12 +790,12 @@ func deployWrapperUniverse(e helpers.Environment) { panic(fmt.Sprintf("failed to parse top up amount '%s'", *subFunding)) } - wrapper, subID := wrapperDeploy(e, + wrapper, subID := WrapperDeploy(e, common.HexToAddress(*linkAddress), common.HexToAddress(*linkETHFeedAddress), common.HexToAddress(*coordinatorAddress)) - wrapperConfigure(e, + WrapperConfigure(e, wrapper, *wrapperGasOverhead, *coordinatorGasOverhead, @@ -709,14 +808,14 @@ func deployWrapperUniverse(e helpers.Environment) { uint32(*fulfillmentFlatFeeNativePPM), ) - consumer := wrapperConsumerDeploy(e, + consumer := WrapperConsumerDeploy(e, common.HexToAddress(*linkAddress), wrapper) coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - eoaFundSubscription(e, *coordinator, *linkAddress, amount, subID) + EoaFundSubWithLink(e, *coordinator, *linkAddress, amount, subID) link, err := link_token_interface.NewLinkToken(common.HexToAddress(*linkAddress), e.Ec) helpers.PanicErr(err) diff --git a/core/scripts/vrfv2plus/testnet/util.go b/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go similarity index 79% rename from core/scripts/vrfv2plus/testnet/util.go rename to core/scripts/vrfv2plus/testnet/v2plusscripts/util.go index 2aeb71bd598..ebe881a9951 100644 --- a/core/scripts/vrfv2plus/testnet/util.go +++ b/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go @@ -1,9 +1,10 @@ -package main +package v2plusscripts import ( "context" "encoding/hex" "fmt" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" "math/big" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -22,19 +23,19 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) -func deployBHS(e helpers.Environment) (blockhashStoreAddress common.Address) { +func DeployBHS(e helpers.Environment) (blockhashStoreAddress common.Address) { _, tx, _, err := blockhash_store.DeployBlockhashStore(e.Owner, e.Ec) helpers.PanicErr(err) return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) } -func deployBatchBHS(e helpers.Environment, bhsAddress common.Address) (batchBHSAddress common.Address) { +func DeployBatchBHS(e helpers.Environment, bhsAddress common.Address) (batchBHSAddress common.Address) { _, tx, _, err := batch_blockhash_store.DeployBatchBlockhashStore(e.Owner, e.Ec, bhsAddress) helpers.PanicErr(err) return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) } -func deployCoordinator( +func DeployCoordinator( e helpers.Environment, linkAddress string, bhsAddress string, @@ -58,27 +59,31 @@ func deployCoordinator( return coordinatorAddress } -func deployBatchCoordinatorV2(e helpers.Environment, coordinatorAddress common.Address) (batchCoordinatorAddress common.Address) { +func DeployBatchCoordinatorV2(e helpers.Environment, coordinatorAddress common.Address) (batchCoordinatorAddress common.Address) { _, tx, _, err := batch_vrf_coordinator_v2plus.DeployBatchVRFCoordinatorV2Plus(e.Owner, e.Ec, coordinatorAddress) helpers.PanicErr(err) return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) } -func eoaAddConsumerToSub(e helpers.Environment, - coordinator vrf_coordinator_v2_5.VRFCoordinatorV25, subID *big.Int, consumerAddress string) { +func EoaAddConsumerToSub( + e helpers.Environment, + coordinator vrf_coordinator_v2_5.VRFCoordinatorV25, + subID *big.Int, + consumerAddress string, +) { txadd, err := coordinator.AddConsumer(e.Owner, subID, common.HexToAddress(consumerAddress)) helpers.PanicErr(err) helpers.ConfirmTXMined(context.Background(), e.Ec, txadd, e.ChainID) } -func eoaCreateSub(e helpers.Environment, coordinator vrf_coordinator_v2_5.VRFCoordinatorV25) { +func EoaCreateSub(e helpers.Environment, coordinator vrf_coordinator_v2_5.VRFCoordinatorV25) { tx, err := coordinator.CreateSubscription(e.Owner) helpers.PanicErr(err) helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) } // returns subscription ID that belongs to the given owner. Returns result found first -func findSubscriptionID(e helpers.Environment, coordinator *vrf_coordinator_v2_5.VRFCoordinatorV25) *big.Int { +func FindSubscriptionID(e helpers.Environment, coordinator *vrf_coordinator_v2_5.VRFCoordinatorV25) *big.Int { // Use most recent 500 blocks as search window. head, err := e.Ec.BlockNumber(context.Background()) helpers.PanicErr(err) @@ -95,7 +100,7 @@ func findSubscriptionID(e helpers.Environment, coordinator *vrf_coordinator_v2_5 return subscriptionIterator.Event.SubId } -func eoaDeployConsumer(e helpers.Environment, +func EoaDeployConsumer(e helpers.Environment, coordinatorAddress string, linkAddress string) ( consumerAddress common.Address) { @@ -108,13 +113,17 @@ func eoaDeployConsumer(e helpers.Environment, return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) } -func eoaFundSubscription(e helpers.Environment, - coordinator vrf_coordinator_v2_5.VRFCoordinatorV25, linkAddress string, amount, subID *big.Int) { +func EoaFundSubWithLink( + e helpers.Environment, + coordinator vrf_coordinator_v2_5.VRFCoordinatorV25, + linkAddress string, amount, + subID *big.Int, +) { linkToken, err := link_token_interface.NewLinkToken(common.HexToAddress(linkAddress), e.Ec) helpers.PanicErr(err) bal, err := linkToken.BalanceOf(nil, e.Owner.From) helpers.PanicErr(err) - fmt.Println("Initial account balance:", bal, e.Owner.From.String(), "Funding amount:", amount.String()) + fmt.Println("Initial account balance (Juels):", bal, e.Owner.From.String(), "Funding amount:", amount.String()) b, err := utils.ABIEncode(`[{"type":"uint256"}]`, subID) helpers.PanicErr(err) tx, err := linkToken.TransferAndCall(e.Owner, coordinator.Address(), amount, b) @@ -122,7 +131,16 @@ func eoaFundSubscription(e helpers.Environment, helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, fmt.Sprintf("sub ID: %d", subID)) } -func printCoordinatorConfig(coordinator *vrf_coordinator_v2_5.VRFCoordinatorV25) { +func EoaFundSubWithNative(e helpers.Environment, coordinatorAddress common.Address, subID *big.Int, amount *big.Int) { + coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(coordinatorAddress, e.Ec) + helpers.PanicErr(err) + e.Owner.Value = amount + tx, err := coordinator.FundSubscriptionWithNative(e.Owner, subID) + helpers.PanicErr(err) + helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) +} + +func PrintCoordinatorConfig(coordinator *vrf_coordinator_v2_5.VRFCoordinatorV25) { cfg, err := coordinator.SConfig(nil) helpers.PanicErr(err) @@ -133,7 +151,7 @@ func printCoordinatorConfig(coordinator *vrf_coordinator_v2_5.VRFCoordinatorV25) fmt.Printf("Coordinator fee config: %+v\n", feeConfig) } -func setCoordinatorConfig( +func SetCoordinatorConfig( e helpers.Environment, coordinator vrf_coordinator_v2_5.VRFCoordinatorV25, minConfs uint16, @@ -156,7 +174,7 @@ func setCoordinatorConfig( helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) } -func registerCoordinatorProvingKey(e helpers.Environment, +func RegisterCoordinatorProvingKey(e helpers.Environment, coordinator vrf_coordinator_v2_5.VRFCoordinatorV25, uncompressed string, oracleAddress string) { pubBytes, err := hex.DecodeString(uncompressed) helpers.PanicErr(err) @@ -176,7 +194,7 @@ func registerCoordinatorProvingKey(e helpers.Environment, ) } -func wrapperDeploy( +func WrapperDeploy( e helpers.Environment, link, linkEthFeed, coordinator common.Address, ) (common.Address, *big.Int) { @@ -199,7 +217,7 @@ func wrapperDeploy( return address, subID } -func wrapperConfigure( +func WrapperConfigure( e helpers.Environment, wrapperAddress common.Address, wrapperGasOverhead, coordinatorGasOverhead, premiumPercentage uint, @@ -230,7 +248,7 @@ func wrapperConfigure( helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) } -func wrapperConsumerDeploy( +func WrapperConsumerDeploy( e helpers.Environment, link, wrapper common.Address, ) common.Address { @@ -243,3 +261,13 @@ func wrapperConsumerDeploy( fmt.Printf("VRFV2WrapperConsumerExample address: %s\n", address) return address } + +func EoaV2PlusLoadTestConsumerWithMetricsDeploy(e helpers.Environment, consumerCoordinator string) (consumerAddress common.Address) { + _, tx, _, err := vrf_v2plus_load_test_with_metrics.DeployVRFV2PlusLoadTestWithMetrics( + e.Owner, + e.Ec, + common.HexToAddress(consumerCoordinator), + ) + helpers.PanicErr(err) + return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) +} diff --git a/core/services/blockhashstore/delegate_test.go b/core/services/blockhashstore/delegate_test.go index 3060f617876..582492105e0 100644 --- a/core/services/blockhashstore/delegate_test.go +++ b/core/services/blockhashstore/delegate_test.go @@ -55,7 +55,7 @@ func createTestDelegate(t *testing.T) (*blockhashstore.Delegate, *testData) { }) db := pgtest.NewSqlxDB(t) kst := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - sendingKey, _ := cltest.MustAddRandomKeyToKeystore(t, kst) + sendingKey, _ := cltest.MustInsertRandomKey(t, kst) lp := &mocklp.LogPoller{} lp.On("RegisterFilter", mock.Anything).Return(nil) lp.On("LatestBlock", mock.Anything, mock.Anything).Return(int64(0), nil) diff --git a/core/services/fluxmonitorv2/flux_monitor_test.go b/core/services/fluxmonitorv2/flux_monitor_test.go index f2e97b66b35..83ffee8ac57 100644 --- a/core/services/fluxmonitorv2/flux_monitor_test.go +++ b/core/services/fluxmonitorv2/flux_monitor_test.go @@ -278,7 +278,7 @@ func withORM(orm fluxmonitorv2.ORM) func(*setupOptions) { func setupStoreWithKey(t *testing.T) (*sqlx.DB, common.Address) { db := pgtest.NewSqlxDB(t) ethKeyStore := cltest.NewKeyStore(t, db, pgtest.NewQConfig(true)).Eth() - _, nodeAddr := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, nodeAddr := cltest.MustInsertRandomKey(t, ethKeyStore) return db, nodeAddr } @@ -287,7 +287,7 @@ func setupStoreWithKey(t *testing.T) (*sqlx.DB, common.Address) { func setupFullDBWithKey(t *testing.T, name string) (*sqlx.DB, common.Address) { cfg, db := heavyweight.FullTestDBV2(t, name, nil) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, nodeAddr := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, nodeAddr := cltest.MustInsertRandomKey(t, ethKeyStore) return db, nodeAddr } diff --git a/core/services/fluxmonitorv2/key_store_test.go b/core/services/fluxmonitorv2/key_store_test.go index 8445ea55516..ed0485d3b3c 100644 --- a/core/services/fluxmonitorv2/key_store_test.go +++ b/core/services/fluxmonitorv2/key_store_test.go @@ -43,7 +43,7 @@ func TestKeyStore_GetRoundRobinAddress(t *testing.T) { cfg := pgtest.NewQConfig(true) ethKeyStore := cltest.NewKeyStore(t, db, cfg).Eth() - _, k0Address := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, k0Address := cltest.MustInsertRandomKey(t, ethKeyStore) ks := fluxmonitorv2.NewKeyStore(ethKeyStore) diff --git a/core/services/fluxmonitorv2/orm_test.go b/core/services/fluxmonitorv2/orm_test.go index 960618c43bb..3bebc150c82 100644 --- a/core/services/fluxmonitorv2/orm_test.go +++ b/core/services/fluxmonitorv2/orm_test.go @@ -181,7 +181,7 @@ func TestORM_CreateEthTransaction(t *testing.T) { txm = txmmocks.NewMockEvmTxManager(t) orm = fluxmonitorv2.NewORM(db, logger.TestLogger(t), cfg, txm, strategy, txmgr.TransmitCheckerSpec{}) - _, from = cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, from = cltest.MustInsertRandomKey(t, ethKeyStore) to = testutils.NewAddress() payload = []byte{1, 0, 0} gasLimit = uint32(21000) diff --git a/core/services/functions/external_adapter_client.go b/core/services/functions/external_adapter_client.go index fc12406e442..db4fed30e5f 100644 --- a/core/services/functions/external_adapter_client.go +++ b/core/services/functions/external_adapter_client.go @@ -129,6 +129,7 @@ func (ea *externalAdapterClient) RunComputation( nodeProvidedSecrets string, requestData *RequestData, ) (userResult, userError []byte, domains []string, err error) { + requestData.Secrets = nil // secrets are passed in nodeProvidedSecrets payload := requestPayload{ Endpoint: "lambda", diff --git a/core/services/functions/external_adapter_client_test.go b/core/services/functions/external_adapter_client_test.go index a0d6d461099..9fd40ba8280 100644 --- a/core/services/functions/external_adapter_client_test.go +++ b/core/services/functions/external_adapter_client_test.go @@ -166,7 +166,7 @@ func TestRunComputation_CorrectAdapterRequest(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(r.Body) assert.NoError(t, err) - expectedData := `{"source":"abcd","language":7,"codeLocation":42,"secrets":"qrvM","secretsLocation":88,"args":["arg1","arg2"]}` + expectedData := `{"source":"abcd","language":7,"codeLocation":42,"secretsLocation":88,"args":["arg1","arg2"]}` expectedBody := fmt.Sprintf(`{"endpoint":"lambda","requestId":"requestID1234","jobName":"TestJob","subscriptionOwner":"SubOwner","subscriptionId":1,"flags":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"nodeProvidedSecrets":"secRETS","data":%s}`, expectedData) assert.Equal(t, expectedBody, string(body)) diff --git a/core/services/functions/listener.go b/core/services/functions/listener.go index b07a4f302f3..f942629f515 100644 --- a/core/services/functions/listener.go +++ b/core/services/functions/listener.go @@ -698,7 +698,7 @@ func (l *FunctionsListener) getSecrets(ctx context.Context, eaClient ExternalAda return "", nil, errors.Wrap(err, "failed to fetch encrypted secrets") } if len(userError) != 0 { - l.logger.Debugw("no valid threshold encrypted secrets detected, falling back to legacy secrets", "requestID", requestIDStr, "err", string(userError)) + return "", errors.New(string(userError)), nil } secrets = thresholdEncSecrets case LocationDONHosted: diff --git a/core/services/functions/request.go b/core/services/functions/request.go index 1a1d16a51dc..181058b83d0 100644 --- a/core/services/functions/request.go +++ b/core/services/functions/request.go @@ -13,7 +13,7 @@ type RequestData struct { Source string `json:"source" cbor:"source"` Language int `json:"language" cbor:"language"` CodeLocation int `json:"codeLocation" cbor:"codeLocation"` - Secrets []byte `json:"secrets" cbor:"secrets"` + Secrets []byte `json:"secrets,omitempty" cbor:"secrets"` SecretsLocation int `json:"secretsLocation" cbor:"secretsLocation"` Args []string `json:"args,omitempty" cbor:"args"` BytesArgs [][]byte `json:"bytesArgs,omitempty" cbor:"bytesArgs"` diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index a886c52f283..ba7a216feca 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -55,7 +55,7 @@ func TestRunner(t *testing.T) { keyStore := cltest.NewKeyStore(t, db, pgtest.NewQConfig(true)) ethKeyStore := keyStore.Eth() - _, transmitterAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, transmitterAddress := cltest.MustInsertRandomKey(t, ethKeyStore) require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) config := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { diff --git a/core/services/keystore/eth.go b/core/services/keystore/eth.go index 362baed6afc..0f9083f32a2 100644 --- a/core/services/keystore/eth.go +++ b/core/services/keystore/eth.go @@ -12,7 +12,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" - evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -32,10 +31,6 @@ type Eth interface { Enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error Disable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error Add(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error - Reset(address common.Address, chainID *big.Int, nonce int64, qopts ...pg.QOpt) error - - NextSequence(address common.Address, chainID *big.Int, qopts ...pg.QOpt) (evmtypes.Nonce, error) - IncrementNextSequence(address common.Address, chainID *big.Int, currentNonce evmtypes.Nonce, qopts ...pg.QOpt) error EnsureKeys(chainIDs ...*big.Int) error SubscribeToKeyChanges() (ch chan struct{}, unsub func()) @@ -182,51 +177,6 @@ func (ks *eth) Export(id string, password string) ([]byte, error) { return key.ToEncryptedJSON(password, ks.scryptParams) } -// Get the next nonce for the given key and chain. It is safest to always to go the DB for this -func (ks *eth) NextSequence(address common.Address, chainID *big.Int, qopts ...pg.QOpt) (nonce evmtypes.Nonce, err error) { - if !ks.exists(address) { - return evmtypes.Nonce(0), errors.Errorf("key with address %s does not exist", address.String()) - } - nonceVal, err := ks.orm.getNextNonce(address, chainID, qopts...) - if err != nil { - return evmtypes.Nonce(0), errors.Wrap(err, "NextSequence failed") - } - ks.lock.Lock() - defer ks.lock.Unlock() - state, exists := ks.keyStates.KeyIDChainID[address.String()][chainID.String()] - if !exists { - return evmtypes.Nonce(0), errors.Errorf("state not found for address %s, chainID %s", address, chainID.String()) - } - if state.Disabled { - return evmtypes.Nonce(0), errors.Errorf("state is disabled for address %s, chainID %s", address, chainID.String()) - } - // Always clobber the memory nonce with the DB nonce - state.NextNonce = nonceVal - return evmtypes.Nonce(nonceVal), nil -} - -// IncrementNextNonce increments keys.next_nonce by 1 -func (ks *eth) IncrementNextSequence(address common.Address, chainID *big.Int, currentSequence evmtypes.Nonce, qopts ...pg.QOpt) error { - if !ks.exists(address) { - return errors.Errorf("key with address %s does not exist", address.String()) - } - incrementedNonce, err := ks.orm.incrementNextNonce(address, chainID, currentSequence.Int64(), qopts...) - if err != nil { - return errors.Wrap(err, "failed IncrementNextNonce") - } - ks.lock.Lock() - defer ks.lock.Unlock() - state, exists := ks.keyStates.KeyIDChainID[address.String()][chainID.String()] - if !exists { - return errors.Errorf("state not found for address %s, chainID %s", address, chainID.String()) - } - if state.Disabled { - return errors.Errorf("state is disabled for address %s, chainID %s", address, chainID.String()) - } - state.NextNonce = incrementedNonce - return nil -} - func (ks *eth) Add(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { ks.lock.Lock() defer ks.lock.Unlock() @@ -240,8 +190,8 @@ func (ks *eth) Add(address common.Address, chainID *big.Int, qopts ...pg.QOpt) e // caller must hold lock! func (ks *eth) addKey(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { state := new(ethkey.State) - sql := `INSERT INTO evm.key_states (address, next_nonce, disabled, evm_chain_id, created_at, updated_at) - VALUES ($1, 0, false, $2, NOW(), NOW()) + sql := `INSERT INTO evm.key_states (address, disabled, evm_chain_id, created_at, updated_at) + VALUES ($1, false, $2, NOW(), NOW()) RETURNING *;` q := ks.orm.q.WithOpts(qopts...) if err := q.Get(state, sql, address, chainID.String()); err != nil { @@ -292,7 +242,7 @@ func (ks *eth) disable(address common.Address, chainID *big.Int, qopts ...pg.QOp state := new(ethkey.State) q := ks.orm.q.WithOpts(qopts...) sql := `UPDATE evm.key_states SET disabled = false, updated_at = NOW() WHERE address = $1 AND evm_chain_id = $2 - RETURNING id, next_nonce, address, evm_chain_id, disabled, created_at, updated_at;` + RETURNING id, address, evm_chain_id, disabled, created_at, updated_at;` if err := q.Get(state, sql, address, chainID.String()); err != nil { return errors.Wrap(err, "failed to enable state") } @@ -302,30 +252,6 @@ func (ks *eth) disable(address common.Address, chainID *big.Int, qopts ...pg.QOp return nil } -// Reset the key/chain nonce to the given one -func (ks *eth) Reset(address common.Address, chainID *big.Int, nonce int64, qopts ...pg.QOpt) error { - q := ks.orm.q.WithOpts(qopts...) - res, err := q.Exec(`UPDATE evm.key_states SET next_nonce = $1 WHERE address = $2 AND evm_chain_id = $3`, nonce, address, chainID.String()) - if err != nil { - return errors.Wrap(err, "failed to reset state") - } - rowsAffected, err := res.RowsAffected() - if err != nil { - return errors.Wrap(err, "failed to get RowsAffected") - } - if rowsAffected == 0 { - return errors.Errorf("key state not found with address %s and chainID %s", address.Hex(), chainID.String()) - } - ks.lock.Lock() - defer ks.lock.Unlock() - state, exists := ks.keyStates.KeyIDChainID[address.Hex()][chainID.String()] - if !exists { - return errors.Errorf("state not found for address %s, chainID %s", address.Hex(), chainID.String()) - } - state.NextNonce = nonce - return nil -} - func (ks *eth) Delete(id string) (ethkey.KeyV2, error) { ks.lock.Lock() defer ks.lock.Unlock() @@ -554,25 +480,24 @@ func (ks *eth) EnabledAddressesForChain(chainID *big.Int) (addresses []common.Ad return } -func (ks *eth) getV1KeysAsV2() (keys []ethkey.KeyV2, nonces []int64, fundings []bool, _ error) { +func (ks *eth) getV1KeysAsV2() (keys []ethkey.KeyV2, fundings []bool, _ error) { v1Keys, err := ks.orm.GetEncryptedV1EthKeys() if err != nil { - return nil, nil, nil, errors.Wrap(err, "failed to get encrypted v1 eth keys") + return nil, nil, errors.Wrap(err, "failed to get encrypted v1 eth keys") } if len(v1Keys) == 0 { - return nil, nil, nil, nil + return nil, nil, nil } for _, keyV1 := range v1Keys { dKey, err := keystore.DecryptKey(keyV1.JSON, ks.password) if err != nil { - return nil, nil, nil, errors.Wrapf(err, "could not decrypt eth key %s", keyV1.Address.Hex()) + return nil, nil, errors.Wrapf(err, "could not decrypt eth key %s", keyV1.Address.Hex()) } keyV2 := ethkey.FromPrivateKey(dKey.PrivateKey) keys = append(keys, keyV2) - nonces = append(nonces, keyV1.NextNonce) fundings = append(fundings, keyV1.IsFunding) } - return keys, nonces, fundings, nil + return keys, fundings, nil } // XXXTestingOnlySetState is only used in tests to manually update a key's state @@ -587,7 +512,7 @@ func (ks *eth) XXXTestingOnlySetState(state ethkey.State) { panic(fmt.Sprintf("key not found with ID %s", state.KeyID())) } *existingState = state - sql := `UPDATE evm.key_states SET address = :address, next_nonce = :next_nonce, is_disabled = :is_disabled, evm_chain_id = :evm_chain_id, updated_at = NOW() + sql := `UPDATE evm.key_states SET address = :address, is_disabled = :is_disabled, evm_chain_id = :evm_chain_id, updated_at = NOW() WHERE address = :address;` _, err := ks.orm.q.NamedExec(sql, state) if err != nil { diff --git a/core/services/keystore/eth_internal_test.go b/core/services/keystore/eth_internal_test.go index da1585bed44..5fe6e6e7698 100644 --- a/core/services/keystore/eth_internal_test.go +++ b/core/services/keystore/eth_internal_test.go @@ -22,15 +22,14 @@ func Test_EthKeyStore(t *testing.T) { t.Run("returns V1 keys as V2", func(t *testing.T) { ethAddress := testutils.NewAddress() - err = utils.JustError(db.Exec(`INSERT INTO keys (address, json, created_at, updated_at, next_nonce, is_funding, deleted_at) VALUES ($1, '{"address":"6fdac88ddfd811d130095373986889ed90e0d622","crypto":{"cipher":"aes-128-ctr","ciphertext":"557f5324e770c3d203751c1f0f7fb5076386c49f5b05e3f20b3abb59758fd3c3","cipherparams":{"iv":"bd9472543fab7cc63027cbcd039daff0"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":2,"p":1,"r":8,"salt":"647b54770a3fda830b4440ae57c44cf7506297295fe4d72b1ff943e3a8ddb94a"},"mac":"0c654ee29ee06b3816fc0040d84ebd648c557144a77ccc55b9568355f53397b3"},"id":"6fdac88d-dfd8-11d1-3009-5373986889ed","version":3}', NOW(), NOW(), 0, false, NULL)`, ethAddress)) + err = utils.JustError(db.Exec(`INSERT INTO keys (address, json, created_at, updated_at, is_funding, deleted_at) VALUES ($1, '{"address":"6fdac88ddfd811d130095373986889ed90e0d622","crypto":{"cipher":"aes-128-ctr","ciphertext":"557f5324e770c3d203751c1f0f7fb5076386c49f5b05e3f20b3abb59758fd3c3","cipherparams":{"iv":"bd9472543fab7cc63027cbcd039daff0"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":2,"p":1,"r":8,"salt":"647b54770a3fda830b4440ae57c44cf7506297295fe4d72b1ff943e3a8ddb94a"},"mac":"0c654ee29ee06b3816fc0040d84ebd648c557144a77ccc55b9568355f53397b3"},"id":"6fdac88d-dfd8-11d1-3009-5373986889ed","version":3}', NOW(), NOW(), false, NULL)`, ethAddress)) require.NoError(t, err) - keys, nonces, fundings, err := ks.(*eth).getV1KeysAsV2() + keys, fundings, err := ks.(*eth).getV1KeysAsV2() require.NoError(t, err) assert.Len(t, keys, 1) assert.Equal(t, fmt.Sprintf("EthKeyV2{PrivateKey: , Address: %s}", keys[0].Address), keys[0].GoString()) - assert.Equal(t, int64(0), nonces[0]) assert.Equal(t, false, fundings[0]) }) } diff --git a/core/services/keystore/eth_test.go b/core/services/keystore/eth_test.go index 78131bec133..0fec509a325 100644 --- a/core/services/keystore/eth_test.go +++ b/core/services/keystore/eth_test.go @@ -1,7 +1,6 @@ package keystore_test import ( - "database/sql" "fmt" "math/big" "sort" @@ -15,7 +14,6 @@ import ( "github.com/stretchr/testify/require" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" @@ -231,24 +229,24 @@ func Test_EthKeyStore_GetRoundRobinAddress(t *testing.T) { // enabled - simulated // - key 4 // enabled - fixture - k1, _ := cltest.MustInsertRandomKey(t, ethKeyStore, []utils.Big{}) + k1, _ := cltest.MustInsertRandomKeyNoChains(t, ethKeyStore) require.NoError(t, ethKeyStore.Add(k1.Address, testutils.FixtureChainID)) require.NoError(t, ethKeyStore.Add(k1.Address, testutils.SimulatedChainID)) require.NoError(t, ethKeyStore.Enable(k1.Address, testutils.FixtureChainID)) require.NoError(t, ethKeyStore.Enable(k1.Address, testutils.SimulatedChainID)) - k2, _ := cltest.MustInsertRandomKey(t, ethKeyStore, []utils.Big{}) + k2, _ := cltest.MustInsertRandomKeyNoChains(t, ethKeyStore) require.NoError(t, ethKeyStore.Add(k2.Address, testutils.FixtureChainID)) require.NoError(t, ethKeyStore.Add(k2.Address, testutils.SimulatedChainID)) require.NoError(t, ethKeyStore.Enable(k2.Address, testutils.FixtureChainID)) require.NoError(t, ethKeyStore.Enable(k2.Address, testutils.SimulatedChainID)) require.NoError(t, ethKeyStore.Disable(k2.Address, testutils.SimulatedChainID)) - k3, _ := cltest.MustInsertRandomKey(t, ethKeyStore, []utils.Big{}) + k3, _ := cltest.MustInsertRandomKeyNoChains(t, ethKeyStore) require.NoError(t, ethKeyStore.Add(k3.Address, testutils.SimulatedChainID)) require.NoError(t, ethKeyStore.Enable(k3.Address, testutils.SimulatedChainID)) - k4, _ := cltest.MustInsertRandomKey(t, ethKeyStore, []utils.Big{}) + k4, _ := cltest.MustInsertRandomKeyNoChains(t, ethKeyStore) require.NoError(t, ethKeyStore.Add(k4.Address, testutils.FixtureChainID)) require.NoError(t, ethKeyStore.Enable(k4.Address, testutils.FixtureChainID)) @@ -335,7 +333,7 @@ func Test_EthKeyStore_SignTx(t *testing.T) { keyStore := cltest.NewKeyStore(t, db, config.Database()) ethKeyStore := keyStore.Eth() - k, _ := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + k, _ := cltest.MustInsertRandomKey(t, ethKeyStore) chainID := big.NewInt(evmclient.NullClientChainID) tx := types.NewTransaction(0, testutils.NewAddress(), big.NewInt(53), 21000, big.NewInt(1000000000), []byte{1, 2, 3, 4}) @@ -615,140 +613,6 @@ func Test_EthKeyStore_EnsureKeys(t *testing.T) { }) } -func Test_EthKeyStore_Reset(t *testing.T) { - t.Parallel() - - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - ks := keyStore.Eth() - - k1, addr1 := cltest.MustInsertRandomKey(t, ks, testutils.FixtureChainID) - cltest.MustInsertRandomKey(t, ks, testutils.FixtureChainID) - cltest.MustInsertRandomKey(t, ks, testutils.SimulatedChainID) - - newNonce := testutils.NewRandomPositiveInt64() - - t.Run("when no state matches address/chain ID", func(t *testing.T) { - addr := utils.RandomAddress() - cid := testutils.NewRandomEVMChainID() - err := ks.Reset(addr, cid, newNonce) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("key state not found with address %s and chainID %s", addr.Hex(), cid.String())) - }) - t.Run("when no state matches address", func(t *testing.T) { - addr := utils.RandomAddress() - err := ks.Reset(addr, testutils.FixtureChainID, newNonce) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("key state not found with address %s and chainID 0", addr.Hex())) - }) - t.Run("when no state matches chain ID", func(t *testing.T) { - cid := testutils.NewRandomEVMChainID() - err := ks.Reset(addr1, cid, newNonce) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("key state not found with address %s and chainID %s", addr1.Hex(), cid.String())) - }) - t.Run("resets key with given address and chain ID to the given nonce", func(t *testing.T) { - err := ks.Reset(k1.Address, testutils.FixtureChainID, newNonce) - assert.NoError(t, err) - - nonce, err := ks.NextSequence(k1.Address, testutils.FixtureChainID) - require.NoError(t, err) - - assert.Equal(t, nonce.Int64(), newNonce) - - state, err := ks.GetState(k1.Address.Hex(), testutils.FixtureChainID) - require.NoError(t, err) - assert.Equal(t, nonce.Int64(), state.NextNonce) - - keys, err := ks.GetAll() - require.NoError(t, err) - require.Len(t, keys, 3) - states, err := ks.GetStatesForKeys(keys) - require.NoError(t, err) - require.Len(t, states, 3) - for _, state = range states { - if state.Address.Address() == k1.Address { - assert.Equal(t, nonce.Int64(), state.NextNonce) - } else { - // the other states didn't get updated - assert.Equal(t, int64(0), state.NextNonce) - } - } - }) -} - -func Test_NextSequence(t *testing.T) { - t.Parallel() - - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - ks := keyStore.Eth() - randNonce := testutils.NewRandomPositiveInt64() - - _, addr1 := cltest.MustInsertRandomKey(t, ks, testutils.FixtureChainID, randNonce) - cltest.MustInsertRandomKey(t, ks, testutils.FixtureChainID) - - nonce, err := ks.NextSequence(addr1, testutils.FixtureChainID) - require.NoError(t, err) - assert.Equal(t, randNonce, nonce.Int64()) - - _, err = ks.NextSequence(addr1, testutils.SimulatedChainID) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("NextSequence failed: key with address %s is not enabled for chain %s: sql: no rows in result set", addr1.Hex(), testutils.SimulatedChainID.String())) - - randAddr1 := utils.RandomAddress() - _, err = ks.NextSequence(randAddr1, testutils.FixtureChainID) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("key with address %s does not exist", randAddr1.Hex())) - - randAddr2 := utils.RandomAddress() - _, err = ks.NextSequence(randAddr2, testutils.NewRandomEVMChainID()) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("key with address %s does not exist", randAddr2.Hex())) -} - -func Test_IncrementNextSequence(t *testing.T) { - t.Parallel() - - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - ks := keyStore.Eth() - randNonce := testutils.NewRandomPositiveInt64() - - _, addr1 := cltest.MustInsertRandomKey(t, ks, testutils.FixtureChainID, randNonce) - evmAddr1 := addr1 - cltest.MustInsertRandomKey(t, ks, testutils.FixtureChainID) - - err := ks.IncrementNextSequence(evmAddr1, testutils.FixtureChainID, evmtypes.Nonce(randNonce-1)) - assert.ErrorIs(t, err, sql.ErrNoRows) - - err = ks.IncrementNextSequence(evmAddr1, testutils.FixtureChainID, evmtypes.Nonce(randNonce)) - require.NoError(t, err) - var nonce int64 - require.NoError(t, db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 AND evm_chain_id = $2`, addr1, testutils.FixtureChainID.String())) - assert.Equal(t, randNonce+1, nonce) - - err = ks.IncrementNextSequence(evmAddr1, testutils.SimulatedChainID, evmtypes.Nonce(randNonce+1)) - assert.ErrorIs(t, err, sql.ErrNoRows) - - randAddr1 := utils.RandomAddress() - err = ks.IncrementNextSequence(randAddr1, testutils.FixtureChainID, evmtypes.Nonce(randNonce+1)) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("key with address %s does not exist", randAddr1.Hex())) - - randAddr2 := utils.RandomAddress() - err = ks.IncrementNextSequence(randAddr2, testutils.NewRandomEVMChainID(), evmtypes.Nonce(randNonce+1)) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("key with address %s does not exist", randAddr2.Hex())) - - // verify it didnt get changed by any erroring calls - require.NoError(t, db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 AND evm_chain_id = $2`, addr1, testutils.FixtureChainID.String())) - assert.Equal(t, randNonce+1, nonce) -} - func Test_EthKeyStore_Delete(t *testing.T) { t.Parallel() @@ -762,9 +626,9 @@ func Test_EthKeyStore_Delete(t *testing.T) { require.Error(t, err) assert.Contains(t, err.Error(), "Key not found") - _, addr1 := cltest.MustInsertRandomKey(t, ks, testutils.FixtureChainID) - _, addr2 := cltest.MustInsertRandomKey(t, ks, testutils.FixtureChainID) - cltest.MustInsertRandomKey(t, ks, testutils.SimulatedChainID) + _, addr1 := cltest.MustInsertRandomKey(t, ks) + _, addr2 := cltest.MustInsertRandomKey(t, ks) + cltest.MustInsertRandomKey(t, ks, *utils.NewBig(testutils.SimulatedChainID)) require.NoError(t, ks.Add(addr1, testutils.SimulatedChainID)) require.NoError(t, ks.Enable(addr1, testutils.SimulatedChainID)) @@ -814,20 +678,20 @@ func Test_EthKeyStore_CheckEnabled(t *testing.T) { // enabled - simulated // - key 4 // enabled - fixture - k1, addr1 := cltest.MustInsertRandomKey(t, ks, []utils.Big{}) + k1, addr1 := cltest.MustInsertRandomKeyNoChains(t, ks) require.NoError(t, ks.Add(k1.Address, testutils.SimulatedChainID)) require.NoError(t, ks.Add(k1.Address, testutils.FixtureChainID)) require.NoError(t, ks.Enable(k1.Address, testutils.SimulatedChainID)) require.NoError(t, ks.Enable(k1.Address, testutils.FixtureChainID)) - k2, addr2 := cltest.MustInsertRandomKey(t, ks, []utils.Big{}) + k2, addr2 := cltest.MustInsertRandomKeyNoChains(t, ks) require.NoError(t, ks.Add(k2.Address, testutils.FixtureChainID)) require.NoError(t, ks.Add(k2.Address, testutils.SimulatedChainID)) require.NoError(t, ks.Enable(k2.Address, testutils.FixtureChainID)) require.NoError(t, ks.Enable(k2.Address, testutils.SimulatedChainID)) require.NoError(t, ks.Disable(k2.Address, testutils.SimulatedChainID)) - k3, addr3 := cltest.MustInsertRandomKey(t, ks, []utils.Big{}) + k3, addr3 := cltest.MustInsertRandomKeyNoChains(t, ks) require.NoError(t, ks.Add(k3.Address, testutils.SimulatedChainID)) require.NoError(t, ks.Enable(k3.Address, testutils.SimulatedChainID)) diff --git a/core/services/keystore/keys/ethkey/key.go b/core/services/keystore/keys/ethkey/key.go index 2ca671b2cda..4201251e34f 100644 --- a/core/services/keystore/keys/ethkey/key.go +++ b/core/services/keystore/keys/ethkey/key.go @@ -19,13 +19,6 @@ type Key struct { CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` DeletedAt *time.Time `json:"-"` - // This is the nonce that should be used for the next transaction. - // Conceptually equivalent to geth's `PendingNonceAt` but more reliable - // because we have a better view of our own transactions - // NOTE: Be cautious about using this field, it is provided for convenience - // only, can go out of date, and should not be relied upon. The source of - // truth is always the database row for the key. - NextNonce int64 `json:"-"` // IsFunding marks the address as being used for rescuing the node and the pending transactions // Only one key can be IsFunding=true at a time. IsFunding bool diff --git a/core/services/keystore/keys/ethkey/models.go b/core/services/keystore/keys/ethkey/models.go index 1afab408dbe..b90503c3ed6 100644 --- a/core/services/keystore/keys/ethkey/models.go +++ b/core/services/keystore/keys/ethkey/models.go @@ -10,13 +10,10 @@ type State struct { ID int32 Address EIP55Address EVMChainID utils.Big - // NextNonce is used for convenience and rendering in UI but the source of - // truth is always the DB - NextNonce int64 - Disabled bool - CreatedAt time.Time - UpdatedAt time.Time - lastUsed time.Time + Disabled bool + CreatedAt time.Time + UpdatedAt time.Time + lastUsed time.Time } func (s State) KeyID() string { diff --git a/core/services/keystore/master_test.go b/core/services/keystore/master_test.go index d1c09c7b61c..7a280cc6756 100644 --- a/core/services/keystore/master_test.go +++ b/core/services/keystore/master_test.go @@ -45,7 +45,7 @@ func TestMasterKeystore_Unlock_Save(t *testing.T) { t.Run("won't load a saved keyRing if the password is incorrect", func(t *testing.T) { defer reset() require.NoError(t, keyStore.Unlock(cltest.Password)) - cltest.MustAddRandomKeyToKeystore(t, keyStore.Eth()) // need at least 1 key to encrypt + cltest.MustInsertRandomKey(t, keyStore.Eth()) // need at least 1 key to encrypt cltest.AssertCount(t, db, tableName, 1) keyStore.ResetXXXTestOnly() cltest.AssertCount(t, db, tableName, 1) diff --git a/core/services/keystore/mocks/eth.go b/core/services/keystore/mocks/eth.go index bb539d8b7ac..88a5356ac1f 100644 --- a/core/services/keystore/mocks/eth.go +++ b/core/services/keystore/mocks/eth.go @@ -6,15 +6,13 @@ import ( big "math/big" common "github.com/ethereum/go-ethereum/common" - coretypes "github.com/ethereum/go-ethereum/core/types" - ethkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" mock "github.com/stretchr/testify/mock" pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - types "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + types "github.com/ethereum/go-ethereum/core/types" ) // Eth is an autogenerated mock type for the Eth type @@ -465,97 +463,24 @@ func (_m *Eth) Import(keyJSON []byte, password string, chainIDs ...*big.Int) (et return r0, r1 } -// IncrementNextSequence provides a mock function with given fields: address, chainID, currentNonce, qopts -func (_m *Eth) IncrementNextSequence(address common.Address, chainID *big.Int, currentNonce types.Nonce, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, address, chainID, currentNonce) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 error - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, types.Nonce, ...pg.QOpt) error); ok { - r0 = rf(address, chainID, currentNonce, qopts...) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// NextSequence provides a mock function with given fields: address, chainID, qopts -func (_m *Eth) NextSequence(address common.Address, chainID *big.Int, qopts ...pg.QOpt) (types.Nonce, error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, address, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 types.Nonce - var r1 error - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) (types.Nonce, error)); ok { - return rf(address, chainID, qopts...) - } - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) types.Nonce); ok { - r0 = rf(address, chainID, qopts...) - } else { - r0 = ret.Get(0).(types.Nonce) - } - - if rf, ok := ret.Get(1).(func(common.Address, *big.Int, ...pg.QOpt) error); ok { - r1 = rf(address, chainID, qopts...) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Reset provides a mock function with given fields: address, chainID, nonce, qopts -func (_m *Eth) Reset(address common.Address, chainID *big.Int, nonce int64, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, address, chainID, nonce) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 error - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, int64, ...pg.QOpt) error); ok { - r0 = rf(address, chainID, nonce, qopts...) - } else { - r0 = ret.Error(0) - } - - return r0 -} - // SignTx provides a mock function with given fields: fromAddress, tx, chainID -func (_m *Eth) SignTx(fromAddress common.Address, tx *coretypes.Transaction, chainID *big.Int) (*coretypes.Transaction, error) { +func (_m *Eth) SignTx(fromAddress common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { ret := _m.Called(fromAddress, tx, chainID) - var r0 *coretypes.Transaction + var r0 *types.Transaction var r1 error - if rf, ok := ret.Get(0).(func(common.Address, *coretypes.Transaction, *big.Int) (*coretypes.Transaction, error)); ok { + if rf, ok := ret.Get(0).(func(common.Address, *types.Transaction, *big.Int) (*types.Transaction, error)); ok { return rf(fromAddress, tx, chainID) } - if rf, ok := ret.Get(0).(func(common.Address, *coretypes.Transaction, *big.Int) *coretypes.Transaction); ok { + if rf, ok := ret.Get(0).(func(common.Address, *types.Transaction, *big.Int) *types.Transaction); ok { r0 = rf(fromAddress, tx, chainID) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*coretypes.Transaction) + r0 = ret.Get(0).(*types.Transaction) } } - if rf, ok := ret.Get(1).(func(common.Address, *coretypes.Transaction, *big.Int) error); ok { + if rf, ok := ret.Get(1).(func(common.Address, *types.Transaction, *big.Int) error); ok { r1 = rf(fromAddress, tx, chainID) } else { r1 = ret.Error(1) diff --git a/core/services/keystore/orm.go b/core/services/keystore/orm.go index 1396b544205..cb80ae7ef74 100644 --- a/core/services/keystore/orm.go +++ b/core/services/keystore/orm.go @@ -2,7 +2,6 @@ package keystore import ( "database/sql" - "math/big" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" @@ -12,7 +11,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/smartcontractkit/sqlx" ) @@ -67,7 +65,7 @@ func (orm ksORM) getEncryptedKeyRing() (kr encryptedKeyRing, err error) { func (orm ksORM) loadKeyStates() (*keyStates, error) { ks := newKeyStates() var ethkeystates []*ethkey.State - if err := orm.q.Select(ðkeystates, `SELECT id, address, evm_chain_id, next_nonce, disabled, created_at, updated_at FROM evm.key_states`); err != nil { + if err := orm.q.Select(ðkeystates, `SELECT id, address, evm_chain_id, disabled, created_at, updated_at FROM evm.key_states`); err != nil { return ks, errors.Wrap(err, "error loading evm.key_states from DB") } for _, state := range ethkeystates { @@ -76,23 +74,6 @@ func (orm ksORM) loadKeyStates() (*keyStates, error) { return ks, nil } -// getNextNonce returns evm.key_states.next_nonce for the given address -func (orm ksORM) getNextNonce(address common.Address, chainID *big.Int, qopts ...pg.QOpt) (nonce int64, err error) { - q := orm.q.WithOpts(qopts...) - err = q.Get(&nonce, "SELECT next_nonce FROM evm.key_states WHERE address = $1 AND evm_chain_id = $2 AND disabled = false", address, chainID.String()) - if errors.Is(err, sql.ErrNoRows) { - return 0, errors.Wrapf(sql.ErrNoRows, "key with address %s is not enabled for chain %s", address.Hex(), chainID.String()) - } - return nonce, errors.Wrap(err, "failed to load next nonce") -} - -// incrementNextNonce increments evm.key_states.next_nonce by 1 -func (orm ksORM) incrementNextNonce(address common.Address, chainID *big.Int, currentNonce int64, qopts ...pg.QOpt) (incrementedNonce int64, err error) { - q := orm.q.WithOpts(qopts...) - err = q.Get(&incrementedNonce, "UPDATE evm.key_states SET next_nonce = next_nonce + 1, updated_at = NOW() WHERE address = $1 AND next_nonce = $2 AND evm_chain_id = $3 AND disabled = false RETURNING next_nonce", address, currentNonce, chainID.String()) - return incrementedNonce, errors.Wrap(err, "IncrementNextNonce failed to update keys") -} - // ~~~~~~~~~~~~~~~~~~~~ LEGACY FUNCTIONS FOR V1 MIGRATION ~~~~~~~~~~~~~~~~~~~~ func (orm ksORM) GetEncryptedV1CSAKeys() (retrieved []csakey.Key, err error) { diff --git a/core/services/keystore/orm_test.go b/core/services/keystore/orm_test.go index 3264b3b0178..2cfc7b9e26a 100644 --- a/core/services/keystore/orm_test.go +++ b/core/services/keystore/orm_test.go @@ -40,8 +40,8 @@ func Test_ORM(t *testing.T) { utils.JustError(db.Exec(`INSERT INTO csa_keys (public_key, encrypted_private_key, created_at, updated_at) VALUES ($1, '{}', NOW(), NOW())`, csa.PublicKey)), // two per key-type, one deleted and one not deleted - utils.JustError(db.Exec(`INSERT INTO keys (address, json, created_at, updated_at, next_nonce, is_funding, deleted_at) VALUES ($1, '{}', NOW(), NOW(), 0, false, NULL)`, eth1)), - utils.JustError(db.Exec(`INSERT INTO keys (address, json, created_at, updated_at, next_nonce, is_funding, deleted_at) VALUES ($1, '{}', NOW(), NOW(), 0, false, NOW())`, eth2)), + utils.JustError(db.Exec(`INSERT INTO keys (address, json, created_at, updated_at, is_funding, deleted_at) VALUES ($1, '{}', NOW(), NOW(), false, NULL)`, eth1)), + utils.JustError(db.Exec(`INSERT INTO keys (address, json, created_at, updated_at, is_funding, deleted_at) VALUES ($1, '{}', NOW(), NOW(), false, NOW())`, eth2)), utils.JustError(db.Exec(`INSERT INTO encrypted_ocr_key_bundles (id, on_chain_signing_address, off_chain_public_key, encrypted_private_keys, created_at, updated_at, config_public_key, deleted_at) VALUES ($1, $2, $3, '{}', NOW(), NOW(), $4, NULL)`, ocr1, testutils.NewAddress(), utils.NewHash(), utils.NewHash())), utils.JustError(db.Exec(`INSERT INTO encrypted_ocr_key_bundles (id, on_chain_signing_address, off_chain_public_key, encrypted_private_keys, created_at, updated_at, config_public_key, deleted_at) VALUES ($1, $2, $3, '{}', NOW(), NOW(), $4, NOW())`, ocr2, testutils.NewAddress(), utils.NewHash(), utils.NewHash())), utils.JustError(db.Exec(`INSERT INTO encrypted_p2p_keys (peer_id, pub_key, encrypted_priv_key, created_at, updated_at, deleted_at) VALUES ($1, $2, '{}', NOW(), NOW(), NULL)`, p1.Pretty(), utils.NewHash())), diff --git a/core/services/ocr2/plugins/functions/integration_tests/v0/internal/testutils.go b/core/services/ocr2/plugins/functions/integration_tests/v0/internal/testutils.go index a36b3cd3ea7..ee9f7ae121e 100644 --- a/core/services/ocr2/plugins/functions/integration_tests/v0/internal/testutils.go +++ b/core/services/ocr2/plugins/functions/integration_tests/v0/internal/testutils.go @@ -20,8 +20,8 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/hashicorp/consul/sdk/freeport" "github.com/onsi/gomega" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/libocr/commontypes" @@ -228,7 +228,7 @@ type Node struct { func StartNewNode( t *testing.T, owner *bind.TransactOpts, - port uint16, + port int, dbName string, b *backends.SimulatedBackend, maxGas uint32, @@ -415,9 +415,6 @@ func mockEALambdaExecutionResponse(t *testing.T, request map[string]any) []byte require.Equal(t, functions.LanguageJavaScript, int(data["language"].(float64))) require.Equal(t, functions.LocationInline, int(data["codeLocation"].(float64))) require.Equal(t, functions.LocationRemote, int(data["secretsLocation"].(float64))) - if data["secrets"] != DefaultSecretsBase64 && request["nodeProvidedSecrets"] != fmt.Sprintf(`{"0x0":"%s"}`, DefaultSecretsBase64) { - assert.Fail(t, "expected secrets or nodeProvidedSecrets to be '%s'", DefaultSecretsBase64) - } args := data["args"].([]interface{}) require.Equal(t, 2, len(args)) require.Equal(t, DefaultArg1, args[0].(string)) @@ -469,11 +466,12 @@ func CreateFunctionsNodes( require.Fail(t, "ocr2Keystores and thresholdKeyShares must have the same length") } - bootstrapPort := testutils.GetFreePort(t) + bootstrapPort := freeport.GetOne(t) bootstrapNode = StartNewNode(t, owner, bootstrapPort, "bootstrap", b, uint32(maxGas), nil, nil, "") AddBootstrapJob(t, bootstrapNode.App, oracleContractAddress) // oracle nodes with jobs, bridges and mock EAs + ports := freeport.GetN(t, nOracleNodes) for i := 0; i < nOracleNodes; i++ { var thresholdKeyShare string if len(thresholdKeyShares) == 0 { @@ -487,8 +485,7 @@ func CreateFunctionsNodes( } else { ocr2Keystore = ocr2Keystores[i] } - nodePort := testutils.GetFreePort(t) - oracleNode := StartNewNode(t, owner, nodePort, fmt.Sprintf("oracle%d", i), b, uint32(maxGas), []commontypes.BootstrapperLocator{ + oracleNode := StartNewNode(t, owner, ports[i], fmt.Sprintf("oracle%d", i), b, uint32(maxGas), []commontypes.BootstrapperLocator{ {PeerID: bootstrapNode.PeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapPort)}}, }, ocr2Keystore, thresholdKeyShare) oracleNodes = append(oracleNodes, oracleNode.App) diff --git a/core/services/ocr2/plugins/functions/integration_tests/v1/functions_integration_test.go b/core/services/ocr2/plugins/functions/integration_tests/v1/functions_integration_test.go index 944bafadf75..e92cbe8bca4 100644 --- a/core/services/ocr2/plugins/functions/integration_tests/v1/functions_integration_test.go +++ b/core/services/ocr2/plugins/functions/integration_tests/v1/functions_integration_test.go @@ -44,7 +44,7 @@ func TestIntegration_Functions_MultipleV1Requests_Success(t *testing.T) { subscriptionId := utils.CreateAndFundSubscriptions(t, b, owner, linkToken, routerAddress, routerContract, clientContracts, allowListContract) b.Commit() - utils.ClientTestRequests(t, owner, b, linkToken, routerAddress, routerContract, allowListContract, clientContracts, requestLenBytes, utils.DefaultSecretsBytes, subscriptionId, 1*time.Minute) + utils.ClientTestRequests(t, owner, b, linkToken, routerAddress, routerContract, allowListContract, clientContracts, requestLenBytes, nil, subscriptionId, 1*time.Minute) } func TestIntegration_Functions_MultipleV1Requests_ThresholdDecryptionSuccess(t *testing.T) { @@ -91,7 +91,7 @@ func TestIntegration_Functions_MultipleV1Requests_WithUpgrade(t *testing.T) { utils.SetupRouterRoutes(t, b, owner, routerContract, active.Address, proposed.Address, allowListContractAddress) - _, _, oracleIdentities := utils.CreateFunctionsNodes(t, owner, b, routerAddress, nOracleNodes, maxGas, nil, nil) + _, _, oracleIdentities := utils.CreateFunctionsNodes(t, owner, b, routerAddress, nOracleNodes, maxGas, utils.ExportedOcr2Keystores, utils.MockThresholdKeyShares) pluginConfig := functionsConfig.ReportingPluginConfig{ MaxQueryLengthBytes: 10_000, @@ -101,6 +101,16 @@ func TestIntegration_Functions_MultipleV1Requests_WithUpgrade(t *testing.T) { MaxReportTotalCallbackGas: uint32(maxTotalReportGas), DefaultAggregationMethod: functionsConfig.AggregationMethod_AGGREGATION_MODE, UniqueReports: true, + ThresholdPluginConfig: &functionsConfig.ThresholdReportingPluginConfig{ + // approximately 750 bytes per test ciphertext + overhead + MaxQueryLengthBytes: 70_000, + MaxObservationLengthBytes: 70_000, + MaxReportLengthBytes: 70_000, + RequestCountLimit: 50, + RequestTotalBytesLimit: 50_000, + RequireLocalRequestCheck: true, + K: 2, + }, } // set config for both coordinators @@ -108,11 +118,11 @@ func TestIntegration_Functions_MultipleV1Requests_WithUpgrade(t *testing.T) { utils.SetOracleConfig(t, b, owner, proposed.Contract, oracleIdentities, batchSize, &pluginConfig) subscriptionId := utils.CreateAndFundSubscriptions(t, b, owner, linkToken, routerAddress, routerContract, clientContracts, allowListContract) - utils.ClientTestRequests(t, owner, b, linkToken, routerAddress, routerContract, allowListContract, clientContracts, requestLenBytes, utils.DefaultSecretsBytes, subscriptionId, 1*time.Minute) + utils.ClientTestRequests(t, owner, b, linkToken, routerAddress, routerContract, allowListContract, clientContracts, requestLenBytes, utils.DefaultSecretsUrlsBytes, subscriptionId, 1*time.Minute) // upgrade and send requests again _, err := routerContract.UpdateContracts(owner) require.NoError(t, err) b.Commit() - utils.ClientTestRequests(t, owner, b, linkToken, routerAddress, routerContract, allowListContract, clientContracts, requestLenBytes, utils.DefaultSecretsBytes, subscriptionId, 1*time.Minute) + utils.ClientTestRequests(t, owner, b, linkToken, routerAddress, routerContract, allowListContract, clientContracts, requestLenBytes, utils.DefaultSecretsUrlsBytes, subscriptionId, 1*time.Minute) } 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 0970ea7c482..d90d14893c6 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 @@ -21,8 +21,8 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/hashicorp/consul/sdk/freeport" "github.com/onsi/gomega" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/libocr/commontypes" @@ -300,7 +300,7 @@ type Node struct { func StartNewNode( t *testing.T, owner *bind.TransactOpts, - port uint16, + port int, dbName string, b *backends.SimulatedBackend, maxGas uint32, @@ -494,9 +494,9 @@ func mockEALambdaExecutionResponse(t *testing.T, request map[string]any) []byte data := request["data"].(map[string]any) require.Equal(t, functions.LanguageJavaScript, int(data["language"].(float64))) require.Equal(t, functions.LocationInline, int(data["codeLocation"].(float64))) - require.Equal(t, functions.LocationRemote, int(data["secretsLocation"].(float64))) - if data["secrets"] != DefaultSecretsBase64 && request["nodeProvidedSecrets"] != fmt.Sprintf(`{"0x0":"%s"}`, DefaultSecretsBase64) { - assert.Fail(t, "expected secrets or nodeProvidedSecrets to be '%s'", DefaultSecretsBase64) + if len(request["nodeProvidedSecrets"].(string)) > 0 { + require.Equal(t, functions.LocationRemote, int(data["secretsLocation"].(float64))) + require.Equal(t, fmt.Sprintf(`{"0x0":"%s"}`, DefaultSecretsBase64), request["nodeProvidedSecrets"].(string)) } args := data["args"].([]interface{}) require.Equal(t, 2, len(args)) @@ -549,11 +549,12 @@ func CreateFunctionsNodes( require.Fail(t, "ocr2Keystores and thresholdKeyShares must have the same length") } - bootstrapPort := testutils.GetFreePort(t) + bootstrapPort := freeport.GetOne(t) bootstrapNode = StartNewNode(t, owner, bootstrapPort, "bootstrap", b, uint32(maxGas), nil, nil, "") AddBootstrapJob(t, bootstrapNode.App, routerAddress) // oracle nodes with jobs, bridges and mock EAs + ports := freeport.GetN(t, nOracleNodes) for i := 0; i < nOracleNodes; i++ { var thresholdKeyShare string if len(thresholdKeyShares) == 0 { @@ -567,8 +568,7 @@ func CreateFunctionsNodes( } else { ocr2Keystore = ocr2Keystores[i] } - nodePort := testutils.GetFreePort(t) - oracleNode := StartNewNode(t, owner, nodePort, fmt.Sprintf("oracle%d", i), b, uint32(maxGas), []commontypes.BootstrapperLocator{ + oracleNode := StartNewNode(t, owner, ports[i], fmt.Sprintf("oracle%d", i), b, uint32(maxGas), []commontypes.BootstrapperLocator{ {PeerID: bootstrapNode.PeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapPort)}}, }, ocr2Keystore, thresholdKeyShare) oracleNodes = append(oracleNodes, oracleNode.App) diff --git a/core/services/ocr2/plugins/mercury/helpers_test.go b/core/services/ocr2/plugins/mercury/helpers_test.go index 97b86cfc561..ce4e0895164 100644 --- a/core/services/ocr2/plugins/mercury/helpers_test.go +++ b/core/services/ocr2/plugins/mercury/helpers_test.go @@ -13,14 +13,15 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/wsrpc" - "github.com/smartcontractkit/wsrpc/credentials" - "github.com/smartcontractkit/wsrpc/peer" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" "go.uber.org/zap/zaptest/observer" + "github.com/smartcontractkit/wsrpc" + "github.com/smartcontractkit/wsrpc/credentials" + "github.com/smartcontractkit/wsrpc/peer" + "github.com/smartcontractkit/libocr/offchainreporting2/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -150,14 +151,14 @@ func (node *Node) AddBootstrapJob(t *testing.T, spec string) { func setupNode( t *testing.T, - port int64, + port int, dbName string, backend *backends.SimulatedBackend, csaKey csakey.KeyV2, ) (app chainlink.Application, peerID string, clientPubKey credentials.StaticSizedPublicKey, ocr2kb ocr2key.KeyBundle, observedLogs *observer.ObservedLogs) { - k := big.NewInt(port) // keys unique to port + k := big.NewInt(int64(port)) // keys unique to port p2pKey := p2pkey.MustNewV2XXXTestingOnly(k) - rdr := keystest.NewRandReaderFromSeed(port) + rdr := keystest.NewRandReaderFromSeed(int64(port)) ocr2kb = ocr2key.MustNewInsecure(rdr, chaintype.EVM) p2paddresses := []string{fmt.Sprintf("127.0.0.1:%d", port)} @@ -241,7 +242,7 @@ func addV1MercuryJob( i int, verifierAddress common.Address, bootstrapPeerID string, - bootstrapNodePort int64, + bootstrapNodePort int, bmBridge, bidBridge, askBridge, @@ -324,7 +325,7 @@ func addV2MercuryJob( i int, verifierAddress common.Address, bootstrapPeerID string, - bootstrapNodePort int64, + bootstrapNodePort int, bmBridge, serverURL string, serverPubKey, @@ -389,7 +390,7 @@ func addV3MercuryJob( i int, verifierAddress common.Address, bootstrapPeerID string, - bootstrapNodePort int64, + bootstrapNodePort int, bmBridge, bidBridge, askBridge, diff --git a/core/services/ocr2/plugins/mercury/integration_test.go b/core/services/ocr2/plugins/mercury/integration_test.go index fa3aef0451a..e7e059289a2 100644 --- a/core/services/ocr2/plugins/mercury/integration_test.go +++ b/core/services/ocr2/plugins/mercury/integration_test.go @@ -22,16 +22,18 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/hashicorp/consul/sdk/freeport" "github.com/shopspring/decimal" - "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" - "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" - ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/wsrpc/credentials" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" "go.uber.org/zap/zaptest/observer" + "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" + ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/wsrpc/credentials" + relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" relaycodecv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" relaycodecv2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" @@ -172,7 +174,7 @@ func TestIntegration_MercuryV1(t *testing.T) { steve, backend, verifier, verifierAddress := setupBlockchain(t) // Setup bootstrap + oracle nodes - bootstrapNodePort := int64(19700) + bootstrapNodePort := freeport.GetOne(t) appBootstrap, bootstrapPeerID, _, bootstrapKb, observedLogs := setupNode(t, bootstrapNodePort, "bootstrap_mercury", backend, clientCSAKeys[n]) bootstrapNode := Node{App: appBootstrap, KeyBundle: bootstrapKb} logObservers = append(logObservers, observedLogs) @@ -182,8 +184,9 @@ func TestIntegration_MercuryV1(t *testing.T) { oracles []confighelper.OracleIdentityExtra nodes []Node ) - for i := int64(0); i < int64(n); i++ { - app, peerID, transmitter, kb, observedLogs := setupNode(t, bootstrapNodePort+i+1, fmt.Sprintf("oracle_mercury%d", i), backend, clientCSAKeys[i]) + ports := freeport.GetN(t, n) + for i := 0; i < n; i++ { + app, peerID, transmitter, kb, observedLogs := setupNode(t, ports[i], fmt.Sprintf("oracle_mercury%d", i), backend, clientCSAKeys[i]) nodes = append(nodes, Node{ app, transmitter, kb, @@ -520,7 +523,7 @@ func TestIntegration_MercuryV2(t *testing.T) { steve, backend, verifier, verifierAddress := setupBlockchain(t) // Setup bootstrap + oracle nodes - bootstrapNodePort := int64(20700) + bootstrapNodePort := freeport.GetOne(t) appBootstrap, bootstrapPeerID, _, bootstrapKb, observedLogs := setupNode(t, bootstrapNodePort, "bootstrap_mercury", backend, clientCSAKeys[n]) bootstrapNode := Node{App: appBootstrap, KeyBundle: bootstrapKb} logObservers = append(logObservers, observedLogs) @@ -530,8 +533,9 @@ func TestIntegration_MercuryV2(t *testing.T) { oracles []confighelper.OracleIdentityExtra nodes []Node ) - for i := int64(0); i < int64(n); i++ { - app, peerID, transmitter, kb, observedLogs := setupNode(t, bootstrapNodePort+i+1, fmt.Sprintf("oracle_mercury%d", i), backend, clientCSAKeys[i]) + ports := freeport.GetN(t, n) + for i := 0; i < n; i++ { + app, peerID, transmitter, kb, observedLogs := setupNode(t, ports[i], fmt.Sprintf("oracle_mercury%d", i), backend, clientCSAKeys[i]) nodes = append(nodes, Node{ app, transmitter, kb, @@ -795,7 +799,7 @@ func TestIntegration_MercuryV3(t *testing.T) { steve, backend, verifier, verifierAddress := setupBlockchain(t) // Setup bootstrap + oracle nodes - bootstrapNodePort := int64(21700) + bootstrapNodePort := freeport.GetOne(t) appBootstrap, bootstrapPeerID, _, bootstrapKb, observedLogs := setupNode(t, bootstrapNodePort, "bootstrap_mercury", backend, clientCSAKeys[n]) bootstrapNode := Node{App: appBootstrap, KeyBundle: bootstrapKb} logObservers = append(logObservers, observedLogs) @@ -805,8 +809,9 @@ func TestIntegration_MercuryV3(t *testing.T) { oracles []confighelper.OracleIdentityExtra nodes []Node ) - for i := int64(0); i < int64(n); i++ { - app, peerID, transmitter, kb, observedLogs := setupNode(t, bootstrapNodePort+i+1, fmt.Sprintf("oracle_mercury%d", i), backend, clientCSAKeys[i]) + ports := freeport.GetN(t, n) + for i := 0; i < n; i++ { + app, peerID, transmitter, kb, observedLogs := setupNode(t, ports[i], fmt.Sprintf("oracle_mercury%d", i), backend, clientCSAKeys[i]) nodes = append(nodes, Node{ app, transmitter, kb, diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go index e864b0d7e2f..15280de73cf 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go @@ -20,15 +20,17 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/hashicorp/consul/sdk/freeport" "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/umbracle/ethgo/abi" + "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" ocrTypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/umbracle/ethgo/abi" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/assets" @@ -476,7 +478,7 @@ func setupNodes(t *testing.T, nodeKeys [5]ethkey.KeyV2, registry *iregistry21.IK mServer.Start() // Setup bootstrap + oracle nodes - bootstrapNodePort := int64(19599) + bootstrapNodePort := freeport.GetOne(t) appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, "bootstrap_keeper_ocr", nodeKeys[0], backend, nil, mServer) bootstrapNode := Node{ appBootstrap, bootstrapTransmitter, bootstrapKb, @@ -486,8 +488,9 @@ func setupNodes(t *testing.T, nodeKeys [5]ethkey.KeyV2, registry *iregistry21.IK nodes []Node ) // Set up the minimum 4 oracles all funded - for i := int64(0); i < 4; i++ { - app, peerID, transmitter, kb := setupNode(t, bootstrapNodePort+i+1, fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ + ports := freeport.GetN(t, 4) + for i := 0; i < 4; i++ { + app, peerID, transmitter, kb := setupNode(t, ports[i], fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, }, mServer) diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index eea9c1574cf..bf10fa482fd 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -21,8 +21,10 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/hashicorp/consul/sdk/freeport" "github.com/onsi/gomega" "github.com/pkg/errors" + "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrTypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -108,7 +110,7 @@ func deployKeeper20Registry( func setupNode( t *testing.T, - port int64, + port int, dbName string, nodeKey ethkey.KeyV2, backend *backends.SimulatedBackend, @@ -238,7 +240,7 @@ func TestIntegration_KeeperPluginBasic(t *testing.T) { registry := deployKeeper20Registry(t, steve, backend, linkAddr, linkFeedAddr, gasFeedAddr) // Setup bootstrap + oracle nodes - bootstrapNodePort := int64(19599) + bootstrapNodePort := freeport.GetOne(t) appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, "bootstrap_keeper_ocr", nodeKeys[0], backend, nil, NewSimulatedMercuryServer()) bootstrapNode := Node{ appBootstrap, bootstrapTransmitter, bootstrapKb, @@ -248,8 +250,9 @@ func TestIntegration_KeeperPluginBasic(t *testing.T) { nodes []Node ) // Set up the minimum 4 oracles all funded - for i := int64(0); i < 4; i++ { - app, peerID, transmitter, kb := setupNode(t, bootstrapNodePort+i+1, fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ + ports := freeport.GetN(t, 4) + for i := 0; i < 4; i++ { + app, peerID, transmitter, kb := setupNode(t, ports[i], fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, }, NewSimulatedMercuryServer()) @@ -498,7 +501,7 @@ func TestIntegration_KeeperPluginForwarderEnabled(t *testing.T) { effectiveTransmitters := make([]common.Address, 0) // Setup bootstrap + oracle nodes - bootstrapNodePort := int64(19599) + bootstrapNodePort := freeport.GetOne(t) appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, "bootstrap_keeper_ocr", nodeKeys[0], backend, nil, NewSimulatedMercuryServer()) bootstrapNode := Node{ @@ -509,8 +512,9 @@ func TestIntegration_KeeperPluginForwarderEnabled(t *testing.T) { nodes []Node ) // Set up the minimum 4 oracles all funded - for i := int64(0); i < 4; i++ { - app, peerID, transmitter, kb := setupNode(t, bootstrapNodePort+i+1, fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ + ports := freeport.GetN(t, 4) + for i := 0; i < 4; i++ { + app, peerID, transmitter, kb := setupNode(t, ports[i], fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, }, NewSimulatedMercuryServer()) 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 852017dffa9..9ae025d50cf 100644 --- a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go @@ -18,6 +18,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/hashicorp/consul/sdk/freeport" "github.com/onsi/gomega" "github.com/stretchr/testify/require" "go.dedis.ch/kyber/v3" @@ -217,7 +218,7 @@ func setupOCR2VRFContracts( func setupNodeOCR2( t *testing.T, owner *bind.TransactOpts, - port uint16, + port int, dbName string, b *backends.SimulatedBackend, useForwarders bool, @@ -336,7 +337,7 @@ func runOCR2VRFTest(t *testing.T, useForwarders bool) { t.Log("Creating bootstrap node") - bootstrapNodePort := testutils.GetFreePort(t) + bootstrapNodePort := freeport.GetOne(t) bootstrapNode := setupNodeOCR2(t, uni.owner, bootstrapNodePort, "bootstrap", uni.backend, false, nil) numNodes := 5 @@ -354,6 +355,7 @@ func runOCR2VRFTest(t *testing.T, useForwarders bool) { dkgSigners []dkgsignkey.Key sendingKeys [][]string ) + ports := freeport.GetN(t, numNodes) for i := 0; i < numNodes; i++ { // Supply the bootstrap IP and port as a V2 peer address bootstrappers := []commontypes.BootstrapperLocator{ @@ -361,7 +363,7 @@ func runOCR2VRFTest(t *testing.T, useForwarders bool) { fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort), }}, } - node := setupNodeOCR2(t, uni.owner, testutils.GetFreePort(t), fmt.Sprintf("ocr2vrforacle%d", i), uni.backend, useForwarders, bootstrappers) + node := setupNodeOCR2(t, uni.owner, ports[i], fmt.Sprintf("ocr2vrforacle%d", i), uni.backend, useForwarders, bootstrappers) sendingKeys = append(sendingKeys, node.sendingKeys) dkgSignKey, err := node.app.GetKeyStore().DKGSign().Create() diff --git a/core/services/ocrcommon/transmitter_pipeline_test.go b/core/services/ocrcommon/transmitter_pipeline_test.go index 84294a1dde6..8a1f2f2a922 100644 --- a/core/services/ocrcommon/transmitter_pipeline_test.go +++ b/core/services/ocrcommon/transmitter_pipeline_test.go @@ -26,7 +26,7 @@ func Test_PipelineTransmitter_CreateEthTransaction(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) chainID := "12345" gasLimit := uint32(1000) diff --git a/core/services/ocrcommon/transmitter_test.go b/core/services/ocrcommon/transmitter_test.go index 0790f2331c8..ac5d120eb0d 100644 --- a/core/services/ocrcommon/transmitter_test.go +++ b/core/services/ocrcommon/transmitter_test.go @@ -29,7 +29,7 @@ func Test_DefaultTransmitter_CreateEthTransaction(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) gasLimit := uint32(1000) chainID := big.NewInt(0) @@ -70,8 +70,8 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction(t *testing. cfg := configtest.NewTestGeneralConfig(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) - _, fromAddress2 := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + _, fromAddress2 := cltest.MustInsertRandomKey(t, ethKeyStore) gasLimit := uint32(1000) chainID := big.NewInt(0) @@ -153,8 +153,8 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction_No_Keystore cfg := configtest.NewTestGeneralConfig(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) - _, fromAddress2 := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + _, fromAddress2 := cltest.MustInsertRandomKey(t, ethKeyStore) gasLimit := uint32(1000) chainID := big.NewInt(0) diff --git a/core/services/promreporter/prom_reporter_test.go b/core/services/promreporter/prom_reporter_test.go index 9629045cb0b..a893fdb71fa 100644 --- a/core/services/promreporter/prom_reporter_test.go +++ b/core/services/promreporter/prom_reporter_test.go @@ -59,7 +59,7 @@ func Test_PromReporter_OnNewLongestChain(t *testing.T) { cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) var subscribeCalls atomic.Int32 diff --git a/core/store/migrate/migrations/0199_remove_next_nonce_from_keystore.sql b/core/store/migrate/migrations/0199_remove_next_nonce_from_keystore.sql new file mode 100644 index 00000000000..07cdfb02452 --- /dev/null +++ b/core/store/migrate/migrations/0199_remove_next_nonce_from_keystore.sql @@ -0,0 +1,9 @@ +-- +goose Up + +ALTER TABLE evm.key_states DROP COLUMN next_nonce; +ALTER TABLE keys DROP COLUMN next_nonce; + +-- +goose Down + +ALTER TABLE evm.key_states ADD next_nonce bigint NOT NULL DEFAULT 0; +ALTER TABLE keys ADD next_nonce bigint NOT NULL DEFAULT 0; \ No newline at end of file diff --git a/core/store/migrate/migrations/0200_evm_logs_add_block_timestamp_index.sql b/core/store/migrate/migrations/0200_evm_logs_add_block_timestamp_index.sql new file mode 100644 index 00000000000..544a81f2878 --- /dev/null +++ b/core/store/migrate/migrations/0200_evm_logs_add_block_timestamp_index.sql @@ -0,0 +1,15 @@ +-- +goose Up + +-- Start with dropping the index introduced in a previous migration - we are not going to use it +DROP INDEX IF EXISTS evm.log_poller_blocks_by_timestamp; + +CREATE INDEX evm_logs_by_timestamp + ON evm.logs (evm_chain_id, address, event_sig, block_timestamp, block_number); + +-- +goose Down +create index log_poller_blocks_by_timestamp on evm.log_poller_blocks (evm_chain_id, block_timestamp); + +drop index if exists evm.evm_logs_by_timestamp; + + + diff --git a/core/web/eth_keys_controller.go b/core/web/eth_keys_controller.go index f708f8634ec..28afe8c43bf 100644 --- a/core/web/eth_keys_controller.go +++ b/core/web/eth_keys_controller.go @@ -277,14 +277,6 @@ func (ekc *ETHKeysController) Chain(c *gin.Context) { return } - var nonce int64 = -1 - if nonceStr := c.Query("nextNonce"); nonceStr != "" { - nonce, err = strconv.ParseInt(nonceStr, 10, 64) - if err != nil || nonce < 0 { - jsonAPIError(c, http.StatusBadRequest, errors.Wrapf(err, "invalid value for nonce: expected 0 or positive int, got: %s", nonceStr)) - return - } - } abandon := false if abandonStr := c.Query("abandon"); abandonStr != "" { abandon, err = strconv.ParseBool(abandonStr) @@ -295,13 +287,9 @@ func (ekc *ETHKeysController) Chain(c *gin.Context) { } // Reset the chain - if abandon || nonce >= 0 { + if abandon { var resetErr error - err = chain.TxManager().Reset(func() { - if nonce >= 0 { - resetErr = kst.Reset(address, chain.ID(), nonce) - } - }, address, abandon) + err = chain.TxManager().Reset(address, abandon) err = multierr.Combine(err, resetErr) if err != nil { if strings.Contains(err.Error(), "key state not found with address") { diff --git a/core/web/eth_keys_controller_test.go b/core/web/eth_keys_controller_test.go index f0b5b4bfd7c..4d69591999e 100644 --- a/core/web/eth_keys_controller_test.go +++ b/core/web/eth_keys_controller_test.go @@ -4,7 +4,6 @@ import ( "math/big" "net/http" "net/url" - "strconv" "testing" "github.com/pkg/errors" @@ -32,6 +31,7 @@ func TestETHKeysController_Index_Success(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -41,10 +41,10 @@ func TestETHKeysController_Index_Success(t *testing.T) { require.NoError(t, app.KeyStore.Unlock(cltest.Password)) // enabled key - k0, addr0 := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + k0, addr0 := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) // disabled keys - k1, addr1 := cltest.MustInsertRandomDisabledKey(t, app.KeyStore.Eth()) - k2, addr2 := cltest.MustInsertRandomDisabledKey(t, app.KeyStore.Eth()) + k1, addr1 := cltest.RandomKey{Disabled: true}.MustInsert(t, app.KeyStore.Eth()) + k2, addr2 := cltest.RandomKey{Disabled: true}.MustInsert(t, app.KeyStore.Eth()) expectedKeys := []ethkey.KeyV2{k0, k1, k2} ethClient.On("BalanceAt", mock.Anything, addr0, mock.Anything).Return(big.NewInt(256), nil).Once() @@ -84,16 +84,16 @@ func TestETHKeysController_Index_Errors(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) }) - app := cltest.NewApplicationWithConfig(t, cfg, ethClient) require.NoError(t, app.KeyStore.Unlock(cltest.Password)) - _, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + _, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) ethClient.On("BalanceAt", mock.Anything, addr, mock.Anything).Return(nil, errors.New("fake error")).Once() ethClient.On("LINKBalance", mock.Anything, addr, mock.Anything).Return(nil, errors.New("fake error")).Once() @@ -130,7 +130,7 @@ func TestETHKeysController_Index_Disabled(t *testing.T) { require.NoError(t, app.KeyStore.Unlock(cltest.Password)) - _, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + _, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) require.NoError(t, app.Start(testutils.Context(t))) @@ -156,7 +156,7 @@ func TestETHKeysController_Index_NotDev(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) - + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -251,6 +251,7 @@ func TestETHKeysController_ChainSuccess_UpdateNonce(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -259,7 +260,7 @@ func TestETHKeysController_ChainSuccess_UpdateNonce(t *testing.T) { require.NoError(t, app.KeyStore.Unlock(cltest.Password)) // enabled key - key, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + key, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) ethClient.On("BalanceAt", mock.Anything, addr, mock.Anything).Return(big.NewInt(1), nil).Once() ethClient.On("LINKBalance", mock.Anything, addr, mock.Anything).Return(assets.NewLinkFromJuels(1), nil).Once() @@ -270,10 +271,8 @@ func TestETHKeysController_ChainSuccess_UpdateNonce(t *testing.T) { chainURL := url.URL{Path: "/v2/keys/evm/chain"} query := chainURL.Query() - nextNonce := 52 query.Set("address", addr.Hex()) query.Set("evmChainID", cltest.FixtureChainID.String()) - query.Set("nextNonce", strconv.Itoa(nextNonce)) chainURL.RawQuery = query.Encode() resp, cleanup := client.Post(chainURL.String(), nil) @@ -287,13 +286,13 @@ func TestETHKeysController_ChainSuccess_UpdateNonce(t *testing.T) { assert.Equal(t, key.ID(), updatedKey.ID) assert.Equal(t, cltest.FixtureChainID.String(), updatedKey.EVMChainID.String()) assert.Equal(t, false, updatedKey.Disabled) - assert.Equal(t, int64(nextNonce), updatedKey.NextNonce) } func TestETHKeysController_ChainSuccess_Disable(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -303,7 +302,7 @@ func TestETHKeysController_ChainSuccess_Disable(t *testing.T) { require.NoError(t, app.KeyStore.Unlock(cltest.Password)) // enabled key - key, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + key, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) ethClient.On("BalanceAt", mock.Anything, addr, mock.Anything).Return(big.NewInt(1), nil).Once() ethClient.On("LINKBalance", mock.Anything, addr, mock.Anything).Return(assets.NewLinkFromJuels(1), nil).Once() @@ -330,7 +329,6 @@ func TestETHKeysController_ChainSuccess_Disable(t *testing.T) { assert.Equal(t, key.ID(), updatedKey.ID) assert.Equal(t, cltest.FixtureChainID.String(), updatedKey.EVMChainID.String()) - assert.Equal(t, int64(0), updatedKey.NextNonce) assert.Equal(t, true, updatedKey.Disabled) } @@ -347,7 +345,7 @@ func TestETHKeysController_ChainSuccess_Enable(t *testing.T) { require.NoError(t, app.KeyStore.Unlock(cltest.Password)) // disabled key - key, addr := cltest.MustInsertRandomDisabledKey(t, app.KeyStore.Eth()) + key, addr := cltest.RandomKey{Disabled: true}.MustInsert(t, app.KeyStore.Eth()) ethClient.On("BalanceAt", mock.Anything, addr, mock.Anything).Return(big.NewInt(1), nil).Once() ethClient.On("LINKBalance", mock.Anything, addr, mock.Anything).Return(assets.NewLinkFromJuels(1), nil).Once() @@ -374,7 +372,6 @@ func TestETHKeysController_ChainSuccess_Enable(t *testing.T) { assert.Equal(t, key.ID(), updatedKey.ID) assert.Equal(t, cltest.FixtureChainID.String(), updatedKey.EVMChainID.String()) - assert.Equal(t, int64(0), updatedKey.NextNonce) assert.Equal(t, false, updatedKey.Disabled) } @@ -382,6 +379,7 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -391,7 +389,7 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { require.NoError(t, app.KeyStore.Unlock(cltest.Password)) // enabled key - key, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + key, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) ethClient.On("BalanceAt", mock.Anything, addr, mock.Anything).Return(big.NewInt(1), nil).Once() ethClient.On("LINKBalance", mock.Anything, addr, mock.Anything).Return(assets.NewLinkFromJuels(1), nil).Once() @@ -437,7 +435,6 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { assert.Equal(t, key.ID(), updatedKey.ID) assert.Equal(t, cltest.FixtureChainID.String(), updatedKey.EVMChainID.String()) - assert.Equal(t, int64(0), updatedKey.NextNonce) assert.Equal(t, false, updatedKey.Disabled) var s string @@ -450,6 +447,7 @@ func TestETHKeysController_ChainFailure_InvalidAbandon(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -457,7 +455,7 @@ func TestETHKeysController_ChainFailure_InvalidAbandon(t *testing.T) { app := cltest.NewApplicationWithConfig(t, cfg, ethClient) // enabled key - _, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + _, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) require.NoError(t, app.KeyStore.Unlock(cltest.Password)) @@ -467,10 +465,8 @@ func TestETHKeysController_ChainFailure_InvalidAbandon(t *testing.T) { chainURL := url.URL{Path: "/v2/keys/evm/chain"} query := chainURL.Query() - nextNonce := 52 query.Set("address", addr.Hex()) query.Set("evmChainID", cltest.FixtureChainID.String()) - query.Set("nextNonce", strconv.Itoa(nextNonce)) query.Set("abandon", "invalid") chainURL.RawQuery = query.Encode() @@ -484,6 +480,7 @@ func TestETHKeysController_ChainFailure_InvalidEnabled(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -491,7 +488,7 @@ func TestETHKeysController_ChainFailure_InvalidEnabled(t *testing.T) { app := cltest.NewApplicationWithConfig(t, cfg, ethClient) // enabled key - _, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + _, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) require.NoError(t, app.KeyStore.Unlock(cltest.Password)) @@ -501,10 +498,8 @@ func TestETHKeysController_ChainFailure_InvalidEnabled(t *testing.T) { chainURL := url.URL{Path: "/v2/keys/evm/chain"} query := chainURL.Query() - nextNonce := 52 query.Set("address", addr.Hex()) query.Set("evmChainID", cltest.FixtureChainID.String()) - query.Set("nextNonce", strconv.Itoa(nextNonce)) query.Set("enabled", "invalid") chainURL.RawQuery = query.Encode() @@ -532,10 +527,8 @@ func TestETHKeysController_ChainFailure_InvalidAddress(t *testing.T) { chainURL := url.URL{Path: "/v2/keys/evm/chain"} query := chainURL.Query() - nextNonce := 52 query.Set("address", "invalid address") query.Set("evmChainID", cltest.FixtureChainID.String()) - query.Set("nextNonce", strconv.Itoa(nextNonce)) chainURL.RawQuery = query.Encode() resp, cleanup := client.Post(chainURL.String(), nil) @@ -562,16 +555,14 @@ func TestETHKeysController_ChainFailure_MissingAddress(t *testing.T) { chainURL := url.URL{Path: "/v2/keys/evm/chain"} query := chainURL.Query() - nextNonce := 52 query.Set("address", testutils.NewAddress().Hex()) query.Set("evmChainID", cltest.FixtureChainID.String()) - query.Set("nextNonce", strconv.Itoa(nextNonce)) chainURL.RawQuery = query.Encode() resp, cleanup := client.Post(chainURL.String(), nil) defer cleanup() - assert.Equal(t, http.StatusNotFound, resp.StatusCode) + assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) } func TestETHKeysController_ChainFailure_InvalidChainID(t *testing.T) { @@ -592,10 +583,8 @@ func TestETHKeysController_ChainFailure_InvalidChainID(t *testing.T) { chainURL := url.URL{Path: "/v2/keys/evm/chain"} query := chainURL.Query() - nextNonce := 52 query.Set("address", testutils.NewAddress().Hex()) query.Set("evmChainID", "bad chain ID") - query.Set("nextNonce", strconv.Itoa(nextNonce)) chainURL.RawQuery = query.Encode() resp, cleanup := client.Post(chainURL.String(), nil) @@ -608,6 +597,7 @@ func TestETHKeysController_ChainFailure_MissingChainID(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -617,7 +607,7 @@ func TestETHKeysController_ChainFailure_MissingChainID(t *testing.T) { require.NoError(t, app.KeyStore.Unlock(cltest.Password)) // enabled key - _, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + _, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) require.NoError(t, app.Start(testutils.Context(t))) @@ -625,10 +615,8 @@ func TestETHKeysController_ChainFailure_MissingChainID(t *testing.T) { chainURL := url.URL{Path: "/v2/keys/evm/chain"} query := chainURL.Query() - nextNonce := 52 query.Set("address", addr.Hex()) query.Set("evmChainID", "123456789") - query.Set("nextNonce", strconv.Itoa(nextNonce)) chainURL.RawQuery = query.Encode() resp, cleanup := client.Post(chainURL.String(), nil) @@ -637,41 +625,10 @@ func TestETHKeysController_ChainFailure_MissingChainID(t *testing.T) { assert.Equal(t, http.StatusNotFound, resp.StatusCode) } -func TestETHKeysController_ChainFailure_InvalidNonce(t *testing.T) { - t.Parallel() - - ethClient := cltest.NewEthMocksWithStartupAssertions(t) - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].NonceAutoSync = ptr(false) - c.EVM[0].BalanceMonitor.Enabled = ptr(false) - }) - app := cltest.NewApplicationWithConfig(t, cfg, ethClient) - - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) - - // enabled key - _, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) - - require.NoError(t, app.Start(testutils.Context(t))) - - client := app.NewHTTPClient(&cltest.User{}) - chainURL := url.URL{Path: "/v2/keys/evm/chain"} - query := chainURL.Query() - - query.Set("address", addr.Hex()) - query.Set("evmChainID", cltest.FixtureChainID.String()) - query.Set("nextNonce", "bad nonce") - - chainURL.RawQuery = query.Encode() - resp, cleanup := client.Post(chainURL.String(), nil) - defer cleanup() - - assert.Equal(t, http.StatusBadRequest, resp.StatusCode) -} - func TestETHKeysController_DeleteSuccess(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -680,8 +637,8 @@ func TestETHKeysController_DeleteSuccess(t *testing.T) { require.NoError(t, app.KeyStore.Unlock(cltest.Password)) // enabled keys - key0, addr0 := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) - _, addr1 := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + key0, addr0 := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) + _, addr1 := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) ethClient.On("BalanceAt", mock.Anything, addr0, mock.Anything).Return(big.NewInt(1), nil).Once() ethClient.On("BalanceAt", mock.Anything, addr1, mock.Anything).Return(big.NewInt(1), nil).Once() @@ -704,7 +661,6 @@ func TestETHKeysController_DeleteSuccess(t *testing.T) { assert.Equal(t, key0.ID(), deletedKey.ID) assert.Equal(t, cltest.FixtureChainID.String(), deletedKey.EVMChainID.String()) assert.Equal(t, false, deletedKey.Disabled) - assert.Equal(t, int64(0), deletedKey.NextNonce) resp, cleanup2 := client.Get("/v2/keys/evm") defer cleanup2() diff --git a/core/web/evm_transactions_controller_test.go b/core/web/evm_transactions_controller_test.go index 951d9d99259..2668d66c0e6 100644 --- a/core/web/evm_transactions_controller_test.go +++ b/core/web/evm_transactions_controller_test.go @@ -28,7 +28,7 @@ func TestTransactionsController_Index_Success(t *testing.T) { txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) ethKeyStore := cltest.NewKeyStore(t, db, app.Config.Database()).Eth() client := app.NewHTTPClient(&cltest.User{}) - _, from := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, from := cltest.MustInsertRandomKey(t, ethKeyStore) cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) // tx1 tx2 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 3, 2, from) // tx2 @@ -83,7 +83,7 @@ func TestTransactionsController_Show_Success(t *testing.T) { txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) client := app.NewHTTPClient(&cltest.User{}) - _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth(), 0) + _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) tx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, from) require.Len(t, tx.TxAttempts, 1) @@ -116,7 +116,7 @@ func TestTransactionsController_Show_NotFound(t *testing.T) { txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) client := app.NewHTTPClient(&cltest.User{}) - _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth(), 0) + _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) tx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, from) require.Len(t, tx.TxAttempts, 1) attempt := tx.TxAttempts[0] diff --git a/core/web/evm_tx_attempts_controller_test.go b/core/web/evm_tx_attempts_controller_test.go index abf80add213..f9aafc5bda1 100644 --- a/core/web/evm_tx_attempts_controller_test.go +++ b/core/web/evm_tx_attempts_controller_test.go @@ -23,7 +23,7 @@ func TestTxAttemptsController_Index_Success(t *testing.T) { txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) client := app.NewHTTPClient(&cltest.User{}) - _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth(), 0) + _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 1, 2, from) diff --git a/core/web/pipeline_runs_controller_test.go b/core/web/pipeline_runs_controller_test.go index 8e53384856d..3efd692c9db 100644 --- a/core/web/pipeline_runs_controller_test.go +++ b/core/web/pipeline_runs_controller_test.go @@ -14,6 +14,7 @@ import ( "github.com/google/uuid" "github.com/pelletier/go-toml" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -253,6 +254,7 @@ func TestPipelineRunsController_ShowRun_InvalidID(t *testing.T) { func setupPipelineRunsControllerTests(t *testing.T) (cltest.HTTPClientCleaner, int32, []int64) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.OCR.Enabled = ptr(true) c.P2P.V1.Enabled = ptr(true) diff --git a/core/web/presenters/eth_key.go b/core/web/presenters/eth_key.go index d3a8c55c2be..167679513ef 100644 --- a/core/web/presenters/eth_key.go +++ b/core/web/presenters/eth_key.go @@ -14,7 +14,6 @@ type ETHKeyResource struct { JAID EVMChainID utils.Big `json:"evmChainID"` Address string `json:"address"` - NextNonce int64 `json:"nextNonce"` EthBalance *assets.Eth `json:"ethBalance"` LinkBalance *assets.Link `json:"linkBalance"` Disabled bool `json:"disabled"` @@ -42,7 +41,6 @@ func NewETHKeyResource(k ethkey.KeyV2, state ethkey.State, opts ...NewETHKeyOpti r := ÐKeyResource{ JAID: NewJAID(k.Address.Hex()), EVMChainID: state.EVMChainID, - NextNonce: state.NextNonce, Address: k.Address.Hex(), EthBalance: nil, LinkBalance: nil, diff --git a/core/web/presenters/eth_key_test.go b/core/web/presenters/eth_key_test.go index 1518762cc0e..7afb55068fb 100644 --- a/core/web/presenters/eth_key_test.go +++ b/core/web/presenters/eth_key_test.go @@ -31,7 +31,6 @@ func TestETHKeyResource(t *testing.T) { state := ethkey.State{ ID: 1, EVMChainID: *utils.NewBigI(42), - NextNonce: 99, Address: eip55address, CreatedAt: now, UpdatedAt: now, @@ -59,7 +58,6 @@ func TestETHKeyResource(t *testing.T) { "attributes":{ "address":"%s", "evmChainID":"42", - "nextNonce": 99, "ethBalance":"1", "linkBalance":"1", "disabled":true, @@ -89,7 +87,6 @@ func TestETHKeyResource(t *testing.T) { "attributes":{ "address":"%s", "evmChainID":"42", - "nextNonce": 99, "ethBalance":null, "linkBalance":null, "disabled":true, diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 04b0b46a3e3..3d920ecde5e 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -26,6 +26,10 @@ These will eventually replace `TelemetryIngress.URL` and `TelemetryIngress.Serve - Starting in 2.8.0, chainlink nodes will no longer allow `TelemetryIngress.URL` and `TelemetryIngress.ServerPubKey`. Any TOML configuration that sets this fields will prevent the node from booting. These fields will be replaced by `[[TelemetryIngress.Endpoints]]` +### Removed + +- Removed the ability to set a next nonce value for an address through CLI + ## 2.6.0 - UNRELEASED ### Added diff --git a/docs/core/BULLETPROOF_TX_MANAGER_ARCHITECTURE.md b/docs/core/TX_MANAGER_ARCHITECTURE.md similarity index 86% rename from docs/core/BULLETPROOF_TX_MANAGER_ARCHITECTURE.md rename to docs/core/TX_MANAGER_ARCHITECTURE.md index 37480a88c4c..6e0ff946ffc 100644 --- a/docs/core/BULLETPROOF_TX_MANAGER_ARCHITECTURE.md +++ b/docs/core/TX_MANAGER_ARCHITECTURE.md @@ -4,28 +4,28 @@ ## Finite state machine -### `eth_txes.state` +### `evm.txes.state` `unstarted` | | v `in_progress` (only one per key) -| \ -| \ -v v -`fatal_error` `unconfirmed` - | ^ - | | - v | - `confirmed` +| \ +| \ +v v +`fatal_error` `unconfirmed` +| ^ +| | +v | +`confirmed` ### `eth_tx_attempts.state` `in_progress` -| ^ -| | -v | +| ^ +| | +v | `broadcast` # Data structures @@ -42,7 +42,7 @@ EB - EthBroadcaster EC - EthConfirmer -`eth_txes` has five possible states: +`evm.txes` has five possible states: - EB ⚫️ `unstarted` - EB 🟠 `in_progress` @@ -57,12 +57,6 @@ EC - EthConfirmer An attempt may have 0 or more `eth_receipts` indicating that the transaction has been mined into a block. This block may or may not exist as part of the canonical longest chain. -`keys` has a field: - -- `next_nonce` - -Which tracks the nonce that is available to use for the next transaction. It is only updated after a successful broadcast has occurred. - # Components BulletproofTxManager is split into three components, each of which has a clearly delineated set of responsibilities. @@ -71,7 +65,7 @@ BulletproofTxManager is split into three components, each of which has a clearly Conceptually, **EthTx** defines the transaction. -**EthTx** is responsible for generating the transaction criteria and inserting the initial `unstarted` row into the `eth_txes` table. +**EthTx** is responsible for generating the transaction criteria and inserting the initial `unstarted` row into the `evm.txes` table. **EthTx** guarantees that the transaction is defined with the following criteria: @@ -87,9 +81,9 @@ EthTx should wait until it's transaction confirms before marking the task as com ## EthBroadcaster -Conceptually, **EthBroadcaster** assigns a nonce to a transaction and ensures that it is valid. It alone controls the `keys.next_nonce` field. +Conceptually, **EthBroadcaster** assigns a nonce to a transaction and ensures that it is valid. It alone maintains the next usable sequence for a transaction. -**EthBroadcaster** monitors `eth_txes` for transactions that need to be broadcast, assigns nonces and ensures that at least one eth node somewhere has placed the transaction into its mempool. +**EthBroadcaster** monitors `evm.txes` for transactions that need to be broadcast, assigns nonces and ensures that at least one eth node somewhere has placed the transaction into its mempool. It does not guarantee eventual confirmation! @@ -97,8 +91,8 @@ A whole host of other things can subsequently go wrong such as transactions bein **EthBroadcaster** makes the following guarantees: -- A gapless, monotonically increasing sequence of nonces for `eth_txes` (scoped to key). -- Transition of `eth_txes` from `unstarted` to either `fatal_error` or `unconfirmed`. +- A gapless, monotonically increasing sequence of nonces for `evm.txes` (scoped to key). +- Transition of `evm.txes` from `unstarted` to either `fatal_error` or `unconfirmed`. - If final state is `fatal_error` then the nonce is unassigned, and it is impossible that this transaction could ever be mined into a block. - If final state is `unconfirmed` then a saved `eth_transaction_attempt` exists. - If final state is `unconfirmed` then an eth node somewhere has accepted this transaction into its mempool at least once. @@ -132,7 +126,7 @@ Find all transactions confirmed within the past `ETH_FINALITY_DEPTH` blocks and **EthConfirmer** makes the following guarantees: - All transactions will eventually be confirmed on the canonical longest chain, unless a reorg occurs that is deeper than `ETH_FINALITY_DEPTH` blocks. -- In the case that an external wallet used the nonce, we will ensure that *a* transaction exists at this nonce up to a depth of `ETH_FINALITY_DEPTH` blocks but it most likely will not be the transaction in our database. +- In the case that an external wallet used the nonce, we will ensure that _a_ transaction exists at this nonce up to a depth of `ETH_FINALITY_DEPTH` blocks but it most likely will not be the transaction in our database. Note that since checking for inclusion in the longest chain can now be done cheaply, without any calls to the eth node, `ETH_FINALITY_DEPTH` can be set to something quite large without penalty (e.g. 50 or 100). diff --git a/go.mod b/go.mod index 5ffcb338675..7d0ee8fff5d 100644 --- a/go.mod +++ b/go.mod @@ -30,9 +30,10 @@ require ( github.com/gorilla/securecookie v1.1.1 github.com/gorilla/sessions v1.2.1 github.com/gorilla/websocket v1.5.0 - github.com/grafana/pyroscope-go v1.0.2 + github.com/grafana/pyroscope-go v1.0.4 github.com/graph-gophers/dataloader v5.0.0+incompatible github.com/graph-gophers/graphql-go v1.3.0 + github.com/hashicorp/consul/sdk v0.14.1 github.com/hashicorp/go-plugin v1.5.2 github.com/hdevalence/ed25519consensus v0.1.0 github.com/jackc/pgconn v1.14.1 @@ -55,20 +56,20 @@ require ( github.com/pelletier/go-toml v1.9.5 github.com/pelletier/go-toml/v2 v2.1.0 github.com/pkg/errors v0.9.1 - github.com/pressly/goose/v3 v3.15.0 - github.com/prometheus/client_golang v1.16.0 - github.com/prometheus/client_model v0.4.0 + github.com/pressly/goose/v3 v3.15.1 + github.com/prometheus/client_golang v1.17.0 + github.com/prometheus/client_model v0.5.0 github.com/prometheus/common v0.44.0 github.com/prometheus/prometheus v0.46.0 github.com/robfig/cron/v3 v3.0.1 github.com/rogpeppe/go-internal v1.11.0 github.com/scylladb/go-reflectx v1.0.1 - github.com/shirou/gopsutil/v3 v3.23.8 + github.com/shirou/gopsutil/v3 v3.23.9 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231003135342-5e581164f8dd - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231010203454-896f5c3c04d1 github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6 github.com/smartcontractkit/ocr2keepers v0.7.27 @@ -89,15 +90,15 @@ require ( go.dedis.ch/fixbuf v1.0.3 go.dedis.ch/kyber/v3 v3.1.0 go.uber.org/multierr v1.11.0 - go.uber.org/zap v1.24.0 - golang.org/x/crypto v0.11.0 + go.uber.org/zap v1.26.0 + golang.org/x/crypto v0.14.0 golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 - golang.org/x/net v0.12.0 - golang.org/x/sync v0.3.0 - golang.org/x/term v0.10.0 - golang.org/x/text v0.11.0 + golang.org/x/net v0.17.0 + golang.org/x/sync v0.4.0 + golang.org/x/term v0.13.0 + golang.org/x/text v0.13.0 golang.org/x/time v0.3.0 - golang.org/x/tools v0.11.0 + golang.org/x/tools v0.14.0 gonum.org/v1/gonum v0.13.0 google.golang.org/protobuf v1.31.0 gopkg.in/guregu/null.v2 v2.1.2 @@ -123,7 +124,6 @@ require ( github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect - github.com/benbjohnson/clock v1.3.4 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/blendle/zapdriver v1.3.1 // indirect @@ -196,7 +196,7 @@ require ( github.com/google/gofuzz v1.2.0 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/gorilla/context v1.1.1 // indirect - github.com/grafana/pyroscope-go/godeltaprof v0.1.3 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.4 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0-rc.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3 // indirect @@ -235,7 +235,7 @@ require ( github.com/jmhodges/levigo v1.0.0 // indirect github.com/jmoiron/sqlx v1.3.5 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/compress v1.17.0 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/koron/go-ssdp v0.0.2 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -309,7 +309,7 @@ require ( github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/prometheus/procfs v0.11.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect @@ -349,14 +349,13 @@ require ( go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 // indirect - go.opentelemetry.io/otel v1.16.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect + go.opentelemetry.io/otel v1.19.0 // indirect + go.opentelemetry.io/otel/metric v1.19.0 // indirect go.opentelemetry.io/otel/sdk v1.16.0 // indirect - go.opentelemetry.io/otel/trace v1.16.0 // indirect - go.uber.org/atomic v1.11.0 // indirect + go.opentelemetry.io/otel/trace v1.19.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/sys v0.11.0 // indirect + golang.org/x/sys v0.13.0 // indirect google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753 // indirect diff --git a/go.sum b/go.sum index 8df4ccfc30c..8deb953dba4 100644 --- a/go.sum +++ b/go.sum @@ -153,8 +153,6 @@ github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.4 h1:wj3BFPrTw8yYgA1OlMqvUk95nc8OMv3cvBSF5erT2W4= -github.com/benbjohnson/clock v1.3.4/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -243,8 +241,8 @@ github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0 github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= -github.com/containerd/continuity v0.4.1 h1:wQnVrjIyQ8vhU2sgOiL5T07jo+ouqc2bnKsv5/EqGhU= -github.com/containerd/continuity v0.4.1/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= +github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -622,10 +620,10 @@ github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grafana/pyroscope-go v1.0.2 h1:dEFgO9VbhYTwuwpCC5coTpuW0JjISEWDZtvRAW9v5Tw= -github.com/grafana/pyroscope-go v1.0.2/go.mod h1:bShDKsVZdzxq+Ol6no0JKigU9y5FTWUcFditMXaH09o= -github.com/grafana/pyroscope-go/godeltaprof v0.1.3 h1:eunWpv1B3Z7ZK9o4499EmQGlY+CsDmSZ4FbxjRx37uk= -github.com/grafana/pyroscope-go/godeltaprof v0.1.3/go.mod h1:1HSPtjU8vLG0jE9JrTdzjgFqdJ/VgN7fvxBNq3luJko= +github.com/grafana/pyroscope-go v1.0.4 h1:oyQX0BOkL+iARXzHuCdIF5TQ7/sRSel1YFViMHC7Bm0= +github.com/grafana/pyroscope-go v1.0.4/go.mod h1:0d7ftwSMBV/Awm7CCiYmHQEG8Y44Ma3YSjt+nWcWztY= +github.com/grafana/pyroscope-go/godeltaprof v0.1.4 h1:mDsJ3ngul7UfrHibGQpV66PbZ3q1T8glz/tK3bQKKEk= +github.com/grafana/pyroscope-go/godeltaprof v0.1.4/go.mod h1:1HSPtjU8vLG0jE9JrTdzjgFqdJ/VgN7fvxBNq3luJko= github.com/graph-gophers/dataloader v5.0.0+incompatible h1:R+yjsbrNq1Mo3aPG+Z/EKYrXrXXUNJHOgbRt+U6jOug= github.com/graph-gophers/dataloader v5.0.0+incompatible/go.mod h1:jk4jk0c5ZISbKaMe8WsVopGB5/15GvGHMdMdPtwlRp4= github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= @@ -652,6 +650,8 @@ github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfm github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= +github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -681,8 +681,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= @@ -884,8 +884,8 @@ github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0 github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= @@ -1325,10 +1325,10 @@ github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= -github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= -github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk= -github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= +github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/opencontainers/runc v1.1.9 h1:XR0VIHTGce5eWPkaPesqTBrhW2yAcaraWfsEalNwQLM= +github.com/opencontainers/runc v1.1.9/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= @@ -1363,20 +1363,20 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/pressly/goose/v3 v3.15.0 h1:6tY5aDqFknY6VZkorFGgZtWygodZQxfmmEF4rqyJW9k= -github.com/pressly/goose/v3 v3.15.0/go.mod h1:LlIo3zGccjb/YUgG+Svdb9Er14vefRdlDI7URCDrwYo= +github.com/pressly/goose/v3 v3.15.1 h1:dKaJ1SdLvS/+HtS8PzFT0KBEtICC1jewLXM+b3emlv8= +github.com/pressly/goose/v3 v3.15.1/go.mod h1:0E3Yg/+EwYzO6Rz2P98MlClFgIcoujbVRs575yi3iIM= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= +github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -1387,8 +1387,8 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk= -github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/prometheus/prometheus v0.46.0 h1:9JSdXnsuT6YsbODEhSQMwxNkGwPExfmzqG73vCMk/Kw= github.com/prometheus/prometheus v0.46.0/go.mod h1:10L5IJE5CEsjee1FnOcVswYXlPIscDWWt3IJ2UDYrz4= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= @@ -1439,8 +1439,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= -github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= +github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E= +github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -1459,8 +1459,8 @@ github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc4 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231003135342-5e581164f8dd h1:5r6SDRgZfi0kxc7D6sFV7h/bX+D7yewDq3FkyE0VMIM= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231003135342-5e581164f8dd/go.mod h1:agmAM21+teJkw0aj9KYj3q3s1sFkx3PXo5ibWJIrDfU= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca h1:x7M0m512gtXw5Z4B1WJPZ52VgshoIv+IvHqQ8hsH4AE= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231010203454-896f5c3c04d1 h1:Tabg69K9lvQsGiXBQ8tsK6aAKPsUc1e4DHiY8an1zMk= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231010203454-896f5c3c04d1/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 h1:ByVauKFXphRlSNG47lNuxZ9aicu+r8AoNp933VRPpCw= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918/go.mod h1:/yp/sqD8Iz5GU5fcercjrw0ivJF7HDcupYg+Gjr7EPg= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= @@ -1662,14 +1662,14 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= +go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= +go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= +go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1697,8 +1697,9 @@ go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= @@ -1739,8 +1740,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1779,8 +1780,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1841,8 +1842,8 @@ golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1867,8 +1868,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1961,16 +1962,18 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1982,8 +1985,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2057,8 +2060,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= -golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2255,20 +2258,20 @@ lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo= lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q= modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y= -modernc.org/ccgo/v3 v3.16.14 h1:af6KNtFgsVmnDYrWk3PQCS9XT6BXe7o3ZFJKkIKvXNQ= -modernc.org/ccgo/v3 v3.16.14/go.mod h1:mPDSujUIaTNWQSG4eqKw+atqLOEbma6Ncsa94WbC9zo= +modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0= +modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI= modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= -modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o= -modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= +modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA= -modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= -modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= -modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/sqlite v1.26.0 h1:SocQdLRSYlA8W99V8YH0NES75thx19d9sB/aFc4R8Lw= +modernc.org/sqlite v1.26.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= diff --git a/integration-tests/Makefile b/integration-tests/Makefile index 287bb939635..d12a1e789af 100644 --- a/integration-tests/Makefile +++ b/integration-tests/Makefile @@ -188,4 +188,4 @@ run_test_with_local_image: build_docker_image SELECTED_NETWORKS="SIMULATED,SIMULATED_1,SIMULATED_2" \ ARGS="$(args)" \ PRODUCT=$(product) \ - ./scripts/run_product_tests \ No newline at end of file + ./scripts/run_product_tests diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index b09782e9e8a..dcdca91cc78 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -72,7 +72,10 @@ func FundChainlinkNodesAddress( if err != nil { return err } - gasEstimates, err := client.EstimateGas(ethereum.CallMsg{}) + toAddr := common.HexToAddress(toAddress[keyIndex]) + gasEstimates, err := client.EstimateGas(ethereum.CallMsg{ + To: &toAddr, + }) if err != nil { return err } @@ -96,7 +99,10 @@ func FundChainlinkNodesAddresses( return err } for _, addr := range toAddress { - gasEstimates, err := client.EstimateGas(ethereum.CallMsg{}) + toAddr := common.HexToAddress(addr) + gasEstimates, err := client.EstimateGas(ethereum.CallMsg{ + To: &toAddr, + }) if err != nil { return err } @@ -379,7 +385,10 @@ func ReturnFunds(chainlinkNodes []*client.ChainlinkK8sClient, blockchainClient b // FundAddresses will fund a list of addresses with an amount of native currency func FundAddresses(blockchain blockchain.EVMClient, amount *big.Float, addresses ...string) error { for _, address := range addresses { - gasEstimates, err := blockchain.EstimateGas(ethereum.CallMsg{}) + toAddr := common.HexToAddress(address) + gasEstimates, err := blockchain.EstimateGas(ethereum.CallMsg{ + To: &toAddr, + }) if err != nil { return err } diff --git a/integration-tests/actions/ocr_helpers_local.go b/integration-tests/actions/ocr_helpers_local.go index 4d8afc52c49..8bb4e834794 100644 --- a/integration-tests/actions/ocr_helpers_local.go +++ b/integration-tests/actions/ocr_helpers_local.go @@ -35,7 +35,10 @@ func FundChainlinkNodesLocal( if err != nil { return err } - gasEstimates, err := client.EstimateGas(ethereum.CallMsg{}) + toAddr := common.HexToAddress(toAddress) + gasEstimates, err := client.EstimateGas(ethereum.CallMsg{ + To: &toAddr, + }) if err != nil { return err } diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go index 3c210786bf8..0ff9b4afa7d 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go @@ -32,4 +32,10 @@ type VRFV2PlusConfig struct { TestDuration time.Duration `envconfig:"TEST_DURATION" default:"3m"` // How long to run the test for RPS int64 `envconfig:"RPS" default:"1"` // How many requests per second to send RateLimitUnitDuration time.Duration `envconfig:"RATE_LIMIT_UNIT_DURATION" default:"1m"` + //Using existing environment and contracts + UseExistingEnv bool `envconfig:"USE_EXISTING_ENV" default:"false"` // Whether to use an existing environment or create a new one + CoordinatorAddress string `envconfig:"COORDINATOR_ADDRESS" default:""` // Coordinator address + ConsumerAddress string `envconfig:"CONSUMER_ADDRESS" default:""` // Consumer address + SubID string `envconfig:"SUB_ID" default:""` // Subscription ID + KeyHash string `envconfig:"KEY_HASH" default:""` } diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go index 0e68f785237..5d4b963f763 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go @@ -3,6 +3,8 @@ package vrfv2plus import ( "context" "fmt" + "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer" "math/big" "time" @@ -509,9 +511,9 @@ func RequestRandomnessAndWaitForFulfillment( subID *big.Int, isNativeBilling bool, vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, - //todo - should it be here? l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { + logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) _, err := consumer.RequestRandomness( vrfv2PlusData.KeyHash, subID, @@ -525,7 +527,7 @@ func RequestRandomnessAndWaitForFulfillment( return nil, errors.Wrap(err, ErrRequestRandomness) } - return WaitForRequestAndFulfillmentEvents(consumer.Address(), coordinator, vrfv2PlusData, subID, l) + return WaitForRequestAndFulfillmentEvents(consumer.Address(), coordinator, vrfv2PlusData, subID, isNativeBilling, l) } func RequestRandomnessAndWaitForFulfillmentUpgraded( @@ -537,6 +539,7 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, l zerolog.Logger, ) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { + logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) _, err := consumer.RequestRandomness( vrfv2PlusData.KeyHash, subID, @@ -560,15 +563,7 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( return nil, errors.Wrap(err, ErrWaitRandomWordsRequestedEvent) } - l.Debug(). - Str("Request ID", randomWordsRequestedEvent.RequestId.String()). - Str("Subscription ID", randomWordsRequestedEvent.SubId.String()). - Str("Sender Address", randomWordsRequestedEvent.Sender.String()). - Interface("Keyhash", randomWordsRequestedEvent.KeyHash). - Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). - Uint32("Number of Words", randomWordsRequestedEvent.NumWords). - Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). - Msg("RandomnessRequested Event") + LogRandomnessRequestedEventUpgraded(l, coordinator, randomWordsRequestedEvent) randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( []*big.Int{subID}, @@ -578,14 +573,8 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( if err != nil { return nil, errors.Wrap(err, ErrWaitRandomWordsFulfilledEvent) } + LogRandomWordsFulfilledEventUpgraded(l, coordinator, randomWordsFulfilledEvent) - l.Debug(). - Str("Total Payment in Juels", randomWordsFulfilledEvent.Payment.String()). - Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). - Str("Subscription ID", randomWordsFulfilledEvent.SubID.String()). - Str("Request ID", randomWordsFulfilledEvent.RequestId.String()). - Bool("Success", randomWordsFulfilledEvent.Success). - Msg("RandomWordsFulfilled Event (TX metadata)") return randomWordsFulfilledEvent, err } @@ -598,6 +587,7 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { + logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) if isNativeBilling { _, err := consumer.RequestRandomnessNative( vrfv2PlusConfig.MinimumConfirmations, @@ -623,7 +613,7 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( if err != nil { return nil, errors.Wrap(err, "error getting wrapper address") } - return WaitForRequestAndFulfillmentEvents(wrapperAddress.String(), coordinator, vrfv2PlusData, subID, l) + return WaitForRequestAndFulfillmentEvents(wrapperAddress.String(), coordinator, vrfv2PlusData, subID, isNativeBilling, l) } func WaitForRequestAndFulfillmentEvents( @@ -631,6 +621,7 @@ func WaitForRequestAndFulfillmentEvents( coordinator contracts.VRFCoordinatorV2_5, vrfv2PlusData *VRFV2PlusData, subID *big.Int, + isNativeBilling bool, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( @@ -643,15 +634,7 @@ func WaitForRequestAndFulfillmentEvents( return nil, errors.Wrap(err, ErrWaitRandomWordsRequestedEvent) } - l.Debug(). - Str("Request ID", randomWordsRequestedEvent.RequestId.String()). - Str("Subscription ID", randomWordsRequestedEvent.SubId.String()). - Str("Sender Address", randomWordsRequestedEvent.Sender.String()). - Interface("Keyhash", randomWordsRequestedEvent.KeyHash). - Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). - Uint32("Number of Words", randomWordsRequestedEvent.NumWords). - Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). - Msg("RandomnessRequested Event") + LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, isNativeBilling) randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( []*big.Int{subID}, @@ -662,12 +645,163 @@ func WaitForRequestAndFulfillmentEvents( return nil, errors.Wrap(err, ErrWaitRandomWordsFulfilledEvent) } + LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent, isNativeBilling) + return randomWordsFulfilledEvent, err +} + +func LogSubDetails(l zerolog.Logger, subscription vrf_coordinator_v2_5.GetSubscription, subID *big.Int, coordinator contracts.VRFCoordinatorV2_5) { + l.Debug(). + Str("Coordinator", coordinator.Address()). + Str("Link Balance", (*assets.Link)(subscription.Balance).Link()). + Str("Native Token Balance", assets.FormatWei(subscription.NativeBalance)). + Str("Subscription ID", subID.String()). + Str("Subscription Owner", subscription.Owner.String()). + Interface("Subscription Consumers", subscription.Consumers). + Msg("Subscription Data") +} + +func LogRandomnessRequestedEventUpgraded( + l zerolog.Logger, + coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, + randomWordsRequestedEvent *vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsRequested, +) { + l.Debug(). + Str("Coordinator", coordinator.Address()). + Str("Request ID", randomWordsRequestedEvent.RequestId.String()). + Str("Subscription ID", randomWordsRequestedEvent.SubId.String()). + Str("Sender Address", randomWordsRequestedEvent.Sender.String()). + Interface("Keyhash", randomWordsRequestedEvent.KeyHash). + Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). + Uint32("Number of Words", randomWordsRequestedEvent.NumWords). + Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). + Msg("RandomnessRequested Event") +} + +func LogRandomWordsFulfilledEventUpgraded( + l zerolog.Logger, + coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, + randomWordsFulfilledEvent *vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, +) { l.Debug(). + Str("Coordinator", coordinator.Address()). Str("Total Payment in Juels", randomWordsFulfilledEvent.Payment.String()). Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). + Str("Subscription ID", randomWordsFulfilledEvent.SubID.String()). + Str("Request ID", randomWordsFulfilledEvent.RequestId.String()). + Bool("Success", randomWordsFulfilledEvent.Success). + Msg("RandomWordsFulfilled Event (TX metadata)") +} + +func LogRandomnessRequestedEvent( + l zerolog.Logger, + coordinator contracts.VRFCoordinatorV2_5, + randomWordsRequestedEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested, + isNativeBilling bool, +) { + l.Debug(). + Str("Coordinator", coordinator.Address()). + Bool("Native Billing", isNativeBilling). + Str("Request ID", randomWordsRequestedEvent.RequestId.String()). + Str("Subscription ID", randomWordsRequestedEvent.SubId.String()). + Str("Sender Address", randomWordsRequestedEvent.Sender.String()). + Interface("Keyhash", randomWordsRequestedEvent.KeyHash). + Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). + Uint32("Number of Words", randomWordsRequestedEvent.NumWords). + Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). + Msg("RandomnessRequested Event") +} + +func LogRandomWordsFulfilledEvent( + l zerolog.Logger, + coordinator contracts.VRFCoordinatorV2_5, + randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, + isNativeBilling bool, +) { + l.Debug(). + Bool("Native Billing", isNativeBilling). + Str("Coordinator", coordinator.Address()). + Str("Total Payment", randomWordsFulfilledEvent.Payment.String()). + Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). Str("Subscription ID", randomWordsFulfilledEvent.SubId.String()). Str("Request ID", randomWordsFulfilledEvent.RequestId.String()). Bool("Success", randomWordsFulfilledEvent.Success). Msg("RandomWordsFulfilled Event (TX metadata)") - return randomWordsFulfilledEvent, err +} + +func LogMigrationCompletedEvent(l zerolog.Logger, migrationCompletedEvent *vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted, vrfv2PlusContracts *VRFV2_5Contracts) { + l.Debug(). + Str("Subscription ID", migrationCompletedEvent.SubId.String()). + Str("Migrated From Coordinator", vrfv2PlusContracts.Coordinator.Address()). + Str("Migrated To Coordinator", migrationCompletedEvent.NewCoordinator.String()). + Msg("MigrationCompleted Event") +} + +func LogSubDetailsAfterMigration(l zerolog.Logger, newCoordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, subID *big.Int, migratedSubscription vrf_v2plus_upgraded_version.GetSubscription) { + l.Debug(). + Str("New Coordinator", newCoordinator.Address()). + Str("Subscription ID", subID.String()). + Str("Juels Balance", migratedSubscription.Balance.String()). + Str("Native Token Balance", migratedSubscription.NativeBalance.String()). + Str("Subscription Owner", migratedSubscription.Owner.String()). + Interface("Subscription Consumers", migratedSubscription.Consumers). + Msg("Subscription Data After Migration to New Coordinator") +} + +func LogFulfillmentDetailsLinkBilling( + l zerolog.Logger, + wrapperConsumerJuelsBalanceBeforeRequest *big.Int, + wrapperConsumerJuelsBalanceAfterRequest *big.Int, + consumerStatus vrfv2plus_wrapper_load_test_consumer.GetRequestStatus, + randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, +) { + l.Debug(). + Str("Consumer Balance Before Request (Link)", (*assets.Link)(wrapperConsumerJuelsBalanceBeforeRequest).Link()). + Str("Consumer Balance After Request (Link)", (*assets.Link)(wrapperConsumerJuelsBalanceAfterRequest).Link()). + Bool("Fulfilment Status", consumerStatus.Fulfilled). + Str("Paid by Consumer Contract (Link)", (*assets.Link)(consumerStatus.Paid).Link()). + Str("Paid by Coordinator Sub (Link)", (*assets.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") +} + +func LogFulfillmentDetailsNativeBilling( + l zerolog.Logger, + wrapperConsumerBalanceBeforeRequestWei *big.Int, + wrapperConsumerBalanceAfterRequestWei *big.Int, + consumerStatus vrfv2plus_wrapper_load_test_consumer.GetRequestStatus, + randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, +) { + l.Debug(). + Str("Consumer Balance Before Request", assets.FormatWei(wrapperConsumerBalanceBeforeRequestWei)). + Str("Consumer Balance After Request", assets.FormatWei(wrapperConsumerBalanceAfterRequestWei)). + Bool("Fulfilment Status", consumerStatus.Fulfilled). + Str("Paid by Consumer Contract", assets.FormatWei(consumerStatus.Paid)). + Str("Paid by Coordinator Sub", assets.FormatWei(randomWordsFulfilledEvent.Payment)). + 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 Request Fulfilment Details For Native Billing") +} + +func logRandRequest( + consumer string, + coordinator string, + subID *big.Int, + isNativeBilling bool, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + l zerolog.Logger) { + l.Debug(). + Str("Consumer", consumer). + Str("Coordinator", coordinator). + Str("subID", subID.String()). + Bool("IsNativePayment", isNativeBilling). + Uint16("MinimumConfirmations", vrfv2PlusConfig.MinimumConfirmations). + Uint16("RandomnessRequestCountPerRequest", vrfv2PlusConfig.RandomnessRequestCountPerRequest). + Msg("Requesting randomness") } diff --git a/integration-tests/benchmark/keeper_test.go b/integration-tests/benchmark/keeper_test.go index 0563cf4e097..7178ab854ea 100644 --- a/integration-tests/benchmark/keeper_test.go +++ b/integration-tests/benchmark/keeper_test.go @@ -156,22 +156,22 @@ func TestAutomationBenchmark(t *testing.T) { chainClient, err := blockchain.NewEVMClient(benchmarkNetwork, testEnvironment, l) require.NoError(t, err, "Error connecting to blockchain") registryVersions := addRegistry(RegistryToTest) - keeperBenchmarkTest := testsetups.NewKeeperBenchmarkTest( + keeperBenchmarkTest := testsetups.NewKeeperBenchmarkTest(t, testsetups.KeeperBenchmarkTestInputs{ BlockchainClient: chainClient, RegistryVersions: registryVersions, KeeperRegistrySettings: &contracts.KeeperRegistrySettings{ PaymentPremiumPPB: uint32(0), BlockCountPerTurn: big.NewInt(100), - CheckGasLimit: uint32(45000000), //45M - StalenessSeconds: big.NewInt(90000), + CheckGasLimit: uint32(45_000_000), //45M + StalenessSeconds: big.NewInt(90_000), GasCeilingMultiplier: uint16(2), MaxPerformGas: uint32(MaxPerformGas), MinUpkeepSpend: big.NewInt(0), FallbackGasPrice: big.NewInt(2e11), FallbackLinkPrice: big.NewInt(2e18), - MaxCheckDataSize: uint32(5000), - MaxPerformDataSize: uint32(5000), + MaxCheckDataSize: uint32(5_000), + MaxPerformDataSize: uint32(5_000), }, Upkeeps: &testsetups.UpkeepConfig{ NumberOfUpkeeps: NumberOfUpkeeps, @@ -202,8 +202,8 @@ func TestAutomationBenchmark(t *testing.T) { l.Error().Err(err).Msg("Error when tearing down remote suite") } }) - keeperBenchmarkTest.Setup(t, testEnvironment) - keeperBenchmarkTest.Run(t) + keeperBenchmarkTest.Setup(testEnvironment) + keeperBenchmarkTest.Run() } func addRegistry(registryToTest string) []eth_contracts.KeeperRegistryVersion { diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index e92b3870faf..c267a82d94f 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -11,12 +11,8 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/rs/zerolog" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" - "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" - ocrConfigHelper "github.com/smartcontractkit/libocr/offchainreporting/confighelper" - eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_load_test_client" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_v1_events_mock" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_consumer_benchmark" @@ -56,6 +52,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier_proxy" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/werc20_mock" + "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" + ocrConfigHelper "github.com/smartcontractkit/libocr/offchainreporting/confighelper" + + eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" ) // ContractDeployer is an interface for abstracting the contract deployment methods across network implementations @@ -154,6 +155,8 @@ func NewContractDeployer(bcClient blockchain.EVMClient, logger zerolog.Logger) ( return &BSCContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil case *blockchain.ScrollClient: return &ScrollContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil + case *blockchain.PolygonZkEvmClient: + return &PolygonZkEvmContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil } return nil, errors.New("unknown blockchain client implementation for contract deployer, register blockchain client in NewContractDeployer") } @@ -209,6 +212,10 @@ type ScrollContractDeployer struct { *EthereumContractDeployer } +type PolygonZkEvmContractDeployer struct { + *EthereumContractDeployer +} + // NewEthereumContractDeployer returns an instantiated instance of the ETH contract deployer func NewEthereumContractDeployer(ethClient blockchain.EVMClient, logger zerolog.Logger) *EthereumContractDeployer { return &EthereumContractDeployer{ diff --git a/integration-tests/contracts/contract_loader.go b/integration-tests/contracts/contract_loader.go index fc0272b107e..4dda2d3f0c4 100644 --- a/integration-tests/contracts/contract_loader.go +++ b/integration-tests/contracts/contract_loader.go @@ -2,6 +2,8 @@ package contracts import ( "errors" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -39,6 +41,10 @@ type ContractLoader interface { LoadMercuryRewardManager(addr common.Address) (MercuryRewardManager, error) LoadWERC20Mock(addr common.Address) (WERC20Mock, error) + + // VRF + LoadVRFCoordinatorV2_5(addr string) (VRFCoordinatorV2_5, error) + LoadVRFv2PlusLoadTestConsumer(addr string) (VRFv2PlusLoadTestConsumer, error) } // NewContractLoader returns an instance of a contract Loader based on the client type @@ -56,6 +62,8 @@ func NewContractLoader(bcClient blockchain.EVMClient, logger zerolog.Logger) (Co return &PolygonContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil case *blockchain.OptimismClient: return &OptimismContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil + case *blockchain.PolygonZkEvmClient: + return &PolygonZkEvmContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil } return nil, errors.New("unknown blockchain client implementation for contract Loader, register blockchain client in NewContractLoader") } @@ -90,6 +98,14 @@ type PolygonContractLoader struct { type OptimismContractLoader struct { *EthereumContractLoader } +type PolygonZkEvmContractLoader struct { + *EthereumContractLoader +} + +// PolygonZKEVMContractLoader wraps for Polygon zkEVM +type PolygonZKEVMContractLoader struct { + *EthereumContractLoader +} // NewEthereumContractLoader returns an instantiated instance of the ETH contract Loader func NewEthereumContractLoader(ethClient blockchain.EVMClient, logger zerolog.Logger) *EthereumContractLoader { @@ -296,3 +312,39 @@ func (e *EthereumContractLoader) LoadWERC20Mock(addr common.Address) (WERC20Mock address: addr, }, err } + +func (e *EthereumContractLoader) LoadVRFCoordinatorV2_5(addr string) (VRFCoordinatorV2_5, error) { + address := common.HexToAddress(addr) + instance, err := e.client.LoadContract("VRFCoordinatorV2_5", address, func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return vrf_coordinator_v2_5.NewVRFCoordinatorV25(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumVRFCoordinatorV2_5{ + address: &address, + client: e.client, + coordinator: instance.(*vrf_coordinator_v2_5.VRFCoordinatorV25), + }, err +} + +func (e *EthereumContractLoader) LoadVRFv2PlusLoadTestConsumer(addr string) (VRFv2PlusLoadTestConsumer, error) { + address := common.HexToAddress(addr) + instance, err := e.client.LoadContract("VRFV2PlusLoadTestWithMetrics", address, func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return vrf_v2plus_load_test_with_metrics.NewVRFV2PlusLoadTestWithMetrics(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumVRFv2PlusLoadTestConsumer{ + client: e.client, + consumer: instance.(*vrf_v2plus_load_test_with_metrics.VRFV2PlusLoadTestWithMetrics), + address: &address, + }, err +} diff --git a/integration-tests/contracts/contract_vrf_models.go b/integration-tests/contracts/contract_vrf_models.go index 2b623469aa4..ed46b08dbbf 100644 --- a/integration-tests/contracts/contract_vrf_models.go +++ b/integration-tests/contracts/contract_vrf_models.go @@ -2,20 +2,18 @@ package contracts import ( "context" - "math/big" "time" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_load_test_with_metrics" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_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/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" ) @@ -172,6 +170,7 @@ type VRFv2PlusLoadTestConsumer interface { GetLastRequestId(ctx context.Context) (*big.Int, error) GetLoadTestMetrics(ctx context.Context) (*VRFLoadTestMetrics, error) GetCoordinator(ctx context.Context) (common.Address, error) + ResetMetrics() error } type VRFv2PlusWrapperLoadTestConsumer interface { diff --git a/integration-tests/contracts/ethereum_contracts.go b/integration-tests/contracts/ethereum_contracts.go index fdeccfedad1..5b3a93fe0c2 100644 --- a/integration-tests/contracts/ethereum_contracts.go +++ b/integration-tests/contracts/ethereum_contracts.go @@ -5,27 +5,19 @@ import ( "encoding/hex" "fmt" "math/big" + "strings" "time" "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/pkg/errors" "github.com/rs/zerolog" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" - "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" - ocrConfigHelper "github.com/smartcontractkit/libocr/offchainreporting/confighelper" - ocrTypes "github.com/smartcontractkit/libocr/offchainreporting/types" - "strings" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/pkg/errors" - - "github.com/smartcontractkit/chainlink/integration-tests/client" - eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_coordinator" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_load_test_client" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_router" @@ -52,6 +44,13 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier_proxy" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/werc20_mock" + "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" + ocrConfigHelper "github.com/smartcontractkit/libocr/offchainreporting/confighelper" + ocrTypes "github.com/smartcontractkit/libocr/offchainreporting/types" + + "github.com/smartcontractkit/chainlink/integration-tests/client" + eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" ) // EthereumOracle oracle for "directrequest" job tests @@ -66,7 +65,9 @@ func (e *EthereumOracle) Address() string { } func (e *EthereumOracle) Fund(ethAmount *big.Float) error { - gasEstimates, err := e.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := e.client.EstimateGas(ethereum.CallMsg{ + To: e.address, + }) if err != nil { return err } @@ -106,7 +107,9 @@ func (e *EthereumAPIConsumer) RoundID(ctx context.Context) (*big.Int, error) { } func (e *EthereumAPIConsumer) Fund(ethAmount *big.Float) error { - gasEstimates, err := e.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := e.client.EstimateGas(ethereum.CallMsg{ + To: e.address, + }) if err != nil { return err } @@ -158,7 +161,9 @@ func (f *EthereumStaking) Address() string { // Fund sends specified currencies to the contract func (f *EthereumStaking) Fund(ethAmount *big.Float) error { - gasEstimates, err := f.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := f.client.EstimateGas(ethereum.CallMsg{ + To: f.address, + }) if err != nil { return err } @@ -902,7 +907,9 @@ func (f *EthereumFluxAggregator) Address() string { // Fund sends specified currencies to the contract func (f *EthereumFluxAggregator) Fund(ethAmount *big.Float) error { - gasEstimates, err := f.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := f.client.EstimateGas(ethereum.CallMsg{ + To: f.address, + }) if err != nil { return err } @@ -1193,7 +1200,9 @@ type EthereumLinkToken struct { // Fund the LINK Token contract with ETH to distribute the token func (l *EthereumLinkToken) Fund(ethAmount *big.Float) error { - gasEstimates, err := l.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := l.client.EstimateGas(ethereum.CallMsg{ + To: &l.address, + }) if err != nil { return err } @@ -1290,7 +1299,9 @@ type EthereumOffchainAggregator struct { // Fund sends specified currencies to the contract func (o *EthereumOffchainAggregator) Fund(ethAmount *big.Float) error { - gasEstimates, err := o.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := o.client.EstimateGas(ethereum.CallMsg{ + To: o.address, + }) if err != nil { return err } @@ -1960,7 +1971,9 @@ func (e *EthereumOffchainAggregatorV2) Address() string { } func (e *EthereumOffchainAggregatorV2) Fund(nativeAmount *big.Float) error { - gasEstimates, err := e.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := e.client.EstimateGas(ethereum.CallMsg{ + To: e.address, + }) if err != nil { return err } @@ -2238,10 +2251,7 @@ func (e *EthereumFunctionsLoadTestClient) ResetStats() error { if err != nil { return err } - if err := e.client.ProcessTransaction(tx); err != nil { - return err - } - return nil + return e.client.ProcessTransaction(tx) } func (e *EthereumFunctionsLoadTestClient) SendRequest(times uint32, source string, encryptedSecretsReferences []byte, args []string, subscriptionId uint64, jobId [32]byte) error { @@ -2433,66 +2443,66 @@ func (e *EthereumWERC20Mock) Address() common.Address { return e.address } -func (l *EthereumWERC20Mock) Approve(to string, amount *big.Int) error { - opts, err := l.client.TransactionOpts(l.client.GetDefaultWallet()) +func (e *EthereumWERC20Mock) Approve(to string, amount *big.Int) error { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) if err != nil { return err } - l.l.Info(). - Str("From", l.client.GetDefaultWallet().Address()). + e.l.Info(). + Str("From", e.client.GetDefaultWallet().Address()). Str("To", to). Str("Amount", amount.String()). Uint64("Nonce", opts.Nonce.Uint64()). Msg("Approving LINK Transfer") - tx, err := l.instance.Approve(opts, common.HexToAddress(to), amount) + tx, err := e.instance.Approve(opts, common.HexToAddress(to), amount) if err != nil { return err } - return l.client.ProcessTransaction(tx) + return e.client.ProcessTransaction(tx) } -func (l *EthereumWERC20Mock) BalanceOf(ctx context.Context, addr string) (*big.Int, error) { +func (e *EthereumWERC20Mock) BalanceOf(ctx context.Context, addr string) (*big.Int, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(l.client.GetDefaultWallet().Address()), + From: common.HexToAddress(e.client.GetDefaultWallet().Address()), Context: ctx, } - balance, err := l.instance.BalanceOf(opts, common.HexToAddress(addr)) + balance, err := e.instance.BalanceOf(opts, common.HexToAddress(addr)) if err != nil { return nil, err } return balance, nil } -func (l *EthereumWERC20Mock) Transfer(to string, amount *big.Int) error { - opts, err := l.client.TransactionOpts(l.client.GetDefaultWallet()) +func (e *EthereumWERC20Mock) Transfer(to string, amount *big.Int) error { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) if err != nil { return err } - l.l.Info(). - Str("From", l.client.GetDefaultWallet().Address()). + e.l.Info(). + Str("From", e.client.GetDefaultWallet().Address()). Str("To", to). Str("Amount", amount.String()). Uint64("Nonce", opts.Nonce.Uint64()). Msg("EthereumWERC20Mock.Transfer()") - tx, err := l.instance.Transfer(opts, common.HexToAddress(to), amount) + tx, err := e.instance.Transfer(opts, common.HexToAddress(to), amount) if err != nil { return err } - return l.client.ProcessTransaction(tx) + return e.client.ProcessTransaction(tx) } -func (l *EthereumWERC20Mock) Mint(account common.Address, amount *big.Int) (*types.Transaction, error) { - opts, err := l.client.TransactionOpts(l.client.GetDefaultWallet()) +func (e *EthereumWERC20Mock) Mint(account common.Address, amount *big.Int) (*types.Transaction, error) { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) if err != nil { return nil, err } - l.l.Info(). + e.l.Info(). Str("account", account.Hex()). Str("amount", amount.String()). Msg("EthereumWERC20Mock.Mint()") - tx, err := l.instance.Mint(opts, account, amount) + tx, err := e.instance.Mint(opts, account, amount) if err != nil { return tx, err } - return tx, l.client.ProcessTransaction(tx) + return tx, e.client.ProcessTransaction(tx) } diff --git a/integration-tests/contracts/ethereum_contracts_local.go b/integration-tests/contracts/ethereum_contracts_local.go index aba6bc354e1..316658a791e 100644 --- a/integration-tests/contracts/ethereum_contracts_local.go +++ b/integration-tests/contracts/ethereum_contracts_local.go @@ -3,11 +3,13 @@ package contracts import ( "encoding/hex" "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink/integration-tests/client" ocrConfigHelper "github.com/smartcontractkit/libocr/offchainreporting/confighelper" ocrTypes "github.com/smartcontractkit/libocr/offchainreporting/types" + + "github.com/smartcontractkit/chainlink/integration-tests/client" ) // SetConfigLocal sets the payees and the offchain reporting protocol configuration diff --git a/integration-tests/contracts/ethereum_keeper_contracts.go b/integration-tests/contracts/ethereum_keeper_contracts.go index afb6550bd2c..635ec1fd0e9 100644 --- a/integration-tests/contracts/ethereum_keeper_contracts.go +++ b/integration-tests/contracts/ethereum_keeper_contracts.go @@ -11,14 +11,13 @@ import ( geth "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/rs/zerolog" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" goabi "github.com/umbracle/ethgo/abi" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_consumer_benchmark" registrar21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_registrar_wrapper2_1" @@ -1356,13 +1355,13 @@ type KeeperConsumerBenchmarkRoundConfirmer struct { context context.Context cancel context.CancelFunc - firstBlockNum uint64 // Records the number of the first block that came in - lastBlockNum uint64 // Records the number of the last block that came in - blockRange int64 // How many blocks to watch upkeeps for - upkeepSLA int64 // SLA after which an upkeep is counted as 'missed' - metricsReporter *testreporters.KeeperBenchmarkTestReporter // Testreporter to track results - upkeepIndex int64 - firstEligibleuffer int64 + firstBlockNum uint64 // Records the number of the first block that came in + lastBlockNum uint64 // Records the number of the last block that came in + blockRange int64 // How many blocks to watch upkeeps for + upkeepSLA int64 // SLA after which an upkeep is counted as 'missed' + metricsReporter *testreporters.KeeperBenchmarkTestReporter // Testreporter to track results + upkeepIndex int64 + firstEligibleBuffer int64 // State variables, changes as we get blocks blocksSinceSubscription int64 // How many blocks have passed since subscribing @@ -1385,7 +1384,7 @@ func NewKeeperConsumerBenchmarkRoundConfirmer( upkeepSLA int64, metricsReporter *testreporters.KeeperBenchmarkTestReporter, upkeepIndex int64, - firstEligibleuffer int64, + firstEligibleBuffer int64, logger zerolog.Logger, ) *KeeperConsumerBenchmarkRoundConfirmer { ctx, cancelFunc := context.WithCancel(context.Background()) @@ -1407,7 +1406,7 @@ func NewKeeperConsumerBenchmarkRoundConfirmer( lastBlockNum: 0, upkeepIndex: upkeepIndex, firstBlockNum: 0, - firstEligibleuffer: firstEligibleuffer, + firstEligibleBuffer: firstEligibleBuffer, l: logger, } } @@ -1458,7 +1457,7 @@ func (o *KeeperConsumerBenchmarkRoundConfirmer) ReceiveHeader(receivedHeader blo o.blocksSinceEligible = 0 } - isEligible, err := o.instance.CheckEligible(context.Background(), big.NewInt(o.upkeepIndex), big.NewInt(o.blockRange), big.NewInt(o.firstEligibleuffer)) + isEligible, err := o.instance.CheckEligible(context.Background(), big.NewInt(o.upkeepIndex), big.NewInt(o.blockRange), big.NewInt(o.firstEligibleBuffer)) if err != nil { return err } diff --git a/integration-tests/contracts/ethereum_ocr2vrf_contracts.go b/integration-tests/contracts/ethereum_ocr2vrf_contracts.go index 11606de53e5..e8149b21251 100644 --- a/integration-tests/contracts/ethereum_ocr2vrf_contracts.go +++ b/integration-tests/contracts/ethereum_ocr2vrf_contracts.go @@ -4,11 +4,15 @@ import ( "context" "encoding/hex" "fmt" + "math/big" + "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" @@ -16,8 +20,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon_consumer" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_coordinator" - "math/big" - "time" ) // EthereumDKG represents DKG contract diff --git a/integration-tests/contracts/ethereum_vrf_contracts.go b/integration-tests/contracts/ethereum_vrf_contracts.go index f97ba86d975..427ac4ccbf8 100644 --- a/integration-tests/contracts/ethereum_vrf_contracts.go +++ b/integration-tests/contracts/ethereum_vrf_contracts.go @@ -13,7 +13,6 @@ import ( "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_consumer_interface" @@ -175,7 +174,9 @@ func (v *EthereumVRFConsumer) Address() string { } func (v *EthereumVRFConsumer) Fund(ethAmount *big.Float) error { - gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{ + To: v.address, + }) if err != nil { return err } @@ -277,7 +278,9 @@ func (f *VRFConsumerRoundConfirmer) Wait() error { // Fund sends specified currencies to the contract func (v *EthereumVRF) Fund(ethAmount *big.Float) error { - gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{ + To: v.address, + }) if err != nil { return err } diff --git a/integration-tests/contracts/ethereum_vrfv2_contracts.go b/integration-tests/contracts/ethereum_vrfv2_contracts.go index 88dfe58eb2f..1bcd460c399 100644 --- a/integration-tests/contracts/ethereum_vrfv2_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2_contracts.go @@ -3,17 +3,20 @@ package contracts import ( "context" "encoding/hex" + "math/big" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "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" - "math/big" + + eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" ) // EthereumVRFCoordinatorV2 represents VRFV2 coordinator contract @@ -286,7 +289,9 @@ func (v *EthereumVRFConsumerV2) GasAvailable() (*big.Int, error) { } func (v *EthereumVRFConsumerV2) Fund(ethAmount *big.Float) error { - gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{ + To: v.address, + }) if err != nil { return err } diff --git a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go index 4ca5c0fec45..463b392dac4 100644 --- a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" @@ -342,6 +343,18 @@ func (v *EthereumVRFv2PlusLoadTestConsumer) RequestRandomness(keyHash [32]byte, return tx, v.client.ProcessTransaction(tx) } +func (v *EthereumVRFv2PlusLoadTestConsumer) ResetMetrics() error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.consumer.Reset(opts) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} + func (v *EthereumVRFv2PlusLoadTestConsumer) GetCoordinator(ctx context.Context) (common.Address, error) { return v.consumer.SVrfCoordinator(&bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), @@ -785,7 +798,9 @@ func (v *EthereumVRFV2PlusWrapper) GetSubID(ctx context.Context) (*big.Int, erro } func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) Fund(ethAmount *big.Float) error { - gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{ + To: v.address, + }) if err != nil { return err } diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index d6ebaa69d81..8d8969e3ebb 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -232,12 +232,16 @@ func (n *ClNode) Fund(evmClient blockchain.EVMClient, amount *big.Float) error { if err != nil { return err } - gasEstimates, err := evmClient.EstimateGas(ethereum.CallMsg{}) + toAddr := common.HexToAddress(toAddress) + gasEstimates, err := evmClient.EstimateGas(ethereum.CallMsg{ + To: &toAddr, + }) if err != nil { return err } return evmClient.Fund(toAddress, amount, gasEstimates) } + func (n *ClNode) StartContainer() error { err := n.PostgresDb.StartContainer() if err != nil { @@ -248,7 +252,7 @@ func (n *ClNode) StartContainer() error { nodeSecretsToml, err := templates.NodeSecretsTemplate{ PgDbName: n.PostgresDb.DbName, PgHost: n.PostgresDb.ContainerName, - PgPort: n.PostgresDb.Port, + PgPort: n.PostgresDb.InternalPort, PgPassword: n.PostgresDb.Password, CustomSecrets: n.NodeSecretsConfigTOML, }.String() diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index 02db1ae788c..34e3dd17e34 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -231,83 +231,103 @@ func (te *CLClusterTestEnv) Terminate() error { return nil } -// Cleanup cleans the environment up after it's done being used, mainly for returning funds when on live networks. -// Intended to be used as part of t.Cleanup() in tests. -func (te *CLClusterTestEnv) Cleanup(t *testing.T) error { - if te.EVMClient == nil { - return errors.New("blockchain client is nil, unable to return funds from chainlink nodes") +// Cleanup cleans the environment up after it's done being used, mainly for returning funds when on live networks and logs. +func (te *CLClusterTestEnv) Cleanup() error { + te.l.Info().Msg("Cleaning up test environment") + if te.t == nil { + return errors.New("cannot cleanup test environment without a testing.T") } if te.CLNodes == nil { - return errors.New("chainlink nodes are nil, unable to return funds from chainlink nodes") + return errors.New("chainlink nodes are nil, unable cleanup chainlink nodes") } // TODO: This is an imperfect and temporary solution, see TT-590 for a more sustainable solution // Collect logs if the test fails, or if we just want them - if t.Failed() || os.Getenv("TEST_LOG_COLLECT") == "true" { - folder := fmt.Sprintf("./logs/%s-%s", t.Name(), time.Now().Format("2006-01-02T15-04-05")) - if err := os.MkdirAll(folder, os.ModePerm); err != nil { + if te.t.Failed() || os.Getenv("TEST_LOG_COLLECT") == "true" { + if err := te.collectTestLogs(); err != nil { return err } + } - te.l.Info().Msg("Collecting test logs") - eg := &errgroup.Group{} - for _, n := range te.CLNodes { - node := n - eg.Go(func() error { - logFileName := filepath.Join(folder, fmt.Sprintf("node-%s.log", node.ContainerName)) - logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - return err - } - defer logFile.Close() - logReader, err := node.Container.Logs(context.Background()) - if err != nil { - return err - } - _, err = io.Copy(logFile, logReader) - if err != nil { - return err - } - te.l.Info().Str("Node", node.ContainerName).Str("File", logFileName).Msg("Wrote Logs") - return nil - }) - } - - if err := eg.Wait(); err != nil { + if te.EVMClient == nil { + return errors.New("evm client is nil, unable to return funds from chainlink nodes during cleanup") + } else if te.EVMClient.NetworkSimulated() { + te.l.Info(). + Str("Network Name", te.EVMClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return.") + } else { + if err := te.returnFunds(); err != nil { return err } + } + + return nil +} - te.l.Info().Str("Logs Location", folder).Msg("Wrote test logs") +// collectTestLogs collects the logs from all the Chainlink nodes in the test environment and writes them to local files +func (te *CLClusterTestEnv) collectTestLogs() error { + te.l.Info().Msg("Collecting test logs") + folder := fmt.Sprintf("./logs/%s-%s", te.t.Name(), time.Now().Format("2006-01-02T15-04-05")) + if err := os.MkdirAll(folder, os.ModePerm); err != nil { + return err } - // Check if we need to return funds - if te.EVMClient.NetworkSimulated() { - te.l.Info().Str("Network Name", te.EVMClient.GetNetworkName()). - Msg("Network is a simulated network. Skipping fund return.") - } else { - te.l.Info().Msg("Attempting to return Chainlink node funds to default network wallets") - for _, chainlinkNode := range te.CLNodes { - fundedKeys, err := chainlinkNode.API.ExportEVMKeysForChain(te.EVMClient.GetChainID().String()) + eg := &errgroup.Group{} + for _, n := range te.CLNodes { + node := n + eg.Go(func() error { + logFileName := filepath.Join(folder, fmt.Sprintf("node-%s.log", node.ContainerName)) + logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return err + } + defer logFile.Close() + logReader, err := node.Container.Logs(context.Background()) + if err != nil { + return err + } + _, err = io.Copy(logFile, logReader) + if err != nil { + return err + } + te.l.Info().Str("Node", node.ContainerName).Str("File", logFileName).Msg("Wrote Logs") + return nil + }) + } + + if err := eg.Wait(); err != nil { + return err + } + + te.l.Info().Str("Logs Location", folder).Msg("Wrote test logs") + return nil +} + +func (te *CLClusterTestEnv) returnFunds() error { + te.l.Info().Msg("Attempting to return Chainlink node funds to default network wallets") + for _, chainlinkNode := range te.CLNodes { + fundedKeys, err := chainlinkNode.API.ExportEVMKeysForChain(te.EVMClient.GetChainID().String()) + if err != nil { + return err + } + for _, key := range fundedKeys { + keyToDecrypt, err := json.Marshal(key) + if err != nil { + return err + } + // This can take up a good bit of RAM and time. When running on the remote-test-runner, this can lead to OOM + // issues. So we avoid running in parallel; slower, but safer. + decryptedKey, err := keystore.DecryptKey(keyToDecrypt, client.ChainlinkKeyPassword) if err != nil { return err } - for _, key := range fundedKeys { - keyToDecrypt, err := json.Marshal(key) - if err != nil { - return err - } - // This can take up a good bit of RAM and time. When running on the remote-test-runner, this can lead to OOM - // issues. So we avoid running in parallel; slower, but safer. - decryptedKey, err := keystore.DecryptKey(keyToDecrypt, client.ChainlinkKeyPassword) - if err != nil { - return err - } - if err = te.EVMClient.ReturnFunds(decryptedKey.PrivateKey); err != nil { - return err - } + if err = te.EVMClient.ReturnFunds(decryptedKey.PrivateKey); err != nil { + // If we fail to return funds from one, go on to try the others anyway + te.l.Error().Err(err).Str("Node", chainlinkNode.ContainerName).Msg("Error returning funds from node") } } } + te.l.Info().Msg("Returned funds from Chainlink nodes") return nil } diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index ced617bc060..c9c68f0ea9c 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -171,6 +171,12 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } } + b.t.Cleanup(func() { + if err := b.te.Cleanup(); err != nil { + b.l.Error().Err(err).Msg("Error cleaning up test environment") + } + }) + if b.nonDevGethNetworks != nil { b.te.WithPrivateChain(b.nonDevGethNetworks) err := b.te.StartPrivateChain() diff --git a/integration-tests/go.mod b/integration-tests/go.mod index b9a4641eaf6..813199dfe9f 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -19,8 +19,8 @@ require ( github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.30.0 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-env v0.38.1 - github.com/smartcontractkit/chainlink-testing-framework v1.17.6 + github.com/smartcontractkit/chainlink-env v0.38.3 + github.com/smartcontractkit/chainlink-testing-framework v1.17.9 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6 github.com/smartcontractkit/ocr2keepers v0.7.27 @@ -32,8 +32,8 @@ require ( github.com/testcontainers/testcontainers-go v0.23.0 github.com/umbracle/ethgo v0.1.3 go.dedis.ch/kyber/v3 v3.1.0 - go.uber.org/zap v1.25.0 - golang.org/x/sync v0.3.0 + go.uber.org/zap v1.26.0 + golang.org/x/sync v0.4.0 gopkg.in/guregu/null.v4 v4.0.0 ) @@ -74,7 +74,6 @@ require ( github.com/aws/constructs-go/constructs/v10 v10.1.255 // indirect github.com/aws/jsii-runtime-go v1.75.0 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect - github.com/benbjohnson/clock v1.3.4 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/blendle/zapdriver v1.3.1 // indirect @@ -203,8 +202,8 @@ require ( github.com/grafana/dskit v0.0.0-20230201083518-528d8a7d52f2 // indirect github.com/grafana/loki v1.6.2-0.20230403212622-90888a0cc737 // indirect github.com/grafana/loki/pkg/push v0.0.0-20230127102416-571f88bc5765 // indirect - github.com/grafana/pyroscope-go v1.0.2 // indirect - github.com/grafana/pyroscope-go/godeltaprof v0.1.3 // indirect + github.com/grafana/pyroscope-go v1.0.4 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.4 // indirect github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect @@ -260,7 +259,7 @@ require ( github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/julienschmidt/httprouter v1.3.0 // indirect - github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/compress v1.17.0 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/koron/go-ssdp v0.0.2 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -362,12 +361,12 @@ require ( github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/prometheus/alertmanager v0.25.1 // indirect - github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/client_golang v1.17.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/common/sigv4 v0.1.0 // indirect github.com/prometheus/exporter-toolkit v0.10.0 // indirect - github.com/prometheus/procfs v0.11.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/prometheus v0.46.0 // indirect github.com/pyroscope-io/client v0.7.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect @@ -380,13 +379,13 @@ require ( github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/sercand/kuberesolver v2.4.0+incompatible // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/shirou/gopsutil/v3 v3.23.8 // indirect + github.com/shirou/gopsutil/v3 v3.23.9 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 // indirect github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231003135342-5e581164f8dd // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231010203454-896f5c3c04d1 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 // indirect github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect @@ -438,27 +437,27 @@ require ( go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 // indirect - go.opentelemetry.io/otel v1.16.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect + go.opentelemetry.io/otel v1.19.0 // indirect + go.opentelemetry.io/otel/metric v1.19.0 // indirect go.opentelemetry.io/otel/sdk v1.16.0 // indirect - go.opentelemetry.io/otel/trace v1.16.0 // indirect + go.opentelemetry.io/otel/trace v1.19.0 // indirect go.starlark.net v0.0.0-20220817180228-f738f5508c12 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/goleak v1.2.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect golang.org/x/arch v0.4.0 // indirect - golang.org/x/crypto v0.13.0 // indirect + golang.org/x/crypto v0.14.0 // indirect golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.15.0 // indirect + golang.org/x/mod v0.13.0 // indirect + golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect - golang.org/x/sys v0.12.0 // indirect - golang.org/x/term v0.12.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.11.0 // indirect + golang.org/x/tools v0.14.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect gonum.org/v1/gonum v0.13.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 802011b54ed..e72f008d1cc 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -678,8 +678,6 @@ github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.4 h1:wj3BFPrTw8yYgA1OlMqvUk95nc8OMv3cvBSF5erT2W4= -github.com/benbjohnson/clock v1.3.4/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -1362,10 +1360,10 @@ github.com/grafana/loki v1.6.2-0.20230403212622-90888a0cc737 h1:o45+fZAYRtTjx+9f github.com/grafana/loki v1.6.2-0.20230403212622-90888a0cc737/go.mod h1:kxNnWCr4EMobhndjy7a2Qpm7jkLPnJW2ariYvY77hLE= github.com/grafana/loki/pkg/push v0.0.0-20230127102416-571f88bc5765 h1:VXitROTlmZtLzvokNe8ZbUKpmwldM4Hy1zdNRO32jKU= github.com/grafana/loki/pkg/push v0.0.0-20230127102416-571f88bc5765/go.mod h1:DhJMrd2QInI/1CNtTN43BZuTmkccdizW1jZ+F6aHkhY= -github.com/grafana/pyroscope-go v1.0.2 h1:dEFgO9VbhYTwuwpCC5coTpuW0JjISEWDZtvRAW9v5Tw= -github.com/grafana/pyroscope-go v1.0.2/go.mod h1:bShDKsVZdzxq+Ol6no0JKigU9y5FTWUcFditMXaH09o= -github.com/grafana/pyroscope-go/godeltaprof v0.1.3 h1:eunWpv1B3Z7ZK9o4499EmQGlY+CsDmSZ4FbxjRx37uk= -github.com/grafana/pyroscope-go/godeltaprof v0.1.3/go.mod h1:1HSPtjU8vLG0jE9JrTdzjgFqdJ/VgN7fvxBNq3luJko= +github.com/grafana/pyroscope-go v1.0.4 h1:oyQX0BOkL+iARXzHuCdIF5TQ7/sRSel1YFViMHC7Bm0= +github.com/grafana/pyroscope-go v1.0.4/go.mod h1:0d7ftwSMBV/Awm7CCiYmHQEG8Y44Ma3YSjt+nWcWztY= +github.com/grafana/pyroscope-go/godeltaprof v0.1.4 h1:mDsJ3ngul7UfrHibGQpV66PbZ3q1T8glz/tK3bQKKEk= +github.com/grafana/pyroscope-go/godeltaprof v0.1.4/go.mod h1:1HSPtjU8vLG0jE9JrTdzjgFqdJ/VgN7fvxBNq3luJko= github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd h1:PpuIBO5P3e9hpqBD0O/HjhShYuM6XE0i/lbE6J94kww= github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A= github.com/graph-gophers/dataloader v5.0.0+incompatible h1:R+yjsbrNq1Mo3aPG+Z/EKYrXrXXUNJHOgbRt+U6jOug= @@ -1402,8 +1400,8 @@ github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBt github.com/hashicorp/consul/api v1.21.0 h1:WMR2JiyuaQWRAMFaOGiYfY4Q4HRpyYRe/oYQofjyduM= github.com/hashicorp/consul/api v1.21.0/go.mod h1:f8zVJwBcLdr1IQnfdfszjUM0xzp31Zl3bpws3pL9uFM= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.13.1 h1:EygWVWWMczTzXGpO93awkHFzfUka6hLYJ0qhETd+6lY= -github.com/hashicorp/consul/sdk v0.13.1/go.mod h1:SW/mM4LbKfqmMvcFu8v+eiQQ7oitXEFeiBe9StxERb0= +github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= +github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= github.com/hashicorp/cronexpr v1.1.1 h1:NJZDd87hGXjoZBdvyCF9mX4DCq5Wy7+A/w+A7q0wn6c= github.com/hashicorp/cronexpr v1.1.1/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -1673,8 +1671,8 @@ github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -2223,8 +2221,8 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/pressly/goose/v3 v3.15.0 h1:6tY5aDqFknY6VZkorFGgZtWygodZQxfmmEF4rqyJW9k= -github.com/pressly/goose/v3 v3.15.0/go.mod h1:LlIo3zGccjb/YUgG+Svdb9Er14vefRdlDI7URCDrwYo= +github.com/pressly/goose/v3 v3.15.1 h1:dKaJ1SdLvS/+HtS8PzFT0KBEtICC1jewLXM+b3emlv8= +github.com/pressly/goose/v3 v3.15.1/go.mod h1:0E3Yg/+EwYzO6Rz2P98MlClFgIcoujbVRs575yi3iIM= github.com/prometheus/alertmanager v0.25.1 h1:LGBNMspOfv8h7brb+LWj2wnwBCg2ZuuKWTh6CAVw2/Y= github.com/prometheus/alertmanager v0.25.1/go.mod h1:MEZ3rFVHqKZsw7IcNS/m4AWZeXThmJhumpiWR4eHU/w= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -2237,15 +2235,15 @@ github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrb github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= +github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -2272,8 +2270,8 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= -github.com/prometheus/procfs v0.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk= -github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/prometheus/prometheus v0.43.1-0.20230327151049-211ae4f1f0a2 h1:i5hmbBzR+VeL5pPl1ZncsJ1bpg3SO66bwkE1msJBsMA= github.com/prometheus/prometheus v0.43.1-0.20230327151049-211ae4f1f0a2/go.mod h1:Mm42Acga98xgA+u5yTaC3ki3i0rJEJWFpbdHN7q2trk= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= @@ -2340,8 +2338,8 @@ github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= -github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= +github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E= +github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -2362,16 +2360,16 @@ 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-cosmos v0.4.1-0.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-env v0.38.1 h1:jIn+BTtWOlQ2IInPgJEjwwuVG2eGDClybg56gsswv8o= -github.com/smartcontractkit/chainlink-env v0.38.1/go.mod h1:ICN9gOBY+NehK8mIxxM9CrWDohgkCQ1vgX9FazCbg8I= +github.com/smartcontractkit/chainlink-env v0.38.3 h1:ZtOnwkG622R0VCTxL5V09AnT/QXhlFwkGTjd0Lsfpfg= +github.com/smartcontractkit/chainlink-env v0.38.3/go.mod h1:7z4sw/hN8TxioQCLwFqQdhK3vaOV0a22Qe99z4bRUcg= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231003135342-5e581164f8dd h1:5r6SDRgZfi0kxc7D6sFV7h/bX+D7yewDq3FkyE0VMIM= github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231003135342-5e581164f8dd/go.mod h1:agmAM21+teJkw0aj9KYj3q3s1sFkx3PXo5ibWJIrDfU= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca h1:x7M0m512gtXw5Z4B1WJPZ52VgshoIv+IvHqQ8hsH4AE= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231010203454-896f5c3c04d1 h1:Tabg69K9lvQsGiXBQ8tsK6aAKPsUc1e4DHiY8an1zMk= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231010203454-896f5c3c04d1/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 h1:ByVauKFXphRlSNG47lNuxZ9aicu+r8AoNp933VRPpCw= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918/go.mod h1:/yp/sqD8Iz5GU5fcercjrw0ivJF7HDcupYg+Gjr7EPg= -github.com/smartcontractkit/chainlink-testing-framework v1.17.6 h1:hcsP1eyzrqQf3veK4xh0T37PFkq5AasDwlgJfl11atY= -github.com/smartcontractkit/chainlink-testing-framework v1.17.6/go.mod h1:rypNxetVFh6bwaoHn05bsd4vCtgdEsF+1Vdyy/AhAR8= +github.com/smartcontractkit/chainlink-testing-framework v1.17.9 h1:dU5F457J4JtLziQszkyFdgrpX7BE0SweEQ+QFlRHiR4= +github.com/smartcontractkit/chainlink-testing-framework v1.17.9/go.mod h1:Q6vSDsN8qWs8K5+XYvbUAkvl1PyW6tqcYwLpCX8PV44= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= @@ -2619,14 +2617,14 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.4 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 h1:pginetY7+onl4qN1vl0xW/V/v6OBZ0vVdH+esuJgvmM= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0/go.mod h1:XiYsayHc36K3EByOO6nbAXnAWbrUxdjUROCEeeROOH8= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= +go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= +go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= +go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= @@ -2661,8 +2659,8 @@ go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= -go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= @@ -2707,8 +2705,8 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2769,8 +2767,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -2856,8 +2854,8 @@ golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2906,8 +2904,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -3037,8 +3035,9 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -3049,8 +3048,8 @@ golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -3159,8 +3158,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= -golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/integration-tests/load/vrfv2plus/config.go b/integration-tests/load/vrfv2plus/config.go index 17178a458e6..3b76d64cc7f 100644 --- a/integration-tests/load/vrfv2plus/config.go +++ b/integration-tests/load/vrfv2plus/config.go @@ -1,11 +1,11 @@ package loadvrfv2plus import ( + "encoding/base64" "github.com/pelletier/go-toml/v2" "github.com/pkg/errors" "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "math/big" "os" ) @@ -17,20 +17,31 @@ const ( ) type PerformanceConfig struct { - Soak *Soak `toml:"Soak"` - Load *Load `toml:"Load"` - SoakVolume *SoakVolume `toml:"SoakVolume"` - LoadVolume *LoadVolume `toml:"LoadVolume"` - Common *Common `toml:"Common"` + Soak *Soak `toml:"Soak"` + Load *Load `toml:"Load"` + SoakVolume *SoakVolume `toml:"SoakVolume"` + LoadVolume *LoadVolume `toml:"LoadVolume"` + Common *Common `toml:"Common"` + ExistingEnvConfig *ExistingEnvConfig `toml:"ExistingEnvConfig"` +} + +type ExistingEnvConfig struct { + CoordinatorAddress string `toml:"coordinator_address"` + ConsumerAddress string `toml:"consumer_address"` + SubID string `toml:"sub_id"` + KeyHash string `toml:"key_hash"` } type Common struct { Funding + IsNativePayment bool `toml:"is_native_payment"` + MinimumConfirmations uint16 `toml:"minimum_confirmations"` } type Funding struct { - NodeFunds *big.Float `toml:"node_funds"` - SubFunds *big.Int `toml:"sub_funds"` + NodeFunds float64 `toml:"node_funds"` + SubFundsLink int64 `toml:"sub_funds_link"` + SubFundsNative int64 `toml:"sub_funds_native"` } type Soak struct { @@ -61,14 +72,22 @@ type LoadVolume struct { func ReadConfig() (*PerformanceConfig, error) { var cfg *PerformanceConfig - d, err := os.ReadFile(DefaultConfigFilename) - if err != nil { - return nil, errors.Wrap(err, ErrReadPerfConfig) + rawConfig := os.Getenv("CONFIG") + var d []byte + var err error + if rawConfig == "" { + d, err = os.ReadFile(DefaultConfigFilename) + if err != nil { + return nil, errors.Wrap(err, ErrReadPerfConfig) + } + } else { + d, err = base64.StdEncoding.DecodeString(rawConfig) } err = toml.Unmarshal(d, &cfg) if err != nil { return nil, errors.Wrap(err, ErrUnmarshalPerfConfig) } - log.Debug().Interface("PerformanceConfig", cfg).Msg("Parsed performance config") + + log.Debug().Interface("Config", cfg).Msg("Parsed config") return cfg, nil } diff --git a/integration-tests/load/vrfv2plus/config.toml b/integration-tests/load/vrfv2plus/config.toml index 03169b4c9d7..d77c22badb8 100644 --- a/integration-tests/load/vrfv2plus/config.toml +++ b/integration-tests/load/vrfv2plus/config.toml @@ -1,27 +1,14 @@ -# testing one product (jobs + contracts) by varying RPS -[Soak] -rps = 1 -duration = "1m" - -[Load] -rps_from = 1 -rps_increase = 1 -rps_steps = 10 -duration = "3m" - -# testing multiple products (jobs + contracts) by varying instances, deploying more of the same type with stable RPS for each product -[SoakVolume] -products = 5 -pace = "1s" -duration = "3m" - -[LoadVolume] -products_from = 1 -products_increase = 1 -products_steps = 10 -pace = "1s" -duration = "3m" [Common] -node_funds = 10 -sub_funds = 100 +node_funds = 0.1 +is_native_payment = false +minimum_confirmations = 3 +sub_funds_link = 10 +sub_funds_native = 1 + +[ExistingEnvConfig] +coordinator_address = "0x4931Ce2e341398c8eD8A5D0F6ADb920476D6DaBb" +consumer_address = "0x087F232165D9bA1A602f148025e5D0666953F64a" +sub_id = "52116875585187328970776211988181422347535732407068188096422095950800466618218" +key_hash = "0x4c422465ed6a06cfc84575a5437fef7b9dc6263133f648afbe6ae7b2c694d3b3" + diff --git a/integration-tests/load/vrfv2plus/onchain_monitoring.go b/integration-tests/load/vrfv2plus/onchain_monitoring.go index b22bf8259d1..0ae27fe6be0 100644 --- a/integration-tests/load/vrfv2plus/onchain_monitoring.go +++ b/integration-tests/load/vrfv2plus/onchain_monitoring.go @@ -18,30 +18,33 @@ const ( ErrLokiPush = "failed to push monitoring metrics to Loki" ) -func MonitorLoadStats(t *testing.T, vrfv2PlusContracts *vrfv2plus.VRFV2_5Contracts, labels map[string]string) { +func MonitorLoadStats(lc *wasp.LokiClient, vrfv2PlusContracts *vrfv2plus.VRFV2_5Contracts, labels map[string]string) { go func() { - updatedLabels := make(map[string]string) - for k, v := range labels { - updatedLabels[k] = v - } - updatedLabels["type"] = LokiTypeLabel - updatedLabels["go_test_name"] = t.Name() - updatedLabels["gen_name"] = "performance" - lc, err := wasp.NewLokiClient(wasp.NewEnvLokiConfig()) - if err != nil { - log.Error().Err(err).Msg(ErrLokiClient) - return - } for { time.Sleep(1 * time.Second) - //todo - should work with multiple consumers and consumers having different keyhashes and wallets - metrics, err := vrfv2PlusContracts.LoadTestConsumers[0].GetLoadTestMetrics(context.Background()) - if err != nil { - log.Error().Err(err).Msg(ErrMetrics) - } - if err := lc.HandleStruct(wasp.LabelsMapToModel(updatedLabels), time.Now(), metrics); err != nil { - log.Error().Err(err).Msg(ErrLokiPush) - } + SendLoadTestMetricsToLoki(vrfv2PlusContracts, lc, labels) } }() } + +func UpdateLabels(labels map[string]string, t *testing.T) map[string]string { + updatedLabels := make(map[string]string) + for k, v := range labels { + updatedLabels[k] = v + } + updatedLabels["type"] = LokiTypeLabel + updatedLabels["go_test_name"] = t.Name() + updatedLabels["gen_name"] = "performance" + return updatedLabels +} + +func SendLoadTestMetricsToLoki(vrfv2PlusContracts *vrfv2plus.VRFV2_5Contracts, lc *wasp.LokiClient, updatedLabels map[string]string) { + //todo - should work with multiple consumers and consumers having different keyhashes and wallets + metrics, err := vrfv2PlusContracts.LoadTestConsumers[0].GetLoadTestMetrics(context.Background()) + if err != nil { + log.Error().Err(err).Msg(ErrMetrics) + } + if err := lc.HandleStruct(wasp.LabelsMapToModel(updatedLabels), time.Now(), metrics); err != nil { + log.Error().Err(err).Msg(ErrLokiPush) + } +} diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index ee8be6bd8a5..5221a9860f6 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -3,64 +3,107 @@ package loadvrfv2plus import ( "context" "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/kelseyhightower/envconfig" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/wasp" "github.com/stretchr/testify/require" "math/big" "sync" "testing" "time" + + "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" ) func TestVRFV2PlusLoad(t *testing.T) { - + cfg, err := ReadConfig() + require.NoError(t, err) var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig - err := envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) + err = envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) require.NoError(t, err) l := logging.GetTestLogger(t) + //todo: temporary solution with envconfig and toml config until VRF-662 is implemented + vrfv2PlusConfig.ChainlinkNodeFunding = cfg.Common.NodeFunds + vrfv2PlusConfig.IsNativePayment = cfg.Common.IsNativePayment + vrfv2PlusConfig.MinimumConfirmations = cfg.Common.MinimumConfirmations + vrfv2PlusConfig.SubscriptionFundingAmountLink = cfg.Common.Funding.SubFundsLink + vrfv2PlusConfig.SubscriptionFundingAmountNative = cfg.Common.Funding.SubFundsNative + + var env *test_env.CLClusterTestEnv + var vrfv2PlusContracts *vrfv2plus.VRFV2_5Contracts + var subID *big.Int + var vrfv2PlusData *vrfv2plus.VRFV2PlusData + if vrfv2PlusConfig.UseExistingEnv { + //todo: temporary solution with envconfig and toml config until VRF-662 is implemented + vrfv2PlusConfig.CoordinatorAddress = cfg.ExistingEnvConfig.CoordinatorAddress + vrfv2PlusConfig.ConsumerAddress = cfg.ExistingEnvConfig.ConsumerAddress + vrfv2PlusConfig.SubID = cfg.ExistingEnvConfig.SubID + vrfv2PlusConfig.KeyHash = cfg.ExistingEnvConfig.KeyHash + + env, err = test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). + Build() + + require.NoError(t, err, "error creating test env") + + coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2_5(vrfv2PlusConfig.CoordinatorAddress) + require.NoError(t, err) - env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). - WithGeth(). - WithCLNodes(1). - WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). - WithLogWatcher(). - Build() - require.NoError(t, err, "error creating test env") - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") + consumer, err := env.ContractLoader.LoadVRFv2PlusLoadTestConsumer(vrfv2PlusConfig.ConsumerAddress) + require.NoError(t, err) + + vrfv2PlusContracts = &vrfv2plus.VRFV2_5Contracts{ + Coordinator: coordinator, + LoadTestConsumers: []contracts.VRFv2PlusLoadTestConsumer{consumer}, + BHS: nil, } - }) + var ok bool + subID, ok = new(big.Int).SetString(vrfv2PlusConfig.SubID, 10) + require.True(t, ok) + + vrfv2PlusData = &vrfv2plus.VRFV2PlusData{ + VRFV2PlusKeyData: vrfv2plus.VRFV2PlusKeyData{ + VRFKey: nil, + EncodedProvingKey: [2]*big.Int{}, + KeyHash: common.HexToHash(vrfv2PlusConfig.KeyHash), + }, + VRFJob: nil, + PrimaryEthAddress: "", + ChainID: nil, + } + } else { + env, err = test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). + WithGeth(). + WithCLNodes(1). + WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). + WithLogWatcher(). + Build() - env.ParallelTransactions(true) + require.NoError(t, err, "error creating test env") - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) - require.NoError(t, err, "error deploying mock ETH/LINK feed") + env.ParallelTransactions(true) - linkToken, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err, "error deploying LINK contract") + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) + require.NoError(t, err, "error deploying mock ETH/LINK feed") - vrfv2PlusContracts, subID, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, vrfv2PlusConfig, linkToken, mockETHLinkFeed, 1) - require.NoError(t, err, "error setting up VRF v2_5 env") + linkToken, err := actions.DeployLINKToken(env.ContractDeployer) + require.NoError(t, err, "error deploying LINK contract") + + vrfv2PlusContracts, subID, vrfv2PlusData, err = vrfv2plus.SetupVRFV2_5Environment(env, vrfv2PlusConfig, linkToken, mockETHLinkFeed, 1) + require.NoError(t, err, "error setting up VRF v2_5 env") + } subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subID) require.NoError(t, err, "error getting subscription information") - l.Debug(). - Str("Juels Balance", subscription.Balance.String()). - Str("Native Token Balance", subscription.NativeBalance.String()). - Str("Subscription ID", subID.String()). - Str("Subscription Owner", subscription.Owner.String()). - Interface("Subscription Consumers", subscription.Consumers). - Msg("Subscription Data") + vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) labels := map[string]string{ "branch": "vrfv2Plus_healthcheck", @@ -70,9 +113,18 @@ func TestVRFV2PlusLoad(t *testing.T) { l.Info(). Str("Test Duration", vrfv2PlusConfig.TestDuration.Truncate(time.Second).String()). Int64("RPS", vrfv2PlusConfig.RPS). + Str("RateLimitUnitDuration", vrfv2PlusConfig.RateLimitUnitDuration.String()). Uint16("RandomnessRequestCountPerRequest", vrfv2PlusConfig.RandomnessRequestCountPerRequest). + Bool("UseExistingEnv", vrfv2PlusConfig.UseExistingEnv). Msg("Load Test Configs") + lokiConfig := wasp.NewEnvLokiConfig() + lc, err := wasp.NewLokiClient(lokiConfig) + if err != nil { + l.Error().Err(err).Msg(ErrLokiClient) + return + } + singleFeedConfig := &wasp.Config{ T: t, LoadType: wasp.RPS, @@ -83,21 +135,26 @@ func TestVRFV2PlusLoad(t *testing.T) { vrfv2PlusData.KeyHash, subID, vrfv2PlusConfig, - l), + l, + ), Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: lokiConfig, CallTimeout: 2 * time.Minute, } - - MonitorLoadStats(t, vrfv2PlusContracts, labels) + consumer := vrfv2PlusContracts.LoadTestConsumers[0] + err = consumer.ResetMetrics() + require.NoError(t, err) + updatedLabels := UpdateLabels(labels, t) + MonitorLoadStats(lc, vrfv2PlusContracts, updatedLabels) // is our "job" stable at all, no memory leaks, no flaking performance under some RPS? t.Run("vrfv2plus soak test", func(t *testing.T) { + singleFeedConfig.Schedule = wasp.Plain( vrfv2PlusConfig.RPS, vrfv2PlusConfig.TestDuration, ) - _, err := wasp.NewProfile(). + _, err = wasp.NewProfile(). Add(wasp.NewGenerator(singleFeedConfig)). Run(true) require.NoError(t, err) @@ -111,8 +168,9 @@ func TestVRFV2PlusLoad(t *testing.T) { Interface("Fulfilment Count", fulfilmentCount). Msg("Final Request/Fulfilment Stats") require.NoError(t, err) - wg.Wait() + //send final results + SendLoadTestMetricsToLoki(vrfv2PlusContracts, lc, updatedLabels) }) } @@ -138,10 +196,12 @@ func WaitForRequestCountEqualToFulfilmentCount(consumer contracts.VRFv2PlusLoadT go getLoadTestMetrics(consumer, metricsChannel, metricsErrorChannel) case metrics = <-metricsChannel: if metrics.RequestCount.Cmp(metrics.FulfilmentCount) == 0 { + ticker.Stop() wg.Done() return metrics.RequestCount, metrics.FulfilmentCount, nil } case err := <-metricsErrorChannel: + ticker.Stop() wg.Done() return nil, nil, err } diff --git a/integration-tests/scripts/entrypoint b/integration-tests/scripts/entrypoint index 3955023685d..cb5c98fde6a 100755 --- a/integration-tests/scripts/entrypoint +++ b/integration-tests/scripts/entrypoint @@ -21,7 +21,9 @@ exit_code=$? echo "Test exit code: ${exit_code}" -if [ $exit_code -eq 2 ]; then # 2 is the code for an interrupted test, we only want to restart the test when the test is interrupted +# 3 is the code for an interrupted test, we only want to restart the test when the test is interrupted and in a state +# that it can recover from. Otherwise we mark the test as "passed" as far as K8s is concerned so it doesn't restart it. +if [ $exit_code -eq 3 ]; then exit 1 # Exiting with non-zero status to trigger pod restart fi diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index db34cb28e1e..ca5db25cd97 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -16,7 +16,10 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + + cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" + "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" @@ -25,9 +28,6 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" - cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) var utilsABI = cltypes.MustGetABI(automation_utils_2_1.AutomationUtilsABI) @@ -105,10 +105,11 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { testName = "basic-upkeep" ) if nodeUpgrade { - upgradeImage, err = utils.GetEnv("UPGRADE_IMAGE") - require.NoError(t, err, "Error getting upgrade image") - upgradeVersion, err = utils.GetEnv("UPGRADE_VERSION") - require.NoError(t, err, "Error getting upgrade version") + upgradeImage = os.Getenv("UPGRADE_IMAGE") + upgradeVersion = os.Getenv("UPGRADE_VERSION") + if len(upgradeImage) == 0 || len(upgradeVersion) == 0 { + t.Fatal("UPGRADE_IMAGE and UPGRADE_VERSION must be set to upgrade nodes") + } testName = "node-upgrade" } chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupAutomationTestDocker( diff --git a/integration-tests/smoke/cron_test.go b/integration-tests/smoke/cron_test.go index 26e039289cf..dee37af3540 100644 --- a/integration-tests/smoke/cron_test.go +++ b/integration-tests/smoke/cron_test.go @@ -26,11 +26,6 @@ func TestCronBasic(t *testing.T) { WithCLNodes(1). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) err = env.MockAdapter.SetAdapterBasedIntValuePath("/variable", []string{http.MethodGet, http.MethodPost}, 5) require.NoError(t, err, "Setting value path in mock adapter shouldn't fail") diff --git a/integration-tests/smoke/flux_test.go b/integration-tests/smoke/flux_test.go index c2fbf2d435b..b517cb5b57a 100644 --- a/integration-tests/smoke/flux_test.go +++ b/integration-tests/smoke/flux_test.go @@ -32,11 +32,6 @@ func TestFluxBasic(t *testing.T) { WithCLNodes(3). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) nodeAddresses, err := env.ChainlinkNodeAddresses() require.NoError(t, err, "Retrieving on-chain wallet addresses for chainlink nodes shouldn't fail") diff --git a/integration-tests/smoke/forwarder_ocr_test.go b/integration-tests/smoke/forwarder_ocr_test.go index a6c0cacb96c..21f108c732f 100644 --- a/integration-tests/smoke/forwarder_ocr_test.go +++ b/integration-tests/smoke/forwarder_ocr_test.go @@ -27,11 +27,6 @@ func TestForwarderOCRBasic(t *testing.T) { WithFunding(big.NewFloat(.1)). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) env.ParallelTransactions(true) diff --git a/integration-tests/smoke/forwarders_ocr2_test.go b/integration-tests/smoke/forwarders_ocr2_test.go index 2840658122e..994a1038f12 100644 --- a/integration-tests/smoke/forwarders_ocr2_test.go +++ b/integration-tests/smoke/forwarders_ocr2_test.go @@ -36,11 +36,6 @@ func TestForwarderOCR2Basic(t *testing.T) { WithFunding(big.NewFloat(.1)). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) env.ParallelTransactions(true) diff --git a/integration-tests/smoke/keeper_test.go b/integration-tests/smoke/keeper_test.go index 5b002b7b9ba..3280a7a23a6 100644 --- a/integration-tests/smoke/keeper_test.go +++ b/integration-tests/smoke/keeper_test.go @@ -1105,7 +1105,6 @@ func setupKeeperTest(t *testing.T) ( clNodeConfig.Keeper.TurnLookBack = &turnLookBack clNodeConfig.Keeper.Registry.SyncInterval = &syncInterval clNodeConfig.Keeper.Registry.PerformGasOverhead = &performGasOverhead - l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). WithTestLogger(t). @@ -1115,11 +1114,6 @@ func setupKeeperTest(t *testing.T) ( WithFunding(big.NewFloat(.5)). Build() require.NoError(t, err, "Error deploying test environment") - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) env.ParallelTransactions(true) diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index ccc75574f21..ac5ab3fdbb2 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -44,11 +44,6 @@ func TestOCRv2Basic(t *testing.T) { WithFunding(big.NewFloat(.1)). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) env.ParallelTransactions(true) diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index dad3b0272fe..75c31e4aa2e 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -25,11 +25,6 @@ func TestOCRBasic(t *testing.T) { WithFunding(big.NewFloat(.1)). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) env.ParallelTransactions(true) diff --git a/integration-tests/smoke/runlog_test.go b/integration-tests/smoke/runlog_test.go index 380d0602c06..14b467764ba 100644 --- a/integration-tests/smoke/runlog_test.go +++ b/integration-tests/smoke/runlog_test.go @@ -30,11 +30,6 @@ func TestRunLogBasic(t *testing.T) { WithFunding(big.NewFloat(.1)). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) lt, err := env.ContractDeployer.DeployLinkTokenContract() require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") diff --git a/integration-tests/smoke/vrf_test.go b/integration-tests/smoke/vrf_test.go index b4a129ad8dc..d375506a776 100644 --- a/integration-tests/smoke/vrf_test.go +++ b/integration-tests/smoke/vrf_test.go @@ -30,11 +30,6 @@ func TestVRFBasic(t *testing.T) { WithFunding(big.NewFloat(.1)). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) env.ParallelTransactions(true) lt, err := actions.DeployLINKToken(env.ContractDeployer) diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index 18e9efeae44..1b431397574 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -29,11 +29,6 @@ func TestVRFv2Basic(t *testing.T) { WithFunding(vrfConst.ChainlinkNodeFundingAmountEth). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) env.ParallelTransactions(true) mockFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, vrfConst.LinkEthFeedResponse) diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index c2b99850811..659616330b5 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -2,15 +2,15 @@ package smoke import ( "context" - "github.com/kelseyhightower/envconfig" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" "math/big" "testing" "time" + "github.com/kelseyhightower/envconfig" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" + "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" @@ -36,11 +36,6 @@ func TestVRFv2Plus(t *testing.T) { WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). Build() require.NoError(t, err, "error creating test env") - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) env.ParallelTransactions(true) @@ -56,13 +51,7 @@ func TestVRFv2Plus(t *testing.T) { subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subID) require.NoError(t, err, "error getting subscription information") - l.Debug(). - Str("Juels Balance", subscription.Balance.String()). - Str("Native Token Balance", subscription.NativeBalance.String()). - Str("Subscription ID", subID.String()). - Str("Subscription Owner", subscription.Owner.String()). - Interface("Subscription Consumers", subscription.Consumers). - Msg("Subscription Data") + vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) t.Run("VRFV2 Plus With Link Billing", func(t *testing.T) { var isNativeBilling = false @@ -195,18 +184,7 @@ func TestVRFv2Plus(t *testing.T) { //todo: uncomment when VRF-651 will be fixed //require.Equal(t, 1, consumerStatus.Paid.Cmp(randomWordsFulfilledEvent.Payment), "Expected Consumer contract pay more than the Coordinator Sub") - l.Debug(). - Str("Consumer Balance Before Request (Juels)", wrapperConsumerJuelsBalanceBeforeRequest.String()). - Str("Consumer Balance After Request (Juels)", wrapperConsumerJuelsBalanceAfterRequest.String()). - Bool("Fulfilment Status", consumerStatus.Fulfilled). - Str("Paid in Juels by Consumer Contract", consumerStatus.Paid.String()). - Str("Paid in Juels by Coordinator Sub", randomWordsFulfilledEvent.Payment.String()). - 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 Request Fulfilment Status") + vrfv2plus.LogFulfillmentDetailsLinkBilling(l, wrapperConsumerJuelsBalanceBeforeRequest, wrapperConsumerJuelsBalanceAfterRequest, consumerStatus, randomWordsFulfilledEvent) require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) for _, w := range consumerStatus.RandomWords { @@ -254,18 +232,7 @@ func TestVRFv2Plus(t *testing.T) { //todo: uncomment when VRF-651 will be fixed //require.Equal(t, 1, consumerStatus.Paid.Cmp(randomWordsFulfilledEvent.Payment), "Expected Consumer contract pay more than the Coordinator Sub") - l.Debug(). - Str("Consumer Balance Before Request (WEI)", wrapperConsumerBalanceBeforeRequestWei.String()). - Str("Consumer Balance After Request (WEI)", wrapperConsumerBalanceAfterRequestWei.String()). - Bool("Fulfilment Status", consumerStatus.Fulfilled). - Str("Paid in Juels by Consumer Contract", consumerStatus.Paid.String()). - Str("Paid in Juels by Coordinator Sub", randomWordsFulfilledEvent.Payment.String()). - 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 Request Fulfilment Status") + vrfv2plus.LogFulfillmentDetailsNativeBilling(l, wrapperConsumerBalanceBeforeRequestWei, wrapperConsumerBalanceAfterRequestWei, consumerStatus, randomWordsFulfilledEvent) require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) for _, w := range consumerStatus.RandomWords { @@ -275,6 +242,7 @@ func TestVRFv2Plus(t *testing.T) { }) } + func TestVRFv2PlusMigration(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) @@ -289,12 +257,6 @@ func TestVRFv2PlusMigration(t *testing.T) { WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). Build() require.NoError(t, err, "error creating test env") - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) - env.ParallelTransactions(true) mockETHLinkFeedAddress, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) @@ -309,13 +271,7 @@ func TestVRFv2PlusMigration(t *testing.T) { subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subID) require.NoError(t, err, "error getting subscription information") - l.Debug(). - Str("Juels Balance", subscription.Balance.String()). - Str("Native Token Balance", subscription.NativeBalance.String()). - Str("Subscription ID", subID.String()). - Str("Subscription Owner", subscription.Owner.String()). - Interface("Subscription Consumers", subscription.Consumers). - Msg("Subscription Data") + vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) activeSubIdsOldCoordinatorBeforeMigration, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(context.Background(), big.NewInt(0), big.NewInt(0)) require.NoError(t, err, "error occurred getting active sub ids") @@ -384,11 +340,7 @@ func TestVRFv2PlusMigration(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) - l.Debug(). - Str("Subscription ID", migrationCompletedEvent.SubId.String()). - Str("Migrated From Coordinator", vrfv2PlusContracts.Coordinator.Address()). - Str("Migrated To Coordinator", migrationCompletedEvent.NewCoordinator.String()). - Msg("MigrationCompleted Event") + vrfv2plus.LogMigrationCompletedEvent(l, migrationCompletedEvent, vrfv2PlusContracts) oldCoordinatorLinkTotalBalanceAfterMigration, oldCoordinatorEthTotalBalanceAfterMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfv2PlusContracts.Coordinator) require.NoError(t, err) @@ -399,14 +351,7 @@ func TestVRFv2PlusMigration(t *testing.T) { migratedSubscription, err := newCoordinator.GetSubscription(context.Background(), subID) require.NoError(t, err, "error getting subscription information") - l.Debug(). - Str("New Coordinator", newCoordinator.Address()). - Str("Subscription ID", subID.String()). - Str("Juels Balance", migratedSubscription.Balance.String()). - Str("Native Token Balance", migratedSubscription.NativeBalance.String()). - Str("Subscription Owner", migratedSubscription.Owner.String()). - Interface("Subscription Consumers", migratedSubscription.Consumers). - Msg("Subscription Data After Migration to New Coordinator") + vrfv2plus.LogSubDetailsAfterMigration(l, newCoordinator, subID, migratedSubscription) //Verify that Coordinators were updated in Consumers for _, consumer := range vrfv2PlusContracts.LoadTestConsumers { diff --git a/integration-tests/testsetups/keeper_benchmark.go b/integration-tests/testsetups/keeper_benchmark.go index ba0cc23b23b..5033e7e3d17 100644 --- a/integration-tests/testsetups/keeper_benchmark.go +++ b/integration-tests/testsetups/keeper_benchmark.go @@ -5,6 +5,9 @@ import ( "fmt" "math" "math/big" + "os" + "os/signal" + "syscall" "testing" "time" @@ -13,6 +16,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/slack-go/slack" "github.com/stretchr/testify/require" @@ -21,7 +25,6 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" - iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_1" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_2" @@ -41,6 +44,10 @@ type KeeperBenchmarkTest struct { Inputs KeeperBenchmarkTestInputs TestReporter testreporters.KeeperBenchmarkTestReporter + t *testing.T + log zerolog.Logger + startingBlock *big.Int + keeperRegistries []contracts.KeeperRegistry keeperRegistrars []contracts.KeeperRegistrar keeperConsumerContracts []contracts.AutomationConsumerBenchmark @@ -57,6 +64,7 @@ type KeeperBenchmarkTest struct { gasFeed contracts.MockGasFeed } +// UpkeepConfig dictates details of how the test's upkeep contracts should be called and configured type UpkeepConfig struct { NumberOfUpkeeps int // Number of upkeep contracts BlockRange int64 // How many blocks to run the test for @@ -67,6 +75,8 @@ type UpkeepConfig struct { FirstEligibleBuffer int64 // How many blocks to add to randomised first eligible block, set to 0 to disable randomised first eligible block } +// PreDeployedContracts are contracts that are already deployed on a (usually) live testnet chain, so re-deployment +// in unnecessary type PreDeployedContracts struct { RegistryAddress string RegistrarAddress string @@ -92,18 +102,19 @@ type KeeperBenchmarkTestInputs struct { } // NewKeeperBenchmarkTest prepares a new keeper benchmark test to be run -func NewKeeperBenchmarkTest(inputs KeeperBenchmarkTestInputs) *KeeperBenchmarkTest { +func NewKeeperBenchmarkTest(t *testing.T, inputs KeeperBenchmarkTestInputs) *KeeperBenchmarkTest { return &KeeperBenchmarkTest{ Inputs: inputs, + t: t, + log: logging.GetTestLogger(t), } } // Setup prepares contracts for the test -func (k *KeeperBenchmarkTest) Setup(t *testing.T, env *environment.Environment) { - l := logging.GetTestLogger(t) +func (k *KeeperBenchmarkTest) Setup(env *environment.Environment) { startTime := time.Now() k.TestReporter.Summary.StartTime = startTime.UnixMilli() - k.ensureInputValues(t) + k.ensureInputValues() k.env = env k.namespace = k.env.Cfg.Namespace inputs := k.Inputs @@ -112,70 +123,65 @@ func (k *KeeperBenchmarkTest) Setup(t *testing.T, env *environment.Environment) k.keeperRegistrars = make([]contracts.KeeperRegistrar, len(inputs.RegistryVersions)) k.keeperConsumerContracts = make([]contracts.AutomationConsumerBenchmark, len(inputs.RegistryVersions)) k.upkeepIDs = make([][]*big.Int, len(inputs.RegistryVersions)) - l.Debug().Interface("TestInputs", inputs).Msg("Setting up benchmark test") + k.log.Debug().Interface("TestInputs", inputs).Msg("Setting up benchmark test") var err error // Connect to networks and prepare for contract deployment - k.contractDeployer, err = contracts.NewContractDeployer(k.chainClient, l) - require.NoError(t, err, "Building a new contract deployer shouldn't fail") + k.contractDeployer, err = contracts.NewContractDeployer(k.chainClient, k.log) + require.NoError(k.t, err, "Building a new contract deployer shouldn't fail") k.chainlinkNodes, err = client.ConnectChainlinkNodes(k.env) - require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") + require.NoError(k.t, err, "Connecting to chainlink nodes shouldn't fail") k.chainClient.ParallelTransactions(true) if len(inputs.RegistryVersions) > 1 && !inputs.ForceSingleTxnKey { for nodeIndex, node := range k.chainlinkNodes { for registryIndex := 1; registryIndex < len(inputs.RegistryVersions); registryIndex++ { - l.Debug().Str("URL", node.URL()).Int("NodeIndex", nodeIndex).Int("RegistryIndex", registryIndex).Msg("Create Tx key") + k.log.Debug().Str("URL", node.URL()).Int("NodeIndex", nodeIndex).Int("RegistryIndex", registryIndex).Msg("Create Tx key") _, _, err := node.CreateTxKey("evm", k.Inputs.BlockchainClient.GetChainID().String()) - require.NoError(t, err, "Creating transaction key shouldn't fail") + require.NoError(k.t, err, "Creating transaction key shouldn't fail") } } } - var () - c := inputs.Contracts if common.IsHexAddress(c.LinkTokenAddress) { k.linkToken, err = k.contractDeployer.LoadLinkToken(common.HexToAddress(c.LinkTokenAddress)) - require.NoError(t, err, "Loading Link Token Contract shouldn't fail") + require.NoError(k.t, err, "Loading Link Token Contract shouldn't fail") } else { k.linkToken, err = k.contractDeployer.DeployLinkTokenContract() - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") + require.NoError(k.t, err, "Deploying Link Token Contract shouldn't fail") err = k.chainClient.WaitForEvents() - require.NoError(t, err, "Failed waiting for LINK Contract deployment") + require.NoError(k.t, err, "Failed waiting for LINK Contract deployment") } if common.IsHexAddress(c.EthFeedAddress) { k.ethFeed, err = k.contractDeployer.LoadETHLINKFeed(common.HexToAddress(c.EthFeedAddress)) - require.NoError(t, err, "Loading ETH-Link feed Contract shouldn't fail") + require.NoError(k.t, err, "Loading ETH-Link feed Contract shouldn't fail") } else { k.ethFeed, err = k.contractDeployer.DeployMockETHLINKFeed(big.NewInt(2e18)) - require.NoError(t, err, "Deploying mock ETH-Link feed shouldn't fail") + require.NoError(k.t, err, "Deploying mock ETH-Link feed shouldn't fail") err = k.chainClient.WaitForEvents() - require.NoError(t, err, "Failed waiting for ETH-Link feed Contract deployment") + require.NoError(k.t, err, "Failed waiting for ETH-Link feed Contract deployment") } if common.IsHexAddress(c.GasFeedAddress) { k.gasFeed, err = k.contractDeployer.LoadGasFeed(common.HexToAddress(c.GasFeedAddress)) - require.NoError(t, err, "Loading Gas feed Contract shouldn't fail") + require.NoError(k.t, err, "Loading Gas feed Contract shouldn't fail") } else { k.gasFeed, err = k.contractDeployer.DeployMockGasFeed(big.NewInt(2e11)) - require.NoError(t, err, "Deploying mock gas feed shouldn't fail") + require.NoError(k.t, err, "Deploying mock gas feed shouldn't fail") err = k.chainClient.WaitForEvents() - require.NoError(t, err, "Failed waiting for mock gas feed Contract deployment") + require.NoError(k.t, err, "Failed waiting for mock gas feed Contract deployment") } err = k.chainClient.WaitForEvents() - require.NoError(t, err, "Failed waiting for mock feeds to deploy") + require.NoError(k.t, err, "Failed waiting for mock feeds to deploy") for index := range inputs.RegistryVersions { - l.Info().Int("Index", index).Msg("Starting Test Setup") + k.log.Info().Int("Index", index).Msg("Starting Test Setup") - k.DeployBenchmarkKeeperContracts( - t, - index, - ) + k.DeployBenchmarkKeeperContracts(index) } var keysToFund = inputs.RegistryVersions @@ -190,19 +196,18 @@ func (k *KeeperBenchmarkTest) Setup(t *testing.T, env *environment.Environment) nodesToFund = k.chainlinkNodes[1:] } err = actions.FundChainlinkNodesAddress(nodesToFund, k.chainClient, k.Inputs.ChainlinkNodeFunding, index) - require.NoError(t, err, "Funding Chainlink nodes shouldn't fail") + require.NoError(k.t, err, "Funding Chainlink nodes shouldn't fail") } - l.Info().Str("Setup Time", time.Since(startTime).String()).Msg("Finished Keeper Benchmark Test Setup") + k.log.Info().Str("Setup Time", time.Since(startTime).String()).Msg("Finished Keeper Benchmark Test Setup") err = k.SendSlackNotification(nil) if err != nil { - l.Warn().Msg("Sending test start slack notification failed") + k.log.Warn().Msg("Sending test start slack notification failed") } } // Run runs the keeper benchmark test -func (k *KeeperBenchmarkTest) Run(t *testing.T) { - l := logging.GetTestLogger(t) +func (k *KeeperBenchmarkTest) Run() { u := k.Inputs.Upkeeps k.TestReporter.Summary.Load.TotalCheckGasPerBlock = int64(u.NumberOfUpkeeps) * u.CheckGasToBurn k.TestReporter.Summary.Load.TotalPerformGasPerBlock = int64((float64(u.NumberOfUpkeeps) / @@ -223,6 +228,9 @@ func (k *KeeperBenchmarkTest) Run(t *testing.T) { "NumberOfRegistries": len(k.keeperRegistries), } inputs := k.Inputs + startingBlock, err := k.chainClient.LatestBlockNumber(context.Background()) + require.NoError(k.t, err, "Error getting latest block number") + k.startingBlock = big.NewInt(0).SetUint64(startingBlock) startTime := time.Now() nodesWithoutBootstrap := k.chainlinkNodes[1:] @@ -234,22 +242,22 @@ func (k *KeeperBenchmarkTest) Run(t *testing.T) { txKeyId = 0 } ocrConfig, err := actions.BuildAutoOCR2ConfigVarsWithKeyIndex( - t, nodesWithoutBootstrap, *inputs.KeeperRegistrySettings, k.keeperRegistrars[rIndex].Address(), k.Inputs.DeltaStage, txKeyId, + k.t, nodesWithoutBootstrap, *inputs.KeeperRegistrySettings, k.keeperRegistrars[rIndex].Address(), k.Inputs.DeltaStage, txKeyId, ) - require.NoError(t, err, "Building OCR config shouldn't fail") + require.NoError(k.t, err, "Building OCR config shouldn't fail") // Send keeper jobs to registry and chainlink nodes if inputs.RegistryVersions[rIndex] == ethereum.RegistryVersion_2_0 || inputs.RegistryVersions[rIndex] == ethereum.RegistryVersion_2_1 { - actions.CreateOCRKeeperJobs(t, k.chainlinkNodes, k.keeperRegistries[rIndex].Address(), k.chainClient.GetChainID().Int64(), txKeyId, inputs.RegistryVersions[rIndex]) + actions.CreateOCRKeeperJobs(k.t, k.chainlinkNodes, k.keeperRegistries[rIndex].Address(), k.chainClient.GetChainID().Int64(), txKeyId, inputs.RegistryVersions[rIndex]) err = k.keeperRegistries[rIndex].SetConfig(*inputs.KeeperRegistrySettings, ocrConfig) - require.NoError(t, err, "Registry config should be be set successfully") + require.NoError(k.t, err, "Registry config should be be set successfully") // Give time for OCR nodes to bootstrap time.Sleep(1 * time.Minute) } else { - actions.CreateKeeperJobsWithKeyIndex(t, k.chainlinkNodes, k.keeperRegistries[rIndex], txKeyId, ocrConfig, k.chainClient.GetChainID().String()) + actions.CreateKeeperJobsWithKeyIndex(k.t, k.chainlinkNodes, k.keeperRegistries[rIndex], txKeyId, ocrConfig, k.chainClient.GetChainID().String()) } err = k.chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for registry setConfig") + require.NoError(k.t, err, "Error waiting for registry setConfig") } for rIndex := range k.keeperRegistries { @@ -264,7 +272,7 @@ func (k *KeeperBenchmarkTest) Run(t *testing.T) { &k.TestReporter, int64(index), inputs.Upkeeps.FirstEligibleBuffer, - l, + k.log, ), ) } @@ -275,32 +283,83 @@ func (k *KeeperBenchmarkTest) Run(t *testing.T) { k.chainClient.DeleteHeaderEventSubscription(fmt.Sprintf("Keeper Tracker %d %d", rIndex, index)) } } - }() - logSubscriptionStop := make(chan bool) + + // Main test loop + k.observeUpkeepEvents() + err = k.chainClient.WaitForEvents() + require.NoError(k.t, err, "Error waiting for keeper subscriptions") + + // Collect logs for each registry to calculate test metrics + registryLogs := make([][]types.Log, len(k.keeperRegistries)) + for rIndex := range k.keeperRegistries { + var ( + logs []types.Log + timeout = 5 * time.Second + addr = k.keeperRegistries[rIndex].Address() + filterQuery = geth.FilterQuery{ + Addresses: []common.Address{common.HexToAddress(addr)}, + FromBlock: k.startingBlock, + } + err = fmt.Errorf("initial error") // to ensure our for loop runs at least once + ) + for err != nil { // This RPC call can possibly time out or otherwise die. Failure is not an option, keep retrying to get our stats. + ctx, cancel := context.WithTimeout(context.Background(), timeout) + logs, err = k.chainClient.FilterLogs(ctx, filterQuery) + cancel() + if err != nil { + k.log.Error().Err(err). + Interface("Filter Query", filterQuery). + Str("Timeout", timeout.String()). + Msg("Error getting logs from chain, trying again") + } else { + k.log.Info().Int("Log Count", len(logs)).Str("Registry Address", addr).Msg("Collected logs") + } + } + registryLogs[rIndex] = logs + } + + // Count reverts and stale upkeeps for rIndex := range k.keeperRegistries { - k.subscribeToUpkeepPerformedEvent(t, logSubscriptionStop, &k.TestReporter, rIndex) + contractABI := k.contractABI(rIndex) + for _, l := range registryLogs[rIndex] { + log := l + eventDetails, err := contractABI.EventByID(log.Topics[0]) + if err != nil { + k.log.Error().Err(err).Str("Log Hash", log.TxHash.Hex()).Msg("Error getting event details for log, report data inaccurate") + break + } + if eventDetails.Name == "UpkeepPerformed" { + parsedLog, err := k.keeperRegistries[rIndex].ParseUpkeepPerformedLog(&log) + if err != nil { + k.log.Error().Err(err).Str("Log Hash", log.TxHash.Hex()).Msg("Error parsing upkeep performed log, report data inaccurate") + break + } + if !parsedLog.Success { + k.TestReporter.NumRevertedUpkeeps++ + } + } else if eventDetails.Name == "StaleUpkeepReport" { + k.TestReporter.NumStaleUpkeepReports++ + } + } } - err := k.chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for keeper subscriptions") - close(logSubscriptionStop) for _, chainlinkNode := range k.chainlinkNodes { txData, err := chainlinkNode.MustReadTransactionAttempts() if err != nil { - l.Error().Err(err).Msg("Error reading transaction attempts from Chainlink Node") + k.log.Error().Err(err).Msg("Error reading transaction attempts from Chainlink Node") } k.TestReporter.AttemptedChainlinkTransactions = append(k.TestReporter.AttemptedChainlinkTransactions, txData) } k.TestReporter.Summary.Config.Chainlink, err = k.env.ResourcesSummary("app=chainlink-0") if err != nil { - l.Error().Err(err).Msg("Error getting resource summary of chainlink node") + k.log.Error().Err(err).Msg("Error getting resource summary of chainlink node") } k.TestReporter.Summary.Config.Geth, err = k.env.ResourcesSummary("app=geth") if err != nil && k.Inputs.BlockchainClient.NetworkSimulated() { - l.Error().Err(err).Msg("Error getting resource summary of geth node") + k.log.Error().Err(err).Msg("Error getting resource summary of geth node") } endTime := time.Now() @@ -309,139 +368,178 @@ func (k *KeeperBenchmarkTest) Run(t *testing.T) { for rIndex := range k.keeperRegistries { if inputs.DeleteJobsOnEnd { // Delete keeper jobs on chainlink nodes - actions.DeleteKeeperJobsWithId(t, k.chainlinkNodes, rIndex+1) + actions.DeleteKeeperJobsWithId(k.t, k.chainlinkNodes, rIndex+1) } } - l.Info().Str("Run Time", endTime.Sub(startTime).String()).Msg("Finished Keeper Benchmark Test") + k.log.Info().Str("Run Time", endTime.Sub(startTime).String()).Msg("Finished Keeper Benchmark Test") } -// subscribeToUpkeepPerformedEvent subscribes to the event log for UpkeepPerformed event and -// counts the number of times it was unsuccessful -func (k *KeeperBenchmarkTest) subscribeToUpkeepPerformedEvent( - t *testing.T, - doneChan chan bool, - metricsReporter *testreporters.KeeperBenchmarkTestReporter, - rIndex int, +// TearDownVals returns the networks that the test is running on +func (k *KeeperBenchmarkTest) TearDownVals(t *testing.T) ( + *testing.T, + string, + []*client.ChainlinkK8sClient, + reportModel.TestReporter, + blockchain.EVMClient, ) { - l := logging.GetTestLogger(t) - contractABI, err := keeper_registry_wrapper1_1.KeeperRegistryMetaData.GetAbi() - require.NoError(t, err, "Error getting ABI") - switch k.Inputs.RegistryVersions[rIndex] { - case ethereum.RegistryVersion_1_0, ethereum.RegistryVersion_1_1: - contractABI, err = keeper_registry_wrapper1_1.KeeperRegistryMetaData.GetAbi() - case ethereum.RegistryVersion_1_2: - contractABI, err = keeper_registry_wrapper1_2.KeeperRegistryMetaData.GetAbi() - case ethereum.RegistryVersion_1_3: - contractABI, err = keeper_registry_wrapper1_3.KeeperRegistryMetaData.GetAbi() - case ethereum.RegistryVersion_2_0: - contractABI, err = keeper_registry_wrapper2_0.KeeperRegistryMetaData.GetAbi() - case ethereum.RegistryVersion_2_1: - contractABI, err = iregistry21.IKeeperRegistryMasterMetaData.GetAbi() - default: - contractABI, err = keeper_registry_wrapper2_0.KeeperRegistryMetaData.GetAbi() - } + return t, k.namespace, k.chainlinkNodes, &k.TestReporter, k.chainClient +} - require.NoError(t, err, "Getting contract abi for registry shouldn't fail") - query := geth.FilterQuery{ - Addresses: []common.Address{common.HexToAddress(k.keeperRegistries[rIndex].Address())}, - } +// ********************* +// ****** Helpers ****** +// ********************* + +// observeUpkeepEvents subscribes to Upkeep events on deployed registries and logs them +// WARNING: This should only be used for observation and logging. This isn't a reliable way to build a final report +// due to how fragile subscriptions can be +func (k *KeeperBenchmarkTest) observeUpkeepEvents() { eventLogs := make(chan types.Log) - sub, err := k.chainClient.SubscribeFilterLogs(context.Background(), query, eventLogs) - require.NoError(t, err, "Subscribing to upkeep performed events log shouldn't fail") + registryAddresses := make([]common.Address, len(k.keeperRegistries)) + addressIndexMap := map[common.Address]int{} + for index, registry := range k.keeperRegistries { + registryAddresses[index] = common.HexToAddress(registry.Address()) + addressIndexMap[registryAddresses[index]] = index + } + filterQuery := geth.FilterQuery{ + Addresses: registryAddresses, + FromBlock: k.startingBlock, + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + sub, err := k.chainClient.SubscribeFilterLogs(ctx, filterQuery, eventLogs) + cancel() + require.NoError(k.t, err, "Subscribing to upkeep performed events log shouldn't fail") + + interruption := make(chan os.Signal, 1) + signal.Notify(interruption, os.Kill, os.Interrupt, syscall.SIGTERM) + go func() { - var numRevertedUpkeeps int64 - var numStaleReports int64 for { select { + case <-interruption: + k.log.Warn().Msg("Received interrupt signal, test container restarting. Dashboard view will be inaccurate.") case err := <-sub.Err(): - l.Error().Err(err).Msg("Error while subscribing to Keeper Event Logs. Resubscribing...") - sub.Unsubscribe() - - sub, err = k.chainClient.SubscribeFilterLogs(context.Background(), query, eventLogs) - require.NoError(t, err, "Error re-subscribing to event logs") + backoff := time.Second + for err != nil { // Keep retrying until we get a successful subscription + k.log.Error(). + Err(err). + Interface("Query", filterQuery). + Str("Backoff", backoff.String()). + Msg("Error while subscribing to Keeper Event Logs. Resubscribing...") + + ctx, cancel := context.WithTimeout(context.Background(), backoff) + sub, err = k.chainClient.SubscribeFilterLogs(ctx, filterQuery, eventLogs) + cancel() + if err != nil { + time.Sleep(backoff) + backoff = time.Duration(math.Min(float64(backoff)*2, float64(30*time.Second))) + } + } + log.Info().Msg("Resubscribed to Keeper Event Logs") case vLog := <-eventLogs: + rIndex, ok := addressIndexMap[vLog.Address] + if !ok { + k.log.Error().Str("Address", vLog.Address.Hex()).Msg("Received log from unknown registry") + continue + } + contractABI := k.contractABI(rIndex) eventDetails, err := contractABI.EventByID(vLog.Topics[0]) - require.NoError(t, err, "Getting event details for subscribed log shouldn't fail") + require.NoError(k.t, err, "Getting event details for subscribed log shouldn't fail") if eventDetails.Name != "UpkeepPerformed" && eventDetails.Name != "StaleUpkeepReport" { // Skip non upkeepPerformed Logs continue } + if vLog.Removed { + k.log.Warn(). + Str("Name", eventDetails.Name). + Str("Registry", k.keeperRegistries[rIndex].Address()). + Msg("Got removed log") + } if eventDetails.Name == "UpkeepPerformed" { parsedLog, err := k.keeperRegistries[rIndex].ParseUpkeepPerformedLog(&vLog) - require.NoError(t, err, "Parsing upkeep performed log shouldn't fail") + require.NoError(k.t, err, "Parsing upkeep performed log shouldn't fail") if parsedLog.Success { - l.Info(). + k.log.Info(). Str("Upkeep ID", parsedLog.Id.String()). Bool("Success", parsedLog.Success). Str("From", parsedLog.From.String()). Str("Registry", k.keeperRegistries[rIndex].Address()). Msg("Got successful Upkeep Performed log on Registry") - } else { - l.Warn(). + k.log.Warn(). Str("Upkeep ID", parsedLog.Id.String()). Bool("Success", parsedLog.Success). Str("From", parsedLog.From.String()). Str("Registry", k.keeperRegistries[rIndex].Address()). Msg("Got reverted Upkeep Performed log on Registry") - numRevertedUpkeeps++ } } else if eventDetails.Name == "StaleUpkeepReport" { parsedLog, err := k.keeperRegistries[rIndex].ParseStaleUpkeepReportLog(&vLog) - require.NoError(t, err, "Parsing stale upkeep report log shouldn't fail") - l.Warn(). + require.NoError(k.t, err, "Parsing stale upkeep report log shouldn't fail") + k.log.Warn(). Str("Upkeep ID", parsedLog.Id.String()). Str("Registry", k.keeperRegistries[rIndex].Address()). Msg("Got stale Upkeep report log on Registry") - numStaleReports++ } - - case <-doneChan: - metricsReporter.NumRevertedUpkeeps = numRevertedUpkeeps - metricsReporter.NumStaleUpkeepReports = numStaleReports - return + case <-k.chainClient.ConnectionIssue(): + k.log.Warn().Msg("RPC connection issue detected.") + case <-k.chainClient.ConnectionRestored(): + k.log.Info().Msg("RPC connection restored.") } } }() } -// TearDownVals returns the networks that the test is running on -func (k *KeeperBenchmarkTest) TearDownVals(t *testing.T) ( - *testing.T, - string, - []*client.ChainlinkK8sClient, - reportModel.TestReporter, - blockchain.EVMClient, -) { - return t, k.namespace, k.chainlinkNodes, &k.TestReporter, k.chainClient +// contractABI returns the ABI of the proper keeper registry contract +func (k *KeeperBenchmarkTest) contractABI(rIndex int) *abi.ABI { + var ( + contractABI *abi.ABI + err error + ) + switch k.Inputs.RegistryVersions[rIndex] { + case ethereum.RegistryVersion_1_0, ethereum.RegistryVersion_1_1: + contractABI, err = keeper_registry_wrapper1_1.KeeperRegistryMetaData.GetAbi() + case ethereum.RegistryVersion_1_2: + contractABI, err = keeper_registry_wrapper1_2.KeeperRegistryMetaData.GetAbi() + case ethereum.RegistryVersion_1_3: + contractABI, err = keeper_registry_wrapper1_3.KeeperRegistryMetaData.GetAbi() + case ethereum.RegistryVersion_2_0: + contractABI, err = keeper_registry_wrapper2_0.KeeperRegistryMetaData.GetAbi() + case ethereum.RegistryVersion_2_1: + contractABI, err = iregistry21.IKeeperRegistryMasterMetaData.GetAbi() + default: + contractABI, err = keeper_registry_wrapper2_0.KeeperRegistryMetaData.GetAbi() + } + require.NoError(k.t, err, "Getting contract ABI shouldn't fail") + return contractABI } // ensureValues ensures that all values needed to run the test are present -func (k *KeeperBenchmarkTest) ensureInputValues(t *testing.T) { +func (k *KeeperBenchmarkTest) ensureInputValues() { inputs := k.Inputs - require.NotNil(t, inputs.BlockchainClient, "Need a valid blockchain client to use for the test") + require.NotNil(k.t, inputs.BlockchainClient, "Need a valid blockchain client to use for the test") k.chainClient = inputs.BlockchainClient - require.GreaterOrEqual(t, inputs.Upkeeps.NumberOfUpkeeps, 1, "Expecting at least 1 keeper contracts") + require.GreaterOrEqual(k.t, inputs.Upkeeps.NumberOfUpkeeps, 1, "Expecting at least 1 keeper contracts") if inputs.Timeout == 0 { - require.Greater(t, inputs.Upkeeps.BlockRange, int64(0), "If no `timeout` is provided, a `testBlockRange` is required") + require.Greater(k.t, inputs.Upkeeps.BlockRange, int64(0), "If no `timeout` is provided, a `testBlockRange` is required") } else if inputs.Upkeeps.BlockRange <= 0 { - require.GreaterOrEqual(t, inputs.Timeout, time.Second, "If no `testBlockRange` is provided a `timeout` is required") + require.GreaterOrEqual(k.t, inputs.Timeout, time.Second, "If no `testBlockRange` is provided a `timeout` is required") } - require.NotNil(t, inputs.KeeperRegistrySettings, "You need to set KeeperRegistrySettings") - require.NotNil(t, k.Inputs.ChainlinkNodeFunding, "You need to set a funding amount for chainlink nodes") + require.NotNil(k.t, inputs.KeeperRegistrySettings, "You need to set KeeperRegistrySettings") + require.NotNil(k.t, k.Inputs.ChainlinkNodeFunding, "You need to set a funding amount for chainlink nodes") clFunds, _ := k.Inputs.ChainlinkNodeFunding.Float64() - require.GreaterOrEqual(t, clFunds, 0.0, "Expecting Chainlink node funding to be more than 0 ETH") - require.Greater(t, inputs.Upkeeps.CheckGasToBurn, int64(0), "You need to set an expected amount of gas to burn on checkUpkeep()") + require.GreaterOrEqual(k.t, clFunds, 0.0, "Expecting Chainlink node funding to be more than 0 ETH") + require.Greater(k.t, inputs.Upkeeps.CheckGasToBurn, int64(0), "You need to set an expected amount of gas to burn on checkUpkeep()") require.GreaterOrEqual( - t, int64(inputs.KeeperRegistrySettings.CheckGasLimit), inputs.Upkeeps.CheckGasToBurn, "CheckGasLimit should be >= CheckGasToBurn", + k.t, int64(inputs.KeeperRegistrySettings.CheckGasLimit), inputs.Upkeeps.CheckGasToBurn, "CheckGasLimit should be >= CheckGasToBurn", ) - require.Greater(t, inputs.Upkeeps.PerformGasToBurn, int64(0), "You need to set an expected amount of gas to burn on performUpkeep()") - require.NotNil(t, inputs.UpkeepSLA, "Expected UpkeepSLA to be set") - require.NotNil(t, inputs.Upkeeps.FirstEligibleBuffer, "You need to set FirstEligibleBuffer") - require.NotNil(t, inputs.RegistryVersions[0], "You need to set RegistryVersion") - require.NotNil(t, inputs.BlockTime, "You need to set BlockTime") + require.Greater(k.t, inputs.Upkeeps.PerformGasToBurn, int64(0), "You need to set an expected amount of gas to burn on performUpkeep()") + require.NotNil(k.t, inputs.UpkeepSLA, "Expected UpkeepSLA to be set") + require.NotNil(k.t, inputs.Upkeeps.FirstEligibleBuffer, "You need to set FirstEligibleBuffer") + require.NotNil(k.t, inputs.RegistryVersions[0], "You need to set RegistryVersion") + require.NotNil(k.t, inputs.BlockTime, "You need to set BlockTime") if k.Inputs.DeltaStage == 0 { k.Inputs.DeltaStage = k.Inputs.BlockTime * 5 @@ -473,11 +571,7 @@ func (k *KeeperBenchmarkTest) SendSlackNotification(slackClient *slack.Client) e } // DeployBenchmarkKeeperContracts deploys a set amount of keeper Benchmark contracts registered to a single registry -func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts( - t *testing.T, - index int, -) { - l := logging.GetTestLogger(t) +func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts(index int) { registryVersion := k.Inputs.RegistryVersions[index] k.Inputs.KeeperRegistrySettings.RegistryVersion = registryVersion upkeep := k.Inputs.Upkeeps @@ -488,7 +582,7 @@ func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts( // Contract deployment is different for legacy keepers and OCR automation if registryVersion <= ethereum.RegistryVersion_1_3 { // Legacy keeper - v1.X - registry = actions.DeployKeeperRegistry(t, k.contractDeployer, k.chainClient, + registry = actions.DeployKeeperRegistry(k.t, k.contractDeployer, k.chainClient, &contracts.KeeperRegistryOpts{ RegistryVersion: registryVersion, LinkAddr: k.linkToken.Address(), @@ -502,7 +596,7 @@ func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts( // Fund the registry with 1 LINK * amount of AutomationConsumerBenchmark contracts err := k.linkToken.Transfer(registry.Address(), big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(k.Inputs.Upkeeps.NumberOfUpkeeps)))) - require.NoError(t, err, "Funding keeper registry contract shouldn't fail") + require.NoError(k.t, err, "Funding keeper registry contract shouldn't fail") registrarSettings := contracts.KeeperRegistrarSettings{ AutoApproveConfigType: 2, @@ -510,29 +604,30 @@ func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts( RegistryAddr: registry.Address(), MinLinkJuels: big.NewInt(0), } - registrar = actions.DeployKeeperRegistrar(t, registryVersion, k.linkToken, registrarSettings, k.contractDeployer, k.chainClient, registry) + registrar = actions.DeployKeeperRegistrar(k.t, registryVersion, k.linkToken, registrarSettings, k.contractDeployer, k.chainClient, registry) } else { // OCR automation - v2.X registry, registrar = actions.DeployAutoOCRRegistryAndRegistrar( - t, registryVersion, *k.Inputs.KeeperRegistrySettings, k.linkToken, k.contractDeployer, k.chainClient) + k.t, registryVersion, *k.Inputs.KeeperRegistrySettings, k.linkToken, k.contractDeployer, k.chainClient, + ) // Fund the registry with LINK err := k.linkToken.Transfer(registry.Address(), big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(k.Inputs.Upkeeps.NumberOfUpkeeps)))) - require.NoError(t, err, "Funding keeper registry contract shouldn't fail") - ocrConfig, err := actions.BuildAutoOCR2ConfigVars(t, k.chainlinkNodes[1:], *k.Inputs.KeeperRegistrySettings, registrar.Address(), k.Inputs.DeltaStage) - l.Debug().Interface("KeeperRegistrySettings", *k.Inputs.KeeperRegistrySettings).Interface("OCRConfig", ocrConfig).Msg("Config") - require.NoError(t, err, "Error building OCR config vars") + require.NoError(k.t, err, "Funding keeper registry contract shouldn't fail") + ocrConfig, err := actions.BuildAutoOCR2ConfigVars(k.t, k.chainlinkNodes[1:], *k.Inputs.KeeperRegistrySettings, registrar.Address(), k.Inputs.DeltaStage) + k.log.Debug().Interface("KeeperRegistrySettings", *k.Inputs.KeeperRegistrySettings).Interface("OCRConfig", ocrConfig).Msg("Config") + require.NoError(k.t, err, "Error building OCR config vars") err = registry.SetConfig(*k.Inputs.KeeperRegistrySettings, ocrConfig) - require.NoError(t, err, "Registry config should be be set successfully") + require.NoError(k.t, err, "Registry config should be be set successfully") } - consumer := DeployKeeperConsumersBenchmark(t, k.contractDeployer, k.chainClient) + consumer := k.DeployKeeperConsumersBenchmark() var upkeepAddresses []string checkData := make([][]byte, 0) uint256Ty, err := abi.NewType("uint256", "uint256", nil) - require.NoError(t, err) + require.NoError(k.t, err) var data []byte checkDataAbi := abi.Arguments{ { @@ -560,8 +655,8 @@ func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts( data, err = checkDataAbi.Pack( big.NewInt(int64(i)), big.NewInt(upkeep.BlockInterval), big.NewInt(upkeep.BlockRange), big.NewInt(upkeep.CheckGasToBurn), big.NewInt(upkeep.PerformGasToBurn), big.NewInt(upkeep.FirstEligibleBuffer)) - require.NoError(t, err) - l.Debug().Str("checkData: ", hexutil.Encode(data)).Int("id", i).Msg("checkData computed") + require.NoError(k.t, err) + k.log.Debug().Str("checkData: ", hexutil.Encode(data)).Int("id", i).Msg("checkData computed") checkData = append(checkData, data) } linkFunds := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(upkeep.BlockRange/upkeep.BlockInterval)) @@ -575,7 +670,7 @@ func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts( linkFunds = big.NewInt(0).Add(linkFunds, minLinkBalance) - upkeepIds := actions.RegisterUpkeepContractsWithCheckData(t, k.linkToken, linkFunds, k.chainClient, uint32(upkeep.UpkeepGasLimit), registry, registrar, upkeep.NumberOfUpkeeps, upkeepAddresses, checkData, false) + upkeepIds := actions.RegisterUpkeepContractsWithCheckData(k.t, k.linkToken, linkFunds, k.chainClient, uint32(upkeep.UpkeepGasLimit), registry, registrar, upkeep.NumberOfUpkeeps, upkeepAddresses, checkData, false) k.keeperRegistries[index] = registry k.keeperRegistrars[index] = registrar @@ -583,27 +678,21 @@ func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts( k.keeperConsumerContracts[index] = consumer } -func DeployKeeperConsumersBenchmark( - t *testing.T, - contractDeployer contracts.ContractDeployer, - client blockchain.EVMClient, -) contracts.AutomationConsumerBenchmark { - l := logging.GetTestLogger(t) - +func (k *KeeperBenchmarkTest) DeployKeeperConsumersBenchmark() contracts.AutomationConsumerBenchmark { // Deploy consumer - keeperConsumerInstance, err := contractDeployer.DeployKeeperConsumerBenchmark() + keeperConsumerInstance, err := k.contractDeployer.DeployKeeperConsumerBenchmark() if err != nil { - l.Error().Err(err).Msg("Deploying AutomationConsumerBenchmark instance %d shouldn't fail") - keeperConsumerInstance, err = contractDeployer.DeployKeeperConsumerBenchmark() - require.NoError(t, err, "Error deploying AutomationConsumerBenchmark") + k.log.Error().Err(err).Msg("Deploying AutomationConsumerBenchmark instance %d shouldn't fail") + keeperConsumerInstance, err = k.contractDeployer.DeployKeeperConsumerBenchmark() + require.NoError(k.t, err, "Error deploying AutomationConsumerBenchmark") } - l.Debug(). + k.log.Debug(). Str("Contract Address", keeperConsumerInstance.Address()). Msg("Deployed Keeper Benchmark Contract") - err = client.WaitForEvents() - require.NoError(t, err, "Failed waiting for to deploy all keeper consumer contracts") - l.Info().Msg("Successfully deployed all Keeper Consumer Contracts") + err = k.chainClient.WaitForEvents() + require.NoError(k.t, err, "Failed waiting for to deploy all keeper consumer contracts") + k.log.Info().Msg("Successfully deployed all Keeper Consumer Contracts") return keeperConsumerInstance } diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go index 7781e6c114f..0eae4b52b63 100644 --- a/integration-tests/testsetups/ocr.go +++ b/integration-tests/testsetups/ocr.go @@ -4,6 +4,7 @@ package testsetups import ( "context" "fmt" + "math" "math/big" "math/rand" "os" @@ -31,11 +32,10 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" - "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" @@ -43,7 +43,10 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/testreporters" ) -const saveFileLocation = "/persistence/ocr-soak-test-state.toml" +const ( + saveFileLocation = "/persistence/ocr-soak-test-state.toml" + interruptedExitCode = 3 +) // OCRSoakTest defines a typical OCR soak test type OCRSoakTest struct { @@ -130,9 +133,10 @@ func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string) { } nsPre = fmt.Sprintf("%s%s", nsPre, strings.ReplaceAll(strings.ToLower(network.Name), " ", "-")) baseEnvironmentConfig := &environment.Config{ - TTL: time.Hour * 720, // 30 days, - NamespacePrefix: nsPre, - Test: o.t, + TTL: time.Hour * 720, // 30 days, + NamespacePrefix: nsPre, + Test: o.t, + PreventPodEviction: true, } cd := chainlink.New(0, map[string]any{ @@ -485,7 +489,7 @@ func (o *OCRSoakTest) testLoop(testDuration time.Duration, newValue int) { o.log.Error().Err(err).Msg("Error saving state") } o.log.Warn().Str("Time Taken", time.Since(saveStart).String()).Msg("Saved state") - os.Exit(2) // Exit with code 2 to indicate test was interrupted, not just a normal failure + os.Exit(interruptedExitCode) // Exit with interrupted code to indicate test was interrupted, not just a normal failure case <-endTest: return case <-newRoundTrigger.C: @@ -581,14 +585,20 @@ func (o *OCRSoakTest) observeOCREvents() error { Int64("Answer", answerUpdated.Current.Int64()). Msg("Answer Updated Event") case err = <-eventSub.Err(): + backoff := time.Second for err != nil { o.log.Info(). Err(err). + Str("Backoff", backoff.String()). Interface("Query", o.filterQuery). Msg("Error while subscribed to OCR Logs. Resubscribing") - ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel = context.WithTimeout(context.Background(), backoff) eventSub, err = o.chainClient.SubscribeFilterLogs(ctx, o.filterQuery, eventLogs) cancel() + if err != nil { + time.Sleep(backoff) + backoff = time.Duration(math.Min(float64(backoff)*2, float64(30*time.Second))) + } } } } diff --git a/testdata/scripts/keys/eth/help.txtar b/testdata/scripts/keys/eth/help.txtar index 0484445580e..76db7cd5ae3 100644 --- a/testdata/scripts/keys/eth/help.txtar +++ b/testdata/scripts/keys/eth/help.txtar @@ -10,7 +10,7 @@ USAGE: COMMANDS: create Create a key in the node's keystore alongside the existing key; to create an original key, just run the node - list List available Ethereum accounts with their ETH & LINK balances, nonces, and other metadata + list List available Ethereum accounts with their ETH & LINK balances and other metadata delete Delete the ETH key by address (irreversible!) import Import an ETH key from a JSON file export Exports an ETH key to a JSON file