From d356f62e7ccf35fe563e3e03df8998d1d4935271 Mon Sep 17 00:00:00 2001 From: Ilja Pavlovs <5300706+iljapavlovs@users.noreply.github.com> Date: Thu, 29 Aug 2024 14:42:41 +0300 Subject: [PATCH] DEVSVCS-138: adding billing test and GHA workflow running smoke tests (#14265) * DEVSVCS-138: adding billing test and GHA workflow running smoke tests * DEVSVCS-138: minor fixes * DEVSVCS-138: adding sub_billing_tolerance_wei --- .github/workflows/live-vrf-tests.yml | 193 -------------- .../on-demand-vrfv2plus-smoke-tests.yml | 115 ++++++++ integration-tests/actions/actions.go | 9 + .../actions/vrf/vrfv2plus/contract_steps.go | 4 +- .../actions/vrf/vrfv2plus/logging_helpers.go | 17 ++ .../contracts/contract_vrf_models.go | 1 + .../contracts/ethereum_vrf_contracts.go | 21 ++ .../contracts/ethereum_vrfv2plus_contracts.go | 12 + integration-tests/smoke/vrfv2_test.go | 6 +- integration-tests/smoke/vrfv2plus_test.go | 252 ++++++++++-------- .../testconfig/vrfv2plus/config.go | 6 +- .../testconfig/vrfv2plus/vrfv2plus.toml | 1 + 12 files changed, 332 insertions(+), 305 deletions(-) delete mode 100644 .github/workflows/live-vrf-tests.yml create mode 100644 .github/workflows/on-demand-vrfv2plus-smoke-tests.yml diff --git a/.github/workflows/live-vrf-tests.yml b/.github/workflows/live-vrf-tests.yml deleted file mode 100644 index 28f5867954b..00000000000 --- a/.github/workflows/live-vrf-tests.yml +++ /dev/null @@ -1,193 +0,0 @@ -# Funding address: 0xC1107e57082945E28d3202A81B1520DEA3AE6AEC -name: Generic Live Smoke Tests -on: - workflow_dispatch: - inputs: - networks: - description: "Comma-separated list of networks to run on" - required: true - default: "SEPOLIA,OPTIMISM_SEPOLIA,ARBITRUM_SEPOLIA" - test_list: - description: "Comma-separated list of tests to run" - required: true - default: "TestVRFBasic,TestVRFv2Basic,TestVRFv2Plus" - -env: - CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink - INTERNAL_DOCKER_REPO: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com - MOD_CACHE_VERSION: 2 - CHAINLINK_NODE_FUNDING: .5 - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - LOKI_TENANT_ID: ${{ vars.LOKI_TENANT_ID }} - LOKI_URL: ${{ secrets.LOKI_URL }} - LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} - LOGSTREAM_LOG_TARGETS: loki - GRAFANA_URL: ${{ vars.GRAFANA_URL }} - RUN_ID: ${{ github.run_id }} - - CHAINLINK_COMMIT_SHA: ${{ github.sha }} - CHAINLINK_ENV_USER: ${{ github.actor }} - TEST_LOG_LEVEL: debug - -jobs: - - # Build Test Dependencies - - build-chainlink: - environment: integration - permissions: - id-token: write - contents: read - name: Build Chainlink Image - runs-on: ubuntu-latest - steps: - - name: Collect Metrics - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1 - with: - id: live-vrf-build-chainlink - org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} - this-job-name: Build Chainlink Image - continue-on-error: true - - name: Checkout the repo - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - with: - ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - - name: Build Chainlink Image - uses: ./.github/actions/build-chainlink-image - with: - tag_suffix: "" - dockerfile: core/chainlink.Dockerfile - git_commit_sha: ${{ github.sha }} - GRAFANA_CLOUD_BASIC_AUTH: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - GRAFANA_CLOUD_HOST: ${{ secrets.GRAFANA_CLOUD_HOST }} - AWS_REGION: ${{ secrets.QA_AWS_REGION }} - AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - - build-tests: - environment: integration - permissions: - id-token: write - contents: read - name: Build Tests Binary - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.build-matrix.outputs.matrix }} - steps: - - name: Collect Metrics - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1 - with: - id: live-vrf-build-test-image - org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} - this-job-name: Build Tests Binary - continue-on-error: true - - name: Checkout the repo - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - with: - ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - - name: Build Network Matrix - id: build-matrix - run: | - NETWORKS="[\"${{ github.event.inputs.networks }}\"]" - NETWORKS="${NETWORKS//,/\",\"}" - echo "matrix=${NETWORKS}" >> "$GITHUB_OUTPUT" - - name: Build Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-tests@75a9005952a9e905649cfb5a6971fd9429436acd # v2.3.25 - with: - test_download_vendor_packages_command: cd ./integration-tests && go mod download - token: ${{ secrets.GITHUB_TOKEN }} - go_mod_path: ./integration-tests/go.mod - go_tags: embed - cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} - cache_restore_only: "true" - binary_name: tests - - - # End Build Test Dependencies - - live-smoke-tests: - environment: integration - permissions: - checks: write - pull-requests: write - id-token: write - contents: read - needs: [build-chainlink, build-tests] - strategy: - fail-fast: false - matrix: - network: ${{fromJson(needs.build-tests.outputs.matrix)}} - name: Smoke Tests on ${{ matrix.network }} - runs-on: ubuntu-latest - steps: - - name: Build Secrets Names - id: build-secrets-names - run: | - echo "HTTP_URLS_SECRET_NAME=QA_${{ matrix.network }}_HTTP_URLS" >> $GITHUB_ENV - echo "URLS_SECRET_NAME=QA_${{ matrix.network }}_URLS" >> $GITHUB_ENV - - name: Split Test Names - id: split_list - run: | - IFS=',' read -ra ADDR <<< "${{ inputs.test_list }}" - echo "test_list=${ADDR[*]}" >> $GITHUB_ENV - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - with: - fetch-depth: 0 - - name: Setup GAP for Grafana - uses: smartcontractkit/.github/actions/setup-gap@d316f66b2990ea4daa479daa3de6fc92b00f863e # setup-gap@0.3.2 - with: - # aws inputs - aws-region: ${{ secrets.AWS_REGION }} - aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} - api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} - # other inputs - duplicate-authorization-header: "true" - - name: Prepare Base64 TOML override - uses: ./.github/actions/setup-create-base64-config-live-testnets - with: - runId: ${{ github.run_id }} - testLogCollect: ${{ vars.TEST_LOG_COLLECT }} - chainlinkImage: ${{ env.CHAINLINK_IMAGE }} - chainlinkVersion: ${{ github.sha }} - lokiEndpoint: ${{ secrets.LOKI_URL }} - lokiTenantId: ${{ vars.LOKI_TENANT_ID }} - lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} - logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: "http://localhost:8080/primary" - grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" - grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} - network: ${{ matrix.network }} - httpEndpoints: ${{ secrets[env.HTTP_URLS_SECRET_NAME] }} - wsEndpoints: ${{ secrets[env.URLS_SECRET_NAME] }} - fundingKeys: ${{ secrets.QA_EVM_KEYS }} - - name: Download Tests Binary - uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 - with: - name: tests - - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@75a9005952a9e905649cfb5a6971fd9429436acd # v2.3.25 - with: - test_command_to_run: ./tests -test.v -test.timeout 4h -test.count=1 -test.parallel=1 -test.run ${{ env.test_list }} - binary_name: tests - cl_repo: ${{ env.CHAINLINK_IMAGE }} - cl_image_tag: ${{ github.sha }} - aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} - dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} - artifacts_location: ./logs - token: ${{ secrets.GITHUB_TOKEN }} - cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} - cache_restore_only: "true" - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - - name: Print failed test summary - if: always() - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@75a9005952a9e905649cfb5a6971fd9429436acd # v2.3.25 - with: - test_directories: "./" diff --git a/.github/workflows/on-demand-vrfv2plus-smoke-tests.yml b/.github/workflows/on-demand-vrfv2plus-smoke-tests.yml new file mode 100644 index 00000000000..5977f92622c --- /dev/null +++ b/.github/workflows/on-demand-vrfv2plus-smoke-tests.yml @@ -0,0 +1,115 @@ +name: On Demand VRFV2 Plus Smoke Tests +on: + workflow_dispatch: + inputs: + base64Config: + description: base64-ed config + required: true + type: string + test_suite: + description: "Test Suite to run" + required: true + type: choice + options: + - "All Tests" + - "Selected Tests" + test_list_regex: + description: "Regex for 'Selected Tests' to run" + required: false + default: "(TestVRFv2Plus$/(Link_Billing|Native_Billing|Direct_Funding)|TestVRFV2PlusWithBHS|TestVRFV2PlusWithBHF)" + test_secrets_override_key: + description: 'Key to run tests with custom test secrets' + required: false + type: string + +jobs: + vrfv2plus_smoke_test: + name: VRFV2 Plus Smoke Test + environment: integration + runs-on: ubuntu22.04-8cores-32GB + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + env: + LOKI_URL: ${{ secrets.LOKI_URL }} + LOKI_TENANT_ID: ${{ secrets.LOKI_TENANT_ID }} + LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} + TEST_LOG_LEVEL: debug + REF_NAME: ${{ github.head_ref || github.ref_name }} + SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} + SLACK_CHANNEL: ${{ secrets.QA_VRF_SLACK_CHANNEL }} + GRAFANA_URL: "http://localhost:8080/primary" + GRAFANA_DASHBOARD_URL: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + WASP_LOG_LEVEL: info + steps: + - name: Collect Metrics + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1 + with: + id: on-demand-vrfv2plus-smoke-tests + org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} + basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} + this-job-name: ${{ inputs.network }} VRFV2 Plus Smoke Test + continue-on-error: true + - name: Checkout code + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + with: + fetch-depth: 0 + - name: Mask base64 config + run: | + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Merge and export base64 config + uses: ./.github/actions/setup-merge-base64-config + with: + base64Config: ${{ env.BASE64_CONFIG_OVERRIDE }} + - name: Send details to Step Summary + shell: bash + run: | + echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.CHAINLINK_IMAGE }}\`" >>$GITHUB_STEP_SUMMARY + echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY + echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY + echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY + - name: Run Tests + if: ${{ github.event.inputs.test_suite == 'Selected Tests' }} + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@2967f2287bd3f3ddbac7b476e9568993df01796e # v2.3.27 + with: + test_command_to_run: cd ./integration-tests/smoke && go test -v -count=1 -parallel=1 -timeout 2h -run "${{ inputs.test_list_regex }}" + test_download_vendor_packages_command: cd ./integration-tests && go mod download + test_secrets_override_base64: ${{ secrets[inputs.test_secrets_override_key] }} + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ env.CHAINLINK_VERSION }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + artifacts_name: vrf-test-logs + artifacts_location: ./integration-tests/smoke/vrfv2plus/logs/ + token: ${{ secrets.GITHUB_TOKEN }} + go_mod_path: ./integration-tests/go.mod + should_cleanup: false + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Run Tests + if: ${{ github.event.inputs.test_suite == 'All Tests' }} + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@2967f2287bd3f3ddbac7b476e9568993df01796e # v2.3.27 + with: + test_command_to_run: cd ./integration-tests/smoke && go test -v -count=1 -parallel=1 -timeout 3h vrfv2plus_test.go + test_download_vendor_packages_command: cd ./integration-tests && go mod download + test_secrets_override_base64: ${{ secrets[inputs.test_secrets_override_key] }} + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ env.CHAINLINK_VERSION }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + artifacts_name: vrf-test-logs + artifacts_location: ./integration-tests/smoke/vrfv2plus/logs/ + token: ${{ secrets.GITHUB_TOKEN }} + go_mod_path: ./integration-tests/go.mod + should_cleanup: false + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index 04767c842ed..b6fc8200428 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -1285,3 +1285,12 @@ func ContinuouslyGenerateTXsOnChain(sethClient *seth.Client, stopChannel chan bo } } } + +func WithinTolerance(a, b, tolerance float64) (bool, float64) { + if a == b { + return true, 0 + } + diff := math.Abs(a - b) + isWithinTolerance := diff < tolerance + return isWithinTolerance, diff +} diff --git a/integration-tests/actions/vrf/vrfv2plus/contract_steps.go b/integration-tests/actions/vrf/vrfv2plus/contract_steps.go index 6b3345edd09..f3f41a0e667 100644 --- a/integration-tests/actions/vrf/vrfv2plus/contract_steps.go +++ b/integration-tests/actions/vrf/vrfv2plus/contract_steps.go @@ -41,7 +41,7 @@ func DeployVRFV2_5Contracts( if err != nil { return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrDeployCoordinatorV2Plus, err) } - err = opStackCoordinator.SetL1FeeCalculation(configGeneral.L1FeeCalculationMode, configGeneral.L1FeeCoefficient) + err = opStackCoordinator.SetL1FeeCalculation(*configGeneral.L1FeeCalculationMode, *configGeneral.L1FeeCoefficient) if err != nil { return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrSetL1FeeCalculation, err) } @@ -437,7 +437,7 @@ func DeployVRFV2PlusDirectFundingContracts( if err != nil { return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrDeployWrapper, err) } - err = opStackWrapper.SetL1FeeCalculation(configGeneral.L1FeeCalculationMode, configGeneral.L1FeeCoefficient) + err = opStackWrapper.SetL1FeeCalculation(*configGeneral.L1FeeCalculationMode, *configGeneral.L1FeeCoefficient) if err != nil { return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrSetL1FeeCalculation, err) } diff --git a/integration-tests/actions/vrf/vrfv2plus/logging_helpers.go b/integration-tests/actions/vrf/vrfv2plus/logging_helpers.go index 1c6e2edaa0a..758200f86f4 100644 --- a/integration-tests/actions/vrf/vrfv2plus/logging_helpers.go +++ b/integration-tests/actions/vrf/vrfv2plus/logging_helpers.go @@ -4,9 +4,11 @@ import ( "fmt" "math/big" + "github.com/ethereum/go-ethereum/core/types" "github.com/rs/zerolog" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" @@ -55,3 +57,18 @@ func LogSubDetailsAfterMigration(l zerolog.Logger, newCoordinator contracts.Coor Interface("Subscription Consumers", migratedSubscription.Consumers). Msg("Subscription Data After Migration to New Coordinator") } + +func LogPaymentDetails(l zerolog.Logger, fulfillmentTxFeeWei *big.Int, fulfillmentTxReceipt *types.Receipt, actualSubPaymentWei *big.Int, expectedSubPaymentWei *big.Float, configCopy tc.TestConfig) { + l.Info(). + Str("Tx Fee in Wei", fulfillmentTxFeeWei.String()). + Str("Effective Gas Price", fulfillmentTxReceipt.EffectiveGasPrice.String()). + Uint64("Gas Used", fulfillmentTxReceipt.GasUsed). + Str("Actual Subscription Payment in Wei", actualSubPaymentWei.String()). + Str("Expected Subscription Payment in Wei", expectedSubPaymentWei.String()). + Uint8("Native Premium Percentage", *configCopy.VRFv2Plus.General.NativePremiumPercentage). + Uint8("Link Premium Percentage", *configCopy.VRFv2Plus.General.LinkPremiumPercentage). + Uint32("FulfillmentFlatFeeNativePPM", *configCopy.VRFv2Plus.General.FulfillmentFlatFeeNativePPM). + Uint32("FulfillmentFlatFeeLinkDiscountPPM", *configCopy.VRFv2Plus.General.FulfillmentFlatFeeLinkDiscountPPM). + Uint32("GasAfterPaymentCalculation", *configCopy.VRFv2Plus.General.GasAfterPaymentCalculation). + Msg("Randomness Fulfillment Payment Details") +} diff --git a/integration-tests/contracts/contract_vrf_models.go b/integration-tests/contracts/contract_vrf_models.go index db8b427b073..8d1424cbfdf 100644 --- a/integration-tests/contracts/contract_vrf_models.go +++ b/integration-tests/contracts/contract_vrf_models.go @@ -125,6 +125,7 @@ type VRFCoordinatorV2_5 interface { GetBlockHashStoreAddress(ctx context.Context) (common.Address, error) GetLinkAddress(ctx context.Context) (common.Address, error) GetLinkNativeFeed(ctx context.Context) (common.Address, error) + GetConfig(ctx context.Context) (vrf_coordinator_v2_5.SConfig, error) } type VRFCoordinatorV2PlusUpgradedVersion interface { diff --git a/integration-tests/contracts/ethereum_vrf_contracts.go b/integration-tests/contracts/ethereum_vrf_contracts.go index 3f83d8fd30f..52b178d412c 100644 --- a/integration-tests/contracts/ethereum_vrf_contracts.go +++ b/integration-tests/contracts/ethereum_vrf_contracts.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/mock_ethlink_aggregator_wrapper" "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/vrfv2plus_wrapper" @@ -353,6 +354,26 @@ func DeployVRFMockETHLINKFeed(seth *seth.Client, answer *big.Int) (VRFMockETHLIN }, err } +func LoadVRFMockETHLINKFeed(client *seth.Client, address common.Address) (VRFMockETHLINKFeed, error) { + abi, err := mock_ethlink_aggregator_wrapper.MockETHLINKAggregatorMetaData.GetAbi() + if err != nil { + return &EthereumVRFMockETHLINKFeed{}, fmt.Errorf("failed to get VRFMockETHLINKAggregator ABI: %w", err) + } + client.ContractStore.AddABI("VRFMockETHLINKAggregator", *abi) + client.ContractStore.AddBIN("VRFMockETHLINKAggregator", common.FromHex(mock_ethlink_aggregator_wrapper.MockETHLINKAggregatorMetaData.Bin)) + + instance, err := vrf_mock_ethlink_aggregator.NewVRFMockETHLINKAggregator(address, wrappers.MustNewWrappedContractBackend(nil, client)) + if err != nil { + return &EthereumVRFMockETHLINKFeed{}, fmt.Errorf("failed to instantiate VRFMockETHLINKAggregator instance: %w", err) + } + + return &EthereumVRFMockETHLINKFeed{ + address: address, + client: client, + feed: instance, + }, nil +} + func (v *EthereumBlockhashStore) Address() string { return v.address.Hex() } diff --git a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go index 2741209114b..35d22e8ef5b 100644 --- a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go @@ -435,6 +435,18 @@ func (v *EthereumVRFCoordinatorV2_5) GetLinkNativeFeed(ctx context.Context) (com return address, nil } +func (v *EthereumVRFCoordinatorV2_5) GetConfig(ctx context.Context) (vrf_coordinator_v2_5.SConfig, error) { + opts := &bind.CallOpts{ + From: v.client.MustGetRootKeyAddress(), + Context: ctx, + } + config, err := v.coordinator.SConfig(opts) + if err != nil { + return vrf_coordinator_v2_5.SConfig{}, err + } + return config, nil +} + // OwnerCancelSubscription cancels subscription by Coordinator owner // return funds to sub owner, // does not check if pending requests for a sub exist diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index a72af0a2290..8d32204dd30 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -1029,7 +1029,6 @@ func TestVRFV2NodeReorg(t *testing.T) { env *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []uint64 - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData sethClient *seth.Client ) @@ -1051,7 +1050,7 @@ func TestVRFV2NodeReorg(t *testing.T) { } else { if *vrfv2Config.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*vrfv2Config.General.UseExistingEnv { @@ -1208,7 +1207,6 @@ func TestVRFv2BatchFulfillmentEnabledDisabled(t *testing.T) { env *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []uint64 - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode sethClient *seth.Client @@ -1228,7 +1226,7 @@ func TestVRFv2BatchFulfillmentEnabledDisabled(t *testing.T) { } else { if *vrfv2Config.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*vrfv2Config.General.UseExistingEnv { diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index 76d1523f890..d8ea7cac10d 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -127,12 +127,6 @@ func TestVRFv2Plus(t *testing.T) { require.Equal(t, isNativeBilling, randomWordsFulfilledEvent.NativePayment, "RandomWordsFulfilled Event's `NativePayment` field should be false") require.True(t, randomWordsFulfilledEvent.Success, "RandomWordsFulfilled Event's `Success` field should be true") - expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - subscription, err = vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForRequestRandomness) - require.NoError(t, err, "error getting subscription information") - subBalanceAfterRequest := subscription.Balance - require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) - status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) @@ -143,6 +137,19 @@ func TestVRFv2Plus(t *testing.T) { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") } + t.Run("Verify Billing", func(t *testing.T) { + actualSubPaymentJuels := randomWordsFulfilledEvent.Payment + + expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, actualSubPaymentJuels) + subscription, err = vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForRequestRandomness) + require.NoError(t, err, "error getting subscription information") + subBalanceAfterRequest := subscription.Balance + require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) + + //todo - need to refactor the test so that when running on live testnet and deploying a new environment, + // we would load real Link Token and Link/ETH feed addresses from the config + }) + }) t.Run("Native Billing", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) @@ -183,12 +190,6 @@ func TestVRFv2Plus(t *testing.T) { require.False(t, randomWordsFulfilledEvent.OnlyPremium) require.Equal(t, isNativeBilling, randomWordsFulfilledEvent.NativePayment) require.True(t, randomWordsFulfilledEvent.Success) - expectedSubBalanceWei := new(big.Int).Sub(subNativeTokenBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - subscription, err = vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) - require.NoError(t, err) - subBalanceAfterRequest := subscription.NativeBalance - require.Equal(t, expectedSubBalanceWei, subBalanceAfterRequest) - status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) @@ -199,92 +200,51 @@ func TestVRFv2Plus(t *testing.T) { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") } - }) - t.Run("VRF Node waits block confirmation number specified by the consumer before sending fulfilment on-chain", func(t *testing.T) { - configCopy := config.MustCopy().(tc.TestConfig) - testConfig := configCopy.VRFv2Plus.General - var isNativeBilling = true - - consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( - testcontext.Get(t), - sethClient, - vrfContracts.CoordinatorV2Plus, - configCopy, - vrfContracts.LinkToken, - 1, - 1, - l, - ) - require.NoError(t, err, "error setting up new consumers and subs") - subID := subIDs[0] - subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) - require.NoError(t, err, "error getting subscription information") - vrfcommon.LogSubDetails(l, subscription, subID.String(), vrfContracts.CoordinatorV2Plus) - subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) - - expectedBlockNumberWait := uint16(10) - testConfig.MinimumConfirmations = ptr.Ptr[uint16](expectedBlockNumberWait) - randomWordsRequestedEvent, randomWordsFulfilledEvent, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( - consumers[0], - vrfContracts.CoordinatorV2Plus, - vrfKey, - subID, - isNativeBilling, - testConfig, - l, - 0, - ) - require.NoError(t, err, "error requesting randomness and waiting for fulfilment") - - // check that VRF node waited at least the number of blocks specified by the consumer in the rand request min confs field - blockNumberWait := randomWordsRequestedEvent.Raw.BlockNumber - randomWordsFulfilledEvent.Raw.BlockNumber - require.GreaterOrEqual(t, blockNumberWait, uint64(expectedBlockNumberWait)) - - status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) - require.NoError(t, err, "error getting rand request status") - require.True(t, status.Fulfilled) - l.Info().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") - }) - t.Run("CL Node VRF Job Runs", func(t *testing.T) { - configCopy := config.MustCopy().(tc.TestConfig) - var isNativeBilling = false - - consumers, subIDsForRequestRandomness, err := vrfv2plus.SetupNewConsumersAndSubs( - testcontext.Get(t), - sethClient, - vrfContracts.CoordinatorV2Plus, - configCopy, - vrfContracts.LinkToken, - 1, - 1, - l, - ) - require.NoError(t, err, "error setting up new consumers and subs") - subIDForRequestRandomness := subIDsForRequestRandomness[0] - subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForRequestRandomness) - require.NoError(t, err, "error getting subscription information") - vrfcommon.LogSubDetails(l, subscription, subIDForRequestRandomness.String(), vrfContracts.CoordinatorV2Plus) - subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForRequestRandomness...) - - jobRunsBeforeTest, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodeTypeToNodeMap[vrfcommon.VRF].Job.Data.ID) - require.NoError(t, err, "error reading job runs") - - // test and assert - _, _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( - consumers[0], - vrfContracts.CoordinatorV2Plus, - vrfKey, - subIDForRequestRandomness, - isNativeBilling, - configCopy.VRFv2Plus.General, - l, - 0, - ) - require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + t.Run("Verify Billing", func(t *testing.T) { + actualSubPaymentWei := randomWordsFulfilledEvent.Payment + expectedSubBalanceWei := new(big.Int).Sub(subNativeTokenBalanceBeforeRequest, actualSubPaymentWei) + subscription, err = vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + require.NoError(t, err) + subBalanceAfterRequest := subscription.NativeBalance + require.Equal(t, expectedSubBalanceWei, subBalanceAfterRequest) - jobRuns, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodeTypeToNodeMap[vrfcommon.VRF].Job.Data.ID) - require.NoError(t, err, "error reading job runs") - require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) + // verify that the actual sub payment is within the expected range - this cannot be checked on SIMULATED env + coordinatorConfig, err := vrfContracts.CoordinatorV2Plus.GetConfig(testcontext.Get(t)) + require.NoError(t, err, "error getting coordinator config") + //check that Coordinator config is correct + require.Equal(t, *configCopy.VRFv2Plus.General.FulfillmentFlatFeeNativePPM, coordinatorConfig.FulfillmentFlatFeeNativePPM) + require.Equal(t, *configCopy.VRFv2Plus.General.NativePremiumPercentage, coordinatorConfig.NativePremiumPercentage) + require.Equal(t, *configCopy.VRFv2Plus.General.GasAfterPaymentCalculation, coordinatorConfig.GasAfterPaymentCalculation) + // check that the actual sub payment is within the expected range and is according to the coordinator config's billing settings + fulfillmentTxHash := randomWordsFulfilledEvent.Raw.TxHash + fulfillmentTxReceipt, err := sethClient.Client.TransactionReceipt(testcontext.Get(t), fulfillmentTxHash) + require.NoError(t, err, "error getting fulfilment tx receipt") + + txGasUsed := new(big.Int).SetUint64(fulfillmentTxReceipt.GasUsed) + // we don't have that information for older Geth versions + if fulfillmentTxReceipt.EffectiveGasPrice == nil { + fulfillmentTxReceipt.EffectiveGasPrice = new(big.Int).SetUint64(0) + } + fulfillmentTxFeeWei := new(big.Int).Mul(txGasUsed, fulfillmentTxReceipt.EffectiveGasPrice) + + premiumFeeInDecimal := new(big.Float).Quo(big.NewFloat(float64(*configCopy.VRFv2Plus.General.CoordinatorNativePremiumPercentage)), big.NewFloat(100)) + premiumFeeRatio := new(big.Float).Add(premiumFeeInDecimal, big.NewFloat(1)) + // since - tx fee * (premium fee in decimal + 1) = expected sub payment + fulfillmentTxFeeWeiFloat64, _ := fulfillmentTxFeeWei.Float64() + expectedSubPaymentWeiWithoutFlatFee := new(big.Float).Mul(big.NewFloat(fulfillmentTxFeeWeiFloat64), premiumFeeRatio) + flatFee := new(big.Float).Mul(big.NewFloat(float64(*configCopy.VRFv2Plus.General.FulfillmentFlatFeeNativePPM)), big.NewFloat(1e12)) + expectedSubPaymentWeiWitFlatFee := new(big.Float).Add(expectedSubPaymentWeiWithoutFlatFee, flatFee) + vrfv2plus.LogPaymentDetails(l, fulfillmentTxFeeWei, fulfillmentTxReceipt, actualSubPaymentWei, expectedSubPaymentWeiWitFlatFee, configCopy) + actualSubPaymentWeiFloat, _ := actualSubPaymentWei.Float64() + expectedSubPaymentWeiFloat, _ := expectedSubPaymentWeiWitFlatFee.Float64() + + //verify that the actual sub payment is more than TX fee + require.Equal(t, 1, actualSubPaymentWei.Cmp(fulfillmentTxFeeWei), "the actual sub payment has to be more than the TX fee") + + tolerance := *testConfig.SubBillingTolerance + isWithinTolerance, diff := actions.WithinTolerance(actualSubPaymentWeiFloat, expectedSubPaymentWeiFloat, tolerance) + require.True(t, isWithinTolerance, fmt.Sprintf("Expected the actual sub payment to be within %f tolerance of the expected sub payment. Diff: %f", tolerance, diff)) + }) }) t.Run("Direct Funding", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) @@ -399,6 +359,92 @@ func TestVRFv2Plus(t *testing.T) { } }) }) + t.Run("VRF Node waits block confirmation number specified by the consumer before sending fulfilment on-chain", func(t *testing.T) { + configCopy := config.MustCopy().(tc.TestConfig) + testConfig := configCopy.VRFv2Plus.General + var isNativeBilling = true + + consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), + sethClient, + vrfContracts.CoordinatorV2Plus, + configCopy, + vrfContracts.LinkToken, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up new consumers and subs") + subID := subIDs[0] + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + require.NoError(t, err, "error getting subscription information") + vrfcommon.LogSubDetails(l, subscription, subID.String(), vrfContracts.CoordinatorV2Plus) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) + + expectedBlockNumberWait := uint16(10) + testConfig.MinimumConfirmations = ptr.Ptr[uint16](expectedBlockNumberWait) + randomWordsRequestedEvent, randomWordsFulfilledEvent, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( + consumers[0], + vrfContracts.CoordinatorV2Plus, + vrfKey, + subID, + isNativeBilling, + testConfig, + l, + 0, + ) + require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + + // check that VRF node waited at least the number of blocks specified by the consumer in the rand request min confs field + blockNumberWait := randomWordsRequestedEvent.Raw.BlockNumber - randomWordsFulfilledEvent.Raw.BlockNumber + require.GreaterOrEqual(t, blockNumberWait, uint64(expectedBlockNumberWait)) + + status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) + require.NoError(t, err, "error getting rand request status") + require.True(t, status.Fulfilled) + l.Info().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") + }) + t.Run("CL Node VRF Job Runs", func(t *testing.T) { + configCopy := config.MustCopy().(tc.TestConfig) + var isNativeBilling = false + + consumers, subIDsForRequestRandomness, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), + sethClient, + vrfContracts.CoordinatorV2Plus, + configCopy, + vrfContracts.LinkToken, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up new consumers and subs") + subIDForRequestRandomness := subIDsForRequestRandomness[0] + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForRequestRandomness) + require.NoError(t, err, "error getting subscription information") + vrfcommon.LogSubDetails(l, subscription, subIDForRequestRandomness.String(), vrfContracts.CoordinatorV2Plus) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForRequestRandomness...) + + jobRunsBeforeTest, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodeTypeToNodeMap[vrfcommon.VRF].Job.Data.ID) + require.NoError(t, err, "error reading job runs") + + // test and assert + _, _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( + consumers[0], + vrfContracts.CoordinatorV2Plus, + vrfKey, + subIDForRequestRandomness, + isNativeBilling, + configCopy.VRFv2Plus.General, + l, + 0, + ) + require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + + jobRuns, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodeTypeToNodeMap[vrfcommon.VRF].Job.Data.ID) + require.NoError(t, err, "error reading job runs") + require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) + }) t.Run("Canceling Sub And Returning Funds", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) @@ -748,8 +794,8 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { config, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.VRFv2Plus) require.NoError(t, err, "Error getting config") vrfv2PlusConfig := config.VRFv2Plus - chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID - + network := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0] + chainID := network.ChainID cleanupFn := func() { if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). @@ -1698,7 +1744,7 @@ func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { env, vrfContracts, vrfKey, nodeTypeToNodeMap, sethClient, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, vrfEnvConfig, newEnvConfig, l) require.NoError(t, err, "error setting up VRFV2Plus universe") - t.Run("Timed out request fulfilled after node restart with replay", func(t *testing.T) { + t.Run("Replaying Requests", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) var isNativeBilling = false @@ -1916,7 +1962,6 @@ func TestVRFv2PlusNodeReorg(t *testing.T) { env *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []*big.Int - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData sethClient *seth.Client ) @@ -1938,7 +1983,7 @@ func TestVRFv2PlusNodeReorg(t *testing.T) { } else { if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*vrfv2PlusConfig.General.UseExistingEnv { @@ -2095,7 +2140,6 @@ func TestVRFv2PlusBatchFulfillmentEnabledDisabled(t *testing.T) { env *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []*big.Int - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode sethClient *seth.Client @@ -2115,7 +2159,7 @@ func TestVRFv2PlusBatchFulfillmentEnabledDisabled(t *testing.T) { } else { if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*vrfv2PlusConfig.General.UseExistingEnv { diff --git a/integration-tests/testconfig/vrfv2plus/config.go b/integration-tests/testconfig/vrfv2plus/config.go index 52d518e5395..4ae5ee5c357 100644 --- a/integration-tests/testconfig/vrfv2plus/config.go +++ b/integration-tests/testconfig/vrfv2plus/config.go @@ -57,10 +57,12 @@ type General struct { CoordinatorLinkPremiumPercentage *uint8 `toml:"coordinator_link_premium_percentage"` //OP Stack chains settings - L1FeeCalculationMode uint8 `toml:"l1_fee_calculation_mode"` - L1FeeCoefficient uint8 `toml:"l1_fee_coefficient"` + L1FeeCalculationMode *uint8 `toml:"l1_fee_calculation_mode"` + L1FeeCoefficient *uint8 `toml:"l1_fee_coefficient"` UseTestCoordinator *bool `toml:"use_test_coordinator"` + + SubBillingTolerance *float64 `toml:"sub_billing_tolerance_wei"` } func (c *General) Validate() error { diff --git a/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml index 1281ae7f2dd..1b43d73e174 100644 --- a/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml +++ b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml @@ -189,6 +189,7 @@ chainlink_node_funding = 0.7 [VRFv2Plus] [VRFv2Plus.General] +sub_billing_tolerance_wei = 1e15 use_test_coordinator = false cancel_subs_after_test_run = true use_existing_env = false