From 05d7b5a2c4afe49250818d48d4733cdcf835583c Mon Sep 17 00:00:00 2001 From: Ilja Pavlovs Date: Thu, 5 Oct 2023 19:51:24 +0300 Subject: [PATCH] =?UTF-8?q?VRF-599:=20add=20load=20tests;=20test=20refacto?= =?UTF-8?q?ring=20to=20have=20configurable=20setup;=E2=80=A6=20(#10834)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * VRF-599: add load tests; test refactoring to have configurable setup; adding GH Action workflow * VRF-599: PR comments * VRF-599: PR comments --- .../on-demand-vrfv2plus-load-test.yml | 116 +++++++++++++ .../actions/vrfv2_actions/vrfv2_steps.go | 1 + .../vrfv2plus/vrfv2plus_config/config.go | 35 ++++ .../vrfv2plus_constants/constants.go | 40 ----- .../actions/vrfv2plus/vrfv2plus_steps.go | 95 ++++++----- integration-tests/load/vrfv2/cmd/dashboard.go | 3 +- integration-tests/load/vrfv2plus/README.md | 22 +++ .../load/vrfv2plus/cmd/dashboard.go | 99 +++++++++++ integration-tests/load/vrfv2plus/config.go | 74 ++++++++ integration-tests/load/vrfv2plus/config.toml | 27 +++ integration-tests/load/vrfv2plus/gun.go | 56 ++++++ .../load/vrfv2plus/onchain_monitoring.go | 47 +++++ .../load/vrfv2plus/vrfv2plus_test.go | 161 ++++++++++++++++++ integration-tests/smoke/vrfv2plus_test.go | 57 ++++--- 14 files changed, 732 insertions(+), 101 deletions(-) create mode 100644 .github/workflows/on-demand-vrfv2plus-load-test.yml create mode 100644 integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go delete mode 100644 integration-tests/actions/vrfv2plus/vrfv2plus_constants/constants.go create mode 100644 integration-tests/load/vrfv2plus/README.md create mode 100644 integration-tests/load/vrfv2plus/cmd/dashboard.go create mode 100644 integration-tests/load/vrfv2plus/config.go create mode 100644 integration-tests/load/vrfv2plus/config.toml create mode 100644 integration-tests/load/vrfv2plus/gun.go create mode 100644 integration-tests/load/vrfv2plus/onchain_monitoring.go create mode 100644 integration-tests/load/vrfv2plus/vrfv2plus_test.go diff --git a/.github/workflows/on-demand-vrfv2plus-load-test.yml b/.github/workflows/on-demand-vrfv2plus-load-test.yml new file mode 100644 index 00000000000..dcfd2def52d --- /dev/null +++ b/.github/workflows/on-demand-vrfv2plus-load-test.yml @@ -0,0 +1,116 @@ +name: On Demand VRFV2 Plus Load Test +on: + workflow_dispatch: + inputs: + network: + description: Network to run tests on + type: choice + options: + - "ETHEREUM_MAINNET" + - "SIMULATED" + - "SEPOLIA" + - "OPTIMISM_MAINNET" + - "OPTIMISM_GOERLI" + - "ARBITRUM_MAINNET" + - "ARBITRUM_GOERLI" + - "BSC_MAINNET" + - "BSC_TESTNET" + - "POLYGON_MAINNET" + - "MUMBAI" + - "AVALANCHE_FUJI" + - "AVALANCHE_MAINNET" + fundingPrivateKey: + description: Private funding key (Skip for Simulated) + required: false + type: string + wsURL: + description: WS URL for the network (Skip for Simulated) + required: false + type: string + httpURL: + description: HTTP URL for the network (Skip for Simulated) + required: false + type: string + chainlinkImage: + description: Container image location for the Chainlink nodes + required: true + default: public.ecr.aws/chainlink/chainlink + chainlinkVersion: + description: Container image version for the Chainlink nodes + required: true + default: "2.5.0" + 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 +jobs: + vrfv2plus_load_test: + name: ${{ inputs.network }} VRFV2 Plus Load Test + environment: integration + runs-on: ubuntu20.04-8cores-32GB + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + 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_RANDOMNESS_REQUEST_COUNT_PER_REQUEST: ${{ inputs.randomnessRequestCountPerRequest }} + + 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 + + WASP_LOG_LEVEL: info + steps: + - name: Collect Metrics + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: ${{ inputs.network }} VRFV2 Plus Load Test + continue-on-error: true + - name: Get Inputs + run: | + EVM_URLS=$(jq -r '.inputs.wsURL' $GITHUB_EVENT_PATH) + EVM_HTTP_URLS=$(jq -r '.inputs.httpURL' $GITHUB_EVENT_PATH) + EVM_KEYS=$(jq -r '.inputs.fundingPrivateKey' $GITHUB_EVENT_PATH) + + echo ::add-mask::$EVM_URLS + echo ::add-mask::$EVM_HTTP_URLS + echo ::add-mask::$EVM_KEYS + + echo EVM_URLS=$EVM_URLS >> $GITHUB_ENV + echo EVM_HTTP_URLS=$EVM_HTTP_URLS >> $GITHUB_ENV + echo EVM_KEYS=$EVM_KEYS >> $GITHUB_ENV + + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Run E2E soak tests + run: | + cd integration-tests/load/vrfv2plus + go test -v -timeout 8h -run TestVRFV2PlusLoad/vrfv2plus_soak_test + diff --git a/integration-tests/actions/vrfv2_actions/vrfv2_steps.go b/integration-tests/actions/vrfv2_actions/vrfv2_steps.go index 4beb49a23cb..96886eb8493 100644 --- a/integration-tests/actions/vrfv2_actions/vrfv2_steps.go +++ b/integration-tests/actions/vrfv2_actions/vrfv2_steps.go @@ -158,6 +158,7 @@ func SetupLocalLoadTestEnv(nodesFunding *big.Float, subFundingLINK *big.Int) (*t WithMockAdapter(). WithCLNodes(1). WithFunding(nodesFunding). + WithLogWatcher(). Build() if err != nil { return nil, nil, [32]byte{}, err diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go new file mode 100644 index 00000000000..3c210786bf8 --- /dev/null +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go @@ -0,0 +1,35 @@ +package vrfv2plus_config + +import "time" + +type VRFV2PlusConfig struct { + ChainlinkNodeFunding float64 `envconfig:"CHAINLINK_NODE_FUNDING" default:".1"` // Amount of native currency to fund each chainlink node with + IsNativePayment bool `envconfig:"IS_NATIVE_PAYMENT" default:"false"` // Whether to use native payment or LINK token + LinkNativeFeedResponse int64 `envconfig:"LINK_NATIVE_FEED_RESPONSE" default:"1000000000000000000"` // Response of the LINK/ETH feed + MinimumConfirmations uint16 `envconfig:"MINIMUM_CONFIRMATIONS" default:"3"` // Minimum number of confirmations for the VRF Coordinator + SubscriptionFundingAmountLink int64 `envconfig:"SUBSCRIPTION_FUNDING_AMOUNT_LINK" default:"10"` // Amount of LINK to fund the subscription with + SubscriptionFundingAmountNative int64 `envconfig:"SUBSCRIPTION_FUNDING_AMOUNT_NATIVE" default:"1"` // Amount of native currency to fund the subscription with + NumberOfWords uint32 `envconfig:"NUMBER_OF_WORDS" default:"3"` // Number of words to request + CallbackGasLimit uint32 `envconfig:"CALLBACK_GAS_LIMIT" default:"1000000"` // Gas limit for the callback + MaxGasLimitCoordinatorConfig uint32 `envconfig:"MAX_GAS_LIMIT_COORDINATOR_CONFIG" default:"2500000"` // Max gas limit for the VRF Coordinator config + FallbackWeiPerUnitLink int64 `envconfig:"FALLBACK_WEI_PER_UNIT_LINK" default:"60000000000000000"` // Fallback wei per unit LINK for the VRF Coordinator config + StalenessSeconds uint32 `envconfig:"STALENESS_SECONDS" default:"86400"` // Staleness in seconds for the VRF Coordinator config + GasAfterPaymentCalculation uint32 `envconfig:"GAS_AFTER_PAYMENT_CALCULATION" default:"33825"` // Gas after payment calculation for the VRF Coordinator config + FulfillmentFlatFeeLinkPPM uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM" default:"500"` // Flat fee in ppm for LINK for the VRF Coordinator config + FulfillmentFlatFeeNativePPM uint32 `envconfig:"FULFILLMENT_FLAT_FEE_NATIVE_PPM" default:"500"` // Flat fee in ppm for native currency for the VRF Coordinator config + + RandomnessRequestCountPerRequest uint16 `envconfig:"RANDOMNESS_REQUEST_COUNT_PER_REQUEST" default:"1"` // How many randomness requests to send per request + + //Wrapper Config + WrapperGasOverhead uint32 `envconfig:"WRAPPER_GAS_OVERHEAD" default:"50000"` + CoordinatorGasOverhead uint32 `envconfig:"COORDINATOR_GAS_OVERHEAD" default:"52000"` + WrapperPremiumPercentage uint8 `envconfig:"WRAPPER_PREMIUM_PERCENTAGE" default:"25"` + WrapperMaxNumberOfWords uint8 `envconfig:"WRAPPER_MAX_NUMBER_OF_WORDS" default:"10"` + WrapperConsumerFundingAmountNativeToken float64 `envconfig:"WRAPPER_CONSUMER_FUNDING_AMOUNT_NATIVE_TOKEN" default:"1"` + WrapperConsumerFundingAmountLink int64 `envconfig:"WRAPPER_CONSUMER_FUNDING_AMOUNT_LINK" default:"10"` + + //LOAD/SOAK Test Config + 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"` +} diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_constants/constants.go b/integration-tests/actions/vrfv2plus/vrfv2plus_constants/constants.go deleted file mode 100644 index bb266e7c2c5..00000000000 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_constants/constants.go +++ /dev/null @@ -1,40 +0,0 @@ -package vrfv2plus_constants - -import ( - "math/big" - - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" -) - -var ( - LinkNativeFeedResponse = big.NewInt(1e18) - MinimumConfirmations = uint16(3) - RandomnessRequestCountPerRequest = uint16(1) - VRFSubscriptionFundingAmountLink = big.NewInt(10) - VRFSubscriptionFundingAmountNativeToken = big.NewInt(1) - ChainlinkNodeFundingAmountNative = big.NewFloat(0.1) - NumberOfWords = uint32(3) - CallbackGasLimit = uint32(1000000) - MaxGasLimitVRFCoordinatorConfig = uint32(2.5e6) - StalenessSeconds = uint32(86400) - GasAfterPaymentCalculation = uint32(33825) - - VRFCoordinatorV2_5FeeConfig = vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig{ - FulfillmentFlatFeeLinkPPM: 500, - FulfillmentFlatFeeNativePPM: 500, - } - - VRFCoordinatorV2PlusUpgradedVersionFeeConfig = vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionFeeConfig{ - FulfillmentFlatFeeLinkPPM: 500, - FulfillmentFlatFeeNativePPM: 500, - } - - WrapperGasOverhead = uint32(50_000) - CoordinatorGasOverhead = uint32(52_000) - WrapperPremiumPercentage = uint8(25) - WrapperMaxNumberOfWords = uint8(10) - WrapperConsumerFundingAmountNativeToken = big.NewFloat(1) - - WrapperConsumerFundingAmountLink = big.NewInt(10) -) diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go index aa6dba8e1b4..0e68f785237 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go @@ -12,12 +12,11 @@ import ( "github.com/rs/zerolog" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_constants" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" - "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -232,6 +231,7 @@ func FundVRFCoordinatorV2_5Subscription(linkToken contracts.LinkToken, coordinat func SetupVRFV2_5Environment( env *test_env.CLClusterTestEnv, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, linkToken contracts.LinkToken, mockNativeLINKFeed contracts.MockETHLINKFeed, consumerContractsAmount int, @@ -243,12 +243,15 @@ func SetupVRFV2_5Environment( } err = vrfv2_5Contracts.Coordinator.SetConfig( - vrfv2plus_constants.MinimumConfirmations, - vrfv2plus_constants.MaxGasLimitVRFCoordinatorConfig, - vrfv2plus_constants.StalenessSeconds, - vrfv2plus_constants.GasAfterPaymentCalculation, - vrfv2plus_constants.LinkNativeFeedResponse, - vrfv2plus_constants.VRFCoordinatorV2_5FeeConfig, + vrfv2PlusConfig.MinimumConfirmations, + vrfv2PlusConfig.MaxGasLimitCoordinatorConfig, + vrfv2PlusConfig.StalenessSeconds, + vrfv2PlusConfig.GasAfterPaymentCalculation, + big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse), + vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig{ + FulfillmentFlatFeeLinkPPM: vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, + FulfillmentFlatFeeNativePPM: vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, + }, ) if err != nil { return nil, nil, nil, errors.Wrap(err, ErrSetVRFCoordinatorConfig) @@ -278,7 +281,7 @@ func SetupVRFV2_5Environment( if err != nil { return nil, nil, nil, errors.Wrap(err, ErrWaitTXsComplete) } - err = FundSubscription(env, linkToken, vrfv2_5Contracts.Coordinator, subID) + err = FundSubscription(env, vrfv2PlusConfig, linkToken, vrfv2_5Contracts.Coordinator, subID) if err != nil { return nil, nil, nil, err } @@ -310,7 +313,7 @@ func SetupVRFV2_5Environment( nativeTokenPrimaryKeyAddress, pubKeyCompressed, chainID.String(), - vrfv2plus_constants.MinimumConfirmations, + vrfv2PlusConfig.MinimumConfirmations, ) if err != nil { return nil, nil, nil, errors.Wrap(err, ErrCreateVRFV2PlusJobs) @@ -349,6 +352,7 @@ func SetupVRFV2_5Environment( func SetupVRFV2PlusWrapperEnvironment( env *test_env.CLClusterTestEnv, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, linkToken contracts.LinkToken, mockNativeLINKFeed contracts.MockETHLINKFeed, coordinator contracts.VRFCoordinatorV2_5, @@ -373,17 +377,16 @@ func SetupVRFV2PlusWrapperEnvironment( if err != nil { return nil, nil, errors.Wrap(err, ErrWaitTXsComplete) } - err = wrapperContracts.VRFV2PlusWrapper.SetConfig( - vrfv2plus_constants.WrapperGasOverhead, - vrfv2plus_constants.CoordinatorGasOverhead, - vrfv2plus_constants.WrapperPremiumPercentage, + vrfv2PlusConfig.WrapperGasOverhead, + vrfv2PlusConfig.CoordinatorGasOverhead, + vrfv2PlusConfig.WrapperPremiumPercentage, keyHash, - vrfv2plus_constants.WrapperMaxNumberOfWords, - vrfv2plus_constants.StalenessSeconds, - assets.GWei(50_000_000).ToInt(), - vrfv2plus_constants.VRFCoordinatorV2_5FeeConfig.FulfillmentFlatFeeLinkPPM, - vrfv2plus_constants.VRFCoordinatorV2_5FeeConfig.FulfillmentFlatFeeNativePPM, + vrfv2PlusConfig.WrapperMaxNumberOfWords, + vrfv2PlusConfig.StalenessSeconds, + big.NewInt(vrfv2PlusConfig.FallbackWeiPerUnitLink), + vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, + vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, ) if err != nil { return nil, nil, err @@ -405,7 +408,7 @@ func SetupVRFV2PlusWrapperEnvironment( return nil, nil, errors.Wrap(err, ErrWaitTXsComplete) } - err = FundSubscription(env, linkToken, coordinator, wrapperSubID) + err = FundSubscription(env, vrfv2PlusConfig, linkToken, coordinator, wrapperSubID) if err != nil { return nil, nil, err } @@ -413,7 +416,7 @@ func SetupVRFV2PlusWrapperEnvironment( //fund consumer with Link err = linkToken.Transfer( wrapperContracts.LoadTestConsumers[0].Address(), - big.NewInt(0).Mul(big.NewInt(1e18), vrfv2plus_constants.WrapperConsumerFundingAmountLink), + big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(vrfv2PlusConfig.WrapperConsumerFundingAmountLink)), ) if err != nil { return nil, nil, err @@ -424,7 +427,7 @@ func SetupVRFV2PlusWrapperEnvironment( } //fund consumer with Eth - err = wrapperContracts.LoadTestConsumers[0].Fund(vrfv2plus_constants.WrapperConsumerFundingAmountNativeToken) + err = wrapperContracts.LoadTestConsumers[0].Fund(big.NewFloat(vrfv2PlusConfig.WrapperConsumerFundingAmountNativeToken)) if err != nil { return nil, nil, err } @@ -474,14 +477,20 @@ func GetCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2_5) (linkT return } -func FundSubscription(env *test_env.CLClusterTestEnv, linkAddress contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, subID *big.Int) error { +func FundSubscription( + env *test_env.CLClusterTestEnv, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + linkAddress contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2_5, + subID *big.Int, +) error { //Native Billing - err := coordinator.FundSubscriptionWithNative(subID, big.NewInt(0).Mul(vrfv2plus_constants.VRFSubscriptionFundingAmountNativeToken, big.NewInt(1e18))) + err := coordinator.FundSubscriptionWithNative(subID, big.NewInt(0).Mul(big.NewInt(vrfv2PlusConfig.SubscriptionFundingAmountNative), big.NewInt(1e18))) if err != nil { return errors.Wrap(err, ErrFundSubWithNativeToken) } - err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, vrfv2plus_constants.VRFSubscriptionFundingAmountLink) + err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, big.NewInt(vrfv2PlusConfig.SubscriptionFundingAmountLink)) if err != nil { return errors.Wrap(err, ErrFundSubWithLinkToken) } @@ -499,16 +508,18 @@ func RequestRandomnessAndWaitForFulfillment( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + //todo - should it be here? l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { _, err := consumer.RequestRandomness( vrfv2PlusData.KeyHash, subID, - vrfv2plus_constants.MinimumConfirmations, - vrfv2plus_constants.CallbackGasLimit, + vrfv2PlusConfig.MinimumConfirmations, + vrfv2PlusConfig.CallbackGasLimit, isNativeBilling, - vrfv2plus_constants.NumberOfWords, - vrfv2plus_constants.RandomnessRequestCountPerRequest, + vrfv2PlusConfig.NumberOfWords, + vrfv2PlusConfig.RandomnessRequestCountPerRequest, ) if err != nil { return nil, errors.Wrap(err, ErrRequestRandomness) @@ -523,16 +534,17 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, l zerolog.Logger, ) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { _, err := consumer.RequestRandomness( vrfv2PlusData.KeyHash, subID, - vrfv2plus_constants.MinimumConfirmations, - vrfv2plus_constants.CallbackGasLimit, + vrfv2PlusConfig.MinimumConfirmations, + vrfv2PlusConfig.CallbackGasLimit, isNativeBilling, - vrfv2plus_constants.NumberOfWords, - vrfv2plus_constants.RandomnessRequestCountPerRequest, + vrfv2PlusConfig.NumberOfWords, + vrfv2PlusConfig.RandomnessRequestCountPerRequest, ) if err != nil { return nil, errors.Wrap(err, ErrRequestRandomness) @@ -583,24 +595,25 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { if isNativeBilling { _, err := consumer.RequestRandomnessNative( - vrfv2plus_constants.MinimumConfirmations, - vrfv2plus_constants.CallbackGasLimit, - vrfv2plus_constants.NumberOfWords, - vrfv2plus_constants.RandomnessRequestCountPerRequest, + vrfv2PlusConfig.MinimumConfirmations, + vrfv2PlusConfig.CallbackGasLimit, + vrfv2PlusConfig.NumberOfWords, + vrfv2PlusConfig.RandomnessRequestCountPerRequest, ) if err != nil { return nil, errors.Wrap(err, ErrRequestRandomnessDirectFundingNativePayment) } } else { _, err := consumer.RequestRandomness( - vrfv2plus_constants.MinimumConfirmations, - vrfv2plus_constants.CallbackGasLimit, - vrfv2plus_constants.NumberOfWords, - vrfv2plus_constants.RandomnessRequestCountPerRequest, + vrfv2PlusConfig.MinimumConfirmations, + vrfv2PlusConfig.CallbackGasLimit, + vrfv2PlusConfig.NumberOfWords, + vrfv2PlusConfig.RandomnessRequestCountPerRequest, ) if err != nil { return nil, errors.Wrap(err, ErrRequestRandomnessDirectFundingLinkPayment) diff --git a/integration-tests/load/vrfv2/cmd/dashboard.go b/integration-tests/load/vrfv2/cmd/dashboard.go index f7e29bd7d75..3035da0422f 100644 --- a/integration-tests/load/vrfv2/cmd/dashboard.go +++ b/integration-tests/load/vrfv2/cmd/dashboard.go @@ -8,10 +8,11 @@ import ( "github.com/K-Phoen/grabana/timeseries" "github.com/K-Phoen/grabana/timeseries/axis" "github.com/smartcontractkit/wasp" + "os" ) func main() { - lokiDS := "grafanacloud-logs" + lokiDS := os.Getenv("DATA_SOURCE_NAME") d, err := wasp.NewDashboard(nil, []dashboard.Option{ dashboard.Row("LoadContractMetrics", diff --git a/integration-tests/load/vrfv2plus/README.md b/integration-tests/load/vrfv2plus/README.md new file mode 100644 index 00000000000..1013a3f4c16 --- /dev/null +++ b/integration-tests/load/vrfv2plus/README.md @@ -0,0 +1,22 @@ +### VRFv2Plus Load tests + +## Usage +``` +export LOKI_TOKEN=... +export LOKI_URL=... + +go test -v -run TestVRFV2PlusLoad/vrfv2plus_soak_test +``` + +### Dashboards + +Deploying dashboard: +``` +export GRAFANA_URL=... +export GRAFANA_TOKEN=... +export DATA_SOURCE_NAME=grafanacloud-logs +export DASHBOARD_FOLDER=LoadTests +export DASHBOARD_NAME=${JobTypeName, for example WaspVRFv2Plus} + +go run dashboard.go +``` \ No newline at end of file diff --git a/integration-tests/load/vrfv2plus/cmd/dashboard.go b/integration-tests/load/vrfv2plus/cmd/dashboard.go new file mode 100644 index 00000000000..9a0ba682a18 --- /dev/null +++ b/integration-tests/load/vrfv2plus/cmd/dashboard.go @@ -0,0 +1,99 @@ +package main + +import ( + "github.com/K-Phoen/grabana/dashboard" + "github.com/K-Phoen/grabana/logs" + "github.com/K-Phoen/grabana/row" + "github.com/K-Phoen/grabana/target/prometheus" + "github.com/K-Phoen/grabana/timeseries" + "github.com/K-Phoen/grabana/timeseries/axis" + "github.com/smartcontractkit/wasp" + "os" +) + +func main() { + lokiDS := os.Getenv("DATA_SOURCE_NAME") + d, err := wasp.NewDashboard(nil, + []dashboard.Option{ + dashboard.Row("LoadContractMetrics", + row.WithTimeSeries( + "RequestCount + FulfilmentCount", + timeseries.Span(12), + timeseries.Height("300px"), + timeseries.DataSource(lokiDS), + timeseries.Axis( + axis.Unit("Requests"), + ), + timeseries.WithPrometheusTarget( + ` + last_over_time({type="vrfv2plus_contracts_load_summary", go_test_name=~"${go_test_name:pipe}", branch=~"${branch:pipe}", commit=~"${commit:pipe}", gen_name=~"${gen_name:pipe}"} + | json + | unwrap RequestCount [$__interval]) by (node_id, go_test_name, gen_name) + `, prometheus.Legend("{{go_test_name}} requests"), + ), + timeseries.WithPrometheusTarget( + ` + last_over_time({type="vrfv2plus_contracts_load_summary", go_test_name=~"${go_test_name:pipe}", branch=~"${branch:pipe}", commit=~"${commit:pipe}", gen_name=~"${gen_name:pipe}"} + | json + | unwrap FulfilmentCount [$__interval]) by (node_id, go_test_name, gen_name) + `, prometheus.Legend("{{go_test_name}} fulfillments"), + ), + ), + row.WithTimeSeries( + "Fulfillment time (blocks)", + timeseries.Span(12), + timeseries.Height("300px"), + timeseries.DataSource(lokiDS), + timeseries.Axis( + axis.Unit("Blocks"), + ), + timeseries.WithPrometheusTarget( + ` + last_over_time({type="vrfv2plus_contracts_load_summary", go_test_name=~"${go_test_name:pipe}", branch=~"${branch:pipe}", commit=~"${commit:pipe}", gen_name=~"${gen_name:pipe}"} + | json + | unwrap AverageFulfillmentInMillions [$__interval]) by (node_id, go_test_name, gen_name) / 1e6 + `, prometheus.Legend("{{go_test_name}} avg"), + ), + timeseries.WithPrometheusTarget( + ` + last_over_time({type="vrfv2plus_contracts_load_summary", go_test_name=~"${go_test_name:pipe}", branch=~"${branch:pipe}", commit=~"${commit:pipe}", gen_name=~"${gen_name:pipe}"} + | json + | unwrap SlowestFulfillment [$__interval]) by (node_id, go_test_name, gen_name) + `, prometheus.Legend("{{go_test_name}} slowest"), + ), + timeseries.WithPrometheusTarget( + ` + last_over_time({type="vrfv2plus_contracts_load_summary", go_test_name=~"${go_test_name:pipe}", branch=~"${branch:pipe}", commit=~"${commit:pipe}", gen_name=~"${gen_name:pipe}"} + | json + | unwrap FastestFulfillment [$__interval]) by (node_id, go_test_name, gen_name) + `, prometheus.Legend("{{go_test_name}} fastest"), + ), + ), + ), + dashboard.Row("CL nodes logs", + row.Collapse(), + row.WithLogs( + "CL nodes logs", + logs.DataSource(lokiDS), + logs.Span(12), + logs.Height("300px"), + logs.Transparent(), + logs.WithLokiTarget(` + {type="log_watch"} + `), + )), + }, + ) + if err != nil { + panic(err) + } + // set env vars + //export GRAFANA_URL=... + //export GRAFANA_TOKEN=... + //export DATA_SOURCE_NAME=Loki + //export DASHBOARD_FOLDER=LoadTests + //export DASHBOARD_NAME=Waspvrfv2plus + if _, err := d.Deploy(); err != nil { + panic(err) + } +} diff --git a/integration-tests/load/vrfv2plus/config.go b/integration-tests/load/vrfv2plus/config.go new file mode 100644 index 00000000000..17178a458e6 --- /dev/null +++ b/integration-tests/load/vrfv2plus/config.go @@ -0,0 +1,74 @@ +package loadvrfv2plus + +import ( + "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" +) + +const ( + DefaultConfigFilename = "config.toml" + + ErrReadPerfConfig = "failed to read TOML config for performance tests" + ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" +) + +type PerformanceConfig struct { + Soak *Soak `toml:"Soak"` + Load *Load `toml:"Load"` + SoakVolume *SoakVolume `toml:"SoakVolume"` + LoadVolume *LoadVolume `toml:"LoadVolume"` + Common *Common `toml:"Common"` +} + +type Common struct { + Funding +} + +type Funding struct { + NodeFunds *big.Float `toml:"node_funds"` + SubFunds *big.Int `toml:"sub_funds"` +} + +type Soak struct { + RPS int64 `toml:"rps"` + Duration *models.Duration `toml:"duration"` +} + +type SoakVolume struct { + Products int64 `toml:"products"` + Pace *models.Duration `toml:"pace"` + Duration *models.Duration `toml:"duration"` +} + +type Load struct { + RPSFrom int64 `toml:"rps_from"` + RPSIncrease int64 `toml:"rps_increase"` + RPSSteps int `toml:"rps_steps"` + Duration *models.Duration `toml:"duration"` +} + +type LoadVolume struct { + ProductsFrom int64 `toml:"products_from"` + ProductsIncrease int64 `toml:"products_increase"` + ProductsSteps int `toml:"products_steps"` + Pace *models.Duration `toml:"pace"` + Duration *models.Duration `toml:"duration"` +} + +func ReadConfig() (*PerformanceConfig, error) { + var cfg *PerformanceConfig + d, err := os.ReadFile(DefaultConfigFilename) + if err != nil { + return nil, errors.Wrap(err, ErrReadPerfConfig) + } + err = toml.Unmarshal(d, &cfg) + if err != nil { + return nil, errors.Wrap(err, ErrUnmarshalPerfConfig) + } + log.Debug().Interface("PerformanceConfig", cfg).Msg("Parsed performance config") + return cfg, nil +} diff --git a/integration-tests/load/vrfv2plus/config.toml b/integration-tests/load/vrfv2plus/config.toml new file mode 100644 index 00000000000..03169b4c9d7 --- /dev/null +++ b/integration-tests/load/vrfv2plus/config.toml @@ -0,0 +1,27 @@ +# 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 diff --git a/integration-tests/load/vrfv2plus/gun.go b/integration-tests/load/vrfv2plus/gun.go new file mode 100644 index 00000000000..f1b15bb5fef --- /dev/null +++ b/integration-tests/load/vrfv2plus/gun.go @@ -0,0 +1,56 @@ +package loadvrfv2plus + +import ( + "github.com/rs/zerolog" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" + "github.com/smartcontractkit/wasp" + "math/big" +) + +/* SingleHashGun is a gun that constantly requests randomness for one feed */ + +type SingleHashGun struct { + contracts *vrfv2plus.VRFV2_5Contracts + keyHash [32]byte + subID *big.Int + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig + logger zerolog.Logger +} + +func NewSingleHashGun( + contracts *vrfv2plus.VRFV2_5Contracts, + keyHash [32]byte, + subID *big.Int, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + logger zerolog.Logger, +) *SingleHashGun { + return &SingleHashGun{ + contracts: contracts, + keyHash: keyHash, + subID: subID, + vrfv2PlusConfig: vrfv2PlusConfig, + logger: logger, + } +} + +// Call implements example gun call, assertions on response bodies should be done here +func (m *SingleHashGun) Call(l *wasp.Generator) *wasp.CallResult { + //todo - should work with multiple consumers and consumers having different keyhashes and wallets + _, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( + m.contracts.LoadTestConsumers[0], + m.contracts.Coordinator, + &vrfv2plus.VRFV2PlusData{VRFV2PlusKeyData: vrfv2plus.VRFV2PlusKeyData{KeyHash: m.keyHash}}, + m.subID, + //todo - make this configurable + m.vrfv2PlusConfig.IsNativePayment, + m.vrfv2PlusConfig, + m.logger, + ) + + if err != nil { + return &wasp.CallResult{Error: err.Error(), Failed: true} + } + + return &wasp.CallResult{} +} diff --git a/integration-tests/load/vrfv2plus/onchain_monitoring.go b/integration-tests/load/vrfv2plus/onchain_monitoring.go new file mode 100644 index 00000000000..b22bf8259d1 --- /dev/null +++ b/integration-tests/load/vrfv2plus/onchain_monitoring.go @@ -0,0 +1,47 @@ +package loadvrfv2plus + +import ( + "context" + "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" + "github.com/smartcontractkit/wasp" + "testing" + "time" +) + +/* Monitors on-chain stats of LoadConsumer and pushes them to Loki every second */ + +const ( + LokiTypeLabel = "vrfv2plus_contracts_load_summary" + ErrMetrics = "failed to get VRFv2Plus load test metrics" + ErrLokiClient = "failed to create Loki client for monitoring" + ErrLokiPush = "failed to push monitoring metrics to Loki" +) + +func MonitorLoadStats(t *testing.T, 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) + } + } + }() +} diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go new file mode 100644 index 00000000000..ee8be6bd8a5 --- /dev/null +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -0,0 +1,161 @@ +package loadvrfv2plus + +import ( + "context" + "fmt" + "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" +) + +func TestVRFV2PlusLoad(t *testing.T) { + + var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig + err := envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) + require.NoError(t, err) + + l := logging.GetTestLogger(t) + + 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") + } + }) + + env.ParallelTransactions(true) + + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) + require.NoError(t, err, "error deploying mock ETH/LINK feed") + + 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") + + labels := map[string]string{ + "branch": "vrfv2Plus_healthcheck", + "commit": "vrfv2Plus_healthcheck", + } + + l.Info(). + Str("Test Duration", vrfv2PlusConfig.TestDuration.Truncate(time.Second).String()). + Int64("RPS", vrfv2PlusConfig.RPS). + Uint16("RandomnessRequestCountPerRequest", vrfv2PlusConfig.RandomnessRequestCountPerRequest). + Msg("Load Test Configs") + + singleFeedConfig := &wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "gun", + RateLimitUnitDuration: vrfv2PlusConfig.RateLimitUnitDuration, + Gun: NewSingleHashGun( + vrfv2PlusContracts, + vrfv2PlusData.KeyHash, + subID, + vrfv2PlusConfig, + l), + Labels: labels, + LokiConfig: wasp.NewEnvLokiConfig(), + CallTimeout: 2 * time.Minute, + } + + MonitorLoadStats(t, vrfv2PlusContracts, labels) + + // 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(). + Add(wasp.NewGenerator(singleFeedConfig)). + Run(true) + require.NoError(t, err) + + var wg sync.WaitGroup + + wg.Add(1) + requestCount, fulfilmentCount, err := WaitForRequestCountEqualToFulfilmentCount(vrfv2PlusContracts.LoadTestConsumers[0], 30*time.Second, &wg) + l.Info(). + Interface("Request Count", requestCount). + Interface("Fulfilment Count", fulfilmentCount). + Msg("Final Request/Fulfilment Stats") + require.NoError(t, err) + + wg.Wait() + }) + +} + +func WaitForRequestCountEqualToFulfilmentCount(consumer contracts.VRFv2PlusLoadTestConsumer, timeout time.Duration, wg *sync.WaitGroup) (*big.Int, *big.Int, error) { + metricsChannel := make(chan *contracts.VRFLoadTestMetrics) + metricsErrorChannel := make(chan error) + + testContext, testCancel := context.WithTimeout(context.Background(), timeout) + defer testCancel() + + ticker := time.NewTicker(time.Second * 1) + var metrics *contracts.VRFLoadTestMetrics + for { + select { + case <-testContext.Done(): + ticker.Stop() + wg.Done() + return metrics.RequestCount, metrics.FulfilmentCount, + fmt.Errorf("timeout waiting for rand request and fulfilments to be equal AFTER performance test was executed. Request Count: %d, Fulfilment Count: %d", + metrics.RequestCount.Uint64(), metrics.FulfilmentCount.Uint64()) + case <-ticker.C: + go getLoadTestMetrics(consumer, metricsChannel, metricsErrorChannel) + case metrics = <-metricsChannel: + if metrics.RequestCount.Cmp(metrics.FulfilmentCount) == 0 { + wg.Done() + return metrics.RequestCount, metrics.FulfilmentCount, nil + } + case err := <-metricsErrorChannel: + wg.Done() + return nil, nil, err + } + } +} + +func getLoadTestMetrics( + consumer contracts.VRFv2PlusLoadTestConsumer, + metricsChannel chan *contracts.VRFLoadTestMetrics, + metricsErrorChannel chan error, +) { + metrics, err := consumer.GetLoadTestMetrics(context.Background()) + if err != nil { + metricsErrorChannel <- err + } + metricsChannel <- metrics +} diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index e26a4ed6b1f..c2b99850811 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -2,6 +2,8 @@ package smoke import ( "context" + "github.com/kelseyhightower/envconfig" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" "math/big" "testing" "time" @@ -15,19 +17,23 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_constants" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" ) -func TestVRFv2PlusBilling(t *testing.T) { +func TestVRFv2Plus(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig + err := envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) + require.NoError(t, err) + env, err := test_env.NewCLTestEnvBuilder(). WithTestLogger(t). WithGeth(). WithCLNodes(1). - WithFunding(vrfv2plus_constants.ChainlinkNodeFundingAmountNative). + WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). Build() require.NoError(t, err, "error creating test env") t.Cleanup(func() { @@ -38,13 +44,13 @@ func TestVRFv2PlusBilling(t *testing.T) { env.ParallelTransactions(true) - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, vrfv2plus_constants.LinkNativeFeedResponse) + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) require.NoError(t, err, "error deploying mock ETH/LINK feed") linkToken, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err, "error deploying LINK contract") - vrfv2PlusContracts, subID, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, linkToken, mockETHLinkFeed, 1) + 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) @@ -72,6 +78,7 @@ func TestVRFv2PlusBilling(t *testing.T) { vrfv2PlusData, subID, isNativeBilling, + vrfv2PlusConfig, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -91,7 +98,7 @@ func TestVRFv2PlusBilling(t *testing.T) { require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") - require.Equal(t, vrfv2plus_constants.NumberOfWords, uint32(len(status.RandomWords))) + require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(status.RandomWords))) for _, w := range status.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") @@ -112,6 +119,7 @@ func TestVRFv2PlusBilling(t *testing.T) { vrfv2PlusData, subID, isNativeBilling, + vrfv2PlusConfig, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -130,7 +138,7 @@ func TestVRFv2PlusBilling(t *testing.T) { require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") - require.Equal(t, vrfv2plus_constants.NumberOfWords, uint32(len(status.RandomWords))) + require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(status.RandomWords))) for _, w := range status.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") @@ -139,6 +147,7 @@ func TestVRFv2PlusBilling(t *testing.T) { wrapperContracts, wrapperSubID, err := vrfv2plus.SetupVRFV2PlusWrapperEnvironment( env, + vrfv2PlusConfig, linkToken, mockETHLinkFeed, vrfv2PlusContracts.Coordinator, @@ -163,6 +172,7 @@ func TestVRFv2PlusBilling(t *testing.T) { vrfv2PlusData, wrapperSubID, isNativeBilling, + vrfv2PlusConfig, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -198,7 +208,7 @@ func TestVRFv2PlusBilling(t *testing.T) { Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). Msg("Random Words Request Fulfilment Status") - require.Equal(t, vrfv2plus_constants.NumberOfWords, uint32(len(consumerStatus.RandomWords))) + require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) for _, w := range consumerStatus.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") @@ -221,6 +231,7 @@ func TestVRFv2PlusBilling(t *testing.T) { vrfv2PlusData, wrapperSubID, isNativeBilling, + vrfv2PlusConfig, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -256,7 +267,7 @@ func TestVRFv2PlusBilling(t *testing.T) { Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). Msg("Random Words Request Fulfilment Status") - require.Equal(t, vrfv2plus_constants.NumberOfWords, uint32(len(consumerStatus.RandomWords))) + require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) for _, w := range consumerStatus.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") @@ -267,12 +278,15 @@ func TestVRFv2PlusBilling(t *testing.T) { func TestVRFv2PlusMigration(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig + err := envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) + require.NoError(t, err) env, err := test_env.NewCLTestEnvBuilder(). WithTestLogger(t). WithGeth(). WithCLNodes(1). - WithFunding(vrfv2plus_constants.ChainlinkNodeFundingAmountNative). + WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). Build() require.NoError(t, err, "error creating test env") t.Cleanup(func() { @@ -283,13 +297,13 @@ func TestVRFv2PlusMigration(t *testing.T) { env.ParallelTransactions(true) - mockETHLinkFeedAddress, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, vrfv2plus_constants.LinkNativeFeedResponse) + mockETHLinkFeedAddress, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) require.NoError(t, err, "error deploying mock ETH/LINK feed") linkAddress, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err, "error deploying LINK contract") - vrfv2PlusContracts, subID, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, linkAddress, mockETHLinkFeedAddress, 2) + vrfv2PlusContracts, subID, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, vrfv2PlusConfig, linkAddress, mockETHLinkFeedAddress, 2) require.NoError(t, err, "error setting up VRF v2_5 env") subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subID) @@ -322,12 +336,15 @@ func TestVRFv2PlusMigration(t *testing.T) { require.NoError(t, err, errors.Wrap(err, vrfv2plus.ErrRegisteringProvingKey)) err = newCoordinator.SetConfig( - vrfv2plus_constants.MinimumConfirmations, - vrfv2plus_constants.MaxGasLimitVRFCoordinatorConfig, - vrfv2plus_constants.StalenessSeconds, - vrfv2plus_constants.GasAfterPaymentCalculation, - vrfv2plus_constants.LinkNativeFeedResponse, - vrfv2plus_constants.VRFCoordinatorV2PlusUpgradedVersionFeeConfig, + vrfv2PlusConfig.MinimumConfirmations, + vrfv2PlusConfig.MaxGasLimitCoordinatorConfig, + vrfv2PlusConfig.StalenessSeconds, + vrfv2PlusConfig.GasAfterPaymentCalculation, + big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse), + vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionFeeConfig{ + FulfillmentFlatFeeLinkPPM: vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, + FulfillmentFlatFeeNativePPM: vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, + }, ) err = newCoordinator.SetLINKAndLINKNativeFeed(linkAddress.Address(), mockETHLinkFeedAddress.Address()) @@ -341,7 +358,7 @@ func TestVRFv2PlusMigration(t *testing.T) { vrfv2PlusData.PrimaryEthAddress, vrfv2PlusData.VRFKey.Data.ID, vrfv2PlusData.ChainID.String(), - vrfv2plus_constants.MinimumConfirmations, + vrfv2PlusConfig.MinimumConfirmations, ) require.NoError(t, err, vrfv2plus.ErrCreateVRFV2PlusJobs) @@ -438,6 +455,7 @@ func TestVRFv2PlusMigration(t *testing.T) { vrfv2PlusData, subID, false, + vrfv2PlusConfig, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -449,6 +467,7 @@ func TestVRFv2PlusMigration(t *testing.T) { vrfv2PlusData, subID, true, + vrfv2PlusConfig, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment")