From 5c7c7ce8a99cd874169ede6c6acac71fe61c92a7 Mon Sep 17 00:00:00 2001 From: Ilja Pavlovs Date: Wed, 7 Feb 2024 11:11:09 +0200 Subject: [PATCH] VRF-329: add BHS CTF test (#11890) * VRF-329: add BHS CTF test * VRF-329: add BHS CTF test - VRF v2 and V2Plus; Refactoring to make it a bit more DRY * VRF-329: small refactoring * VRF-329: fixing lint issues * VRF-329: fixing lint issues * VRF-329: fixing lint issues * VRF-329: fixing lint issues * VRF-329: fixing lint issues * VRF-329: trying to remove flakiness --- .github/workflows/integration-tests.yml | 4 +- integration-tests/actions/actions.go | 78 ++- .../actions/vrf/common/actions.go | 137 +++++ .../actions/vrf/common/errors.go | 27 + .../actions/vrf/common/models.go | 69 +++ integration-tests/actions/vrf/vrfv2/errors.go | 10 + .../actions/vrf/vrfv2/vrfv2_models.go | 34 -- .../actions/vrf/vrfv2/vrfv2_steps.go | 490 +++++++++--------- .../actions/vrf/vrfv2plus/errors.go | 17 + .../actions/vrf/vrfv2plus/vrfv2plus_models.go | 25 - .../actions/vrf/vrfv2plus/vrfv2plus_steps.go | 412 ++++++++------- .../vrfv2plus/vrfv2plus_config/config.go | 51 -- integration-tests/client/chainlink_models.go | 36 +- .../contracts/contract_models.go | 1 + .../contracts/ethereum_vrf_contracts.go | 12 + integration-tests/load/vrfv2/gun.go | 11 +- integration-tests/load/vrfv2/vrfv2_test.go | 51 +- integration-tests/load/vrfv2plus/gun.go | 11 +- .../load/vrfv2plus/vrfv2plus_test.go | 53 +- integration-tests/smoke/vrfv2_test.go | 328 +++++++++--- integration-tests/smoke/vrfv2plus_test.go | 366 +++++++++---- integration-tests/testconfig/vrfv2/config.go | 54 +- integration-tests/testconfig/vrfv2/vrfv2.toml | 16 +- .../testconfig/vrfv2plus/vrfv2plus.toml | 16 +- 24 files changed, 1526 insertions(+), 783 deletions(-) create mode 100644 integration-tests/actions/vrf/common/actions.go create mode 100644 integration-tests/actions/vrf/common/errors.go create mode 100644 integration-tests/actions/vrf/common/models.go create mode 100644 integration-tests/actions/vrf/vrfv2/errors.go create mode 100644 integration-tests/actions/vrf/vrfv2plus/errors.go delete mode 100644 integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index c0a3b834f69..d759a439907 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -454,11 +454,11 @@ jobs: os: ubuntu-latest pyroscope_env: ci-smoke-vrf-evm-simulated - name: vrfv2 - nodes: 3 + nodes: 4 os: ubuntu-latest pyroscope_env: ci-smoke-vrf2-evm-simulated - name: vrfv2plus - nodes: 3 + nodes: 4 os: ubuntu-latest pyroscope_env: ci-smoke-vrf2plus-evm-simulated - name: forwarder_ocr diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index 95b538129c7..6f820247535 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -2,14 +2,18 @@ package actions import ( + "context" "crypto/ecdsa" "encoding/json" "errors" "fmt" "math/big" "strings" + "sync" "testing" + "time" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -26,7 +30,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/testreporters" "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" - + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" ) @@ -484,3 +488,75 @@ func GetTxFromAddress(tx *types.Transaction) (string, error) { from, err := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx) return from.String(), err } + +// todo - move to CTF +func GetTxByHash(ctx context.Context, client blockchain.EVMClient, hash common.Hash) (*types.Transaction, bool, error) { + return client.(*blockchain.EthereumMultinodeClient). + DefaultClient.(*blockchain.EthereumClient). + Client. + TransactionByHash(ctx, hash) +} + +// todo - move to CTF +func DecodeTxInputData(abiString string, data []byte) (map[string]interface{}, error) { + jsonABI, err := abi.JSON(strings.NewReader(abiString)) + if err != nil { + return nil, err + } + methodSigData := data[:4] + inputsSigData := data[4:] + method, err := jsonABI.MethodById(methodSigData) + if err != nil { + return nil, err + } + inputsMap := make(map[string]interface{}) + if err := method.Inputs.UnpackIntoMap(inputsMap, inputsSigData); err != nil { + return nil, err + } + return inputsMap, nil +} + +// todo - move to EVMClient +func WaitForBlockNumberToBe( + waitForBlockNumberToBe uint64, + client blockchain.EVMClient, + wg *sync.WaitGroup, + timeout time.Duration, + t testing.TB, +) (uint64, error) { + blockNumberChannel := make(chan uint64) + errorChannel := make(chan error) + testContext, testCancel := context.WithTimeout(context.Background(), timeout) + defer testCancel() + + ticker := time.NewTicker(time.Second * 1) + var blockNumber uint64 + for { + select { + case <-testContext.Done(): + ticker.Stop() + wg.Done() + return blockNumber, + fmt.Errorf("timeout waiting for Block Number to be: %d. Last recorded block number was: %d", + waitForBlockNumberToBe, blockNumber) + case <-ticker.C: + go func() { + currentBlockNumber, err := client.LatestBlockNumber(testcontext.Get(t)) + if err != nil { + errorChannel <- err + } + blockNumberChannel <- currentBlockNumber + }() + case blockNumber = <-blockNumberChannel: + if blockNumber == waitForBlockNumberToBe { + ticker.Stop() + wg.Done() + return blockNumber, nil + } + case err := <-errorChannel: + ticker.Stop() + wg.Done() + return 0, err + } + } +} diff --git a/integration-tests/actions/vrf/common/actions.go b/integration-tests/actions/vrf/common/actions.go new file mode 100644 index 00000000000..ec7972de597 --- /dev/null +++ b/integration-tests/actions/vrf/common/actions.go @@ -0,0 +1,137 @@ +package common + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/google/uuid" + "github.com/rs/zerolog" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + testconfig "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2" +) + +func CreateFundAndGetSendingKeys( + client blockchain.EVMClient, + node *VRFNode, + chainlinkNodeFunding float64, + numberOfTxKeysToCreate int, + chainID *big.Int, +) ([]string, []common.Address, error) { + newNativeTokenKeyAddresses, err := CreateAndFundSendingKeys(client, node, chainlinkNodeFunding, numberOfTxKeysToCreate, chainID) + if err != nil { + return nil, nil, err + } + nativeTokenPrimaryKeyAddress, err := node.CLNode.API.PrimaryEthAddress() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrNodePrimaryKey, err) + } + allNativeTokenKeyAddressStrings := append(newNativeTokenKeyAddresses, nativeTokenPrimaryKeyAddress) + allNativeTokenKeyAddresses := make([]common.Address, len(allNativeTokenKeyAddressStrings)) + for _, addressString := range allNativeTokenKeyAddressStrings { + allNativeTokenKeyAddresses = append(allNativeTokenKeyAddresses, common.HexToAddress(addressString)) + } + return allNativeTokenKeyAddressStrings, allNativeTokenKeyAddresses, nil +} + +func CreateAndFundSendingKeys( + client blockchain.EVMClient, + node *VRFNode, + chainlinkNodeFunding float64, + numberOfNativeTokenAddressesToCreate int, + chainID *big.Int, +) ([]string, error) { + var newNativeTokenKeyAddresses []string + for i := 0; i < numberOfNativeTokenAddressesToCreate; i++ { + newTxKey, response, err := node.CLNode.API.CreateTxKey("evm", chainID.String()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrNodeNewTxKey, err) + } + if response.StatusCode != 200 { + return nil, fmt.Errorf("error creating transaction key - response code, err %d", response.StatusCode) + } + newNativeTokenKeyAddresses = append(newNativeTokenKeyAddresses, newTxKey.Data.ID) + err = actions.FundAddress(client, newTxKey.Data.ID, big.NewFloat(chainlinkNodeFunding)) + if err != nil { + return nil, err + } + } + return newNativeTokenKeyAddresses, nil +} + +func SetupBHSNode( + env *test_env.CLClusterTestEnv, + config *testconfig.General, + numberOfTxKeysToCreate int, + chainID *big.Int, + coordinatorAddress string, + BHSAddress string, + txKeyFunding float64, + l zerolog.Logger, + bhsNode *VRFNode, +) error { + bhsTXKeyAddressStrings, _, err := CreateFundAndGetSendingKeys( + env.EVMClient, + bhsNode, + txKeyFunding, + numberOfTxKeysToCreate, + chainID, + ) + if err != nil { + return err + } + bhsNode.TXKeyAddressStrings = bhsTXKeyAddressStrings + bhsSpec := client.BlockhashStoreJobSpec{ + ForwardingAllowed: false, + CoordinatorV2Address: coordinatorAddress, + CoordinatorV2PlusAddress: coordinatorAddress, + BlockhashStoreAddress: BHSAddress, + FromAddresses: bhsTXKeyAddressStrings, + EVMChainID: chainID.String(), + WaitBlocks: *config.BHSJobWaitBlocks, + LookbackBlocks: *config.BHSJobLookBackBlocks, + PollPeriod: config.BHSJobPollPeriod.Duration, + RunTimeout: config.BHSJobRunTimeout.Duration, + } + l.Info().Msg("Creating BHS Job") + bhsJob, err := CreateBHSJob( + bhsNode.CLNode.API, + bhsSpec, + ) + if err != nil { + return fmt.Errorf("%s, err %w", "", err) + } + bhsNode.Job = bhsJob + return nil +} + +func CreateBHSJob( + chainlinkNode *client.ChainlinkClient, + bhsJobSpecConfig client.BlockhashStoreJobSpec, +) (*client.Job, error) { + jobUUID := uuid.New() + spec := &client.BlockhashStoreJobSpec{ + Name: fmt.Sprintf("bhs-%s", jobUUID), + ForwardingAllowed: bhsJobSpecConfig.ForwardingAllowed, + CoordinatorV2Address: bhsJobSpecConfig.CoordinatorV2Address, + CoordinatorV2PlusAddress: bhsJobSpecConfig.CoordinatorV2PlusAddress, + BlockhashStoreAddress: bhsJobSpecConfig.BlockhashStoreAddress, + FromAddresses: bhsJobSpecConfig.FromAddresses, + EVMChainID: bhsJobSpecConfig.EVMChainID, + ExternalJobID: jobUUID.String(), + WaitBlocks: bhsJobSpecConfig.WaitBlocks, + LookbackBlocks: bhsJobSpecConfig.LookbackBlocks, + PollPeriod: bhsJobSpecConfig.PollPeriod, + RunTimeout: bhsJobSpecConfig.RunTimeout, + } + + job, err := chainlinkNode.MustCreateJob(spec) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrCreatingBHSJob, err) + } + return job, nil +} diff --git a/integration-tests/actions/vrf/common/errors.go b/integration-tests/actions/vrf/common/errors.go new file mode 100644 index 00000000000..36530428468 --- /dev/null +++ b/integration-tests/actions/vrf/common/errors.go @@ -0,0 +1,27 @@ +package common + +const ( + ErrNodePrimaryKey = "error getting node's primary ETH key" + ErrNodeNewTxKey = "error creating node's EVM transaction key" + ErrCreatingProvingKeyHash = "error creating a keyHash from the proving key" + ErrRegisteringProvingKey = "error registering a proving key on Coordinator contract" + ErrRegisterProvingKey = "error registering proving keys" + ErrEncodingProvingKey = "error encoding proving key" + ErrDeployBlockHashStore = "error deploying blockhash store" + ErrDeployCoordinator = "error deploying VRF CoordinatorV2" + ErrABIEncodingFunding = "error Abi encoding subscriptionID" + ErrSendingLinkToken = "error sending Link token" + ErrCreatingBHSJob = "error creating BHS job" + ErrParseJob = "error parsing job definition" + ErrSetVRFCoordinatorConfig = "error setting config for VRF Coordinator contract" + ErrCreateVRFSubscription = "error creating VRF Subscription" + ErrAddConsumerToSub = "error adding consumer to VRF Subscription" + ErrFundSubWithLinkToken = "error funding subscription with Link tokens" + ErrRestartCLNode = "error restarting CL node" + ErrWaitTXsComplete = "error waiting for TXs to complete" + ErrRequestRandomness = "error requesting randomness" + ErrLoadingCoordinator = "error loading coordinator contract" + + ErrWaitRandomWordsRequestedEvent = "error waiting for RandomWordsRequested event" + ErrWaitRandomWordsFulfilledEvent = "error waiting for RandomWordsFulfilled event" +) diff --git a/integration-tests/actions/vrf/common/models.go b/integration-tests/actions/vrf/common/models.go new file mode 100644 index 00000000000..bb486bd598b --- /dev/null +++ b/integration-tests/actions/vrf/common/models.go @@ -0,0 +1,69 @@ +package common + +import ( + "math/big" + "time" + + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" +) + +type VRFEncodedProvingKey [2]*big.Int + +// VRFV2PlusKeyData defines a jobs into and proving key info +type VRFKeyData struct { + VRFKey *client.VRFKey + EncodedProvingKey VRFEncodedProvingKey + KeyHash [32]byte +} + +type VRFNodeType int + +const ( + VRF VRFNodeType = iota + 1 + BHS +) + +func (n VRFNodeType) String() string { + return [...]string{"VRF", "BHS"}[n-1] +} + +func (n VRFNodeType) Index() int { + return int(n) +} + +type VRFNode struct { + CLNode *test_env.ClNode + Job *client.Job + TXKeyAddressStrings []string +} + +type VRFContracts struct { + CoordinatorV2 contracts.VRFCoordinatorV2 + CoordinatorV2Plus contracts.VRFCoordinatorV2_5 + VRFOwner contracts.VRFOwner + BHS contracts.BlockHashStore + VRFV2Consumer []contracts.VRFv2LoadTestConsumer + VRFV2PlusConsumer []contracts.VRFv2PlusLoadTestConsumer +} + +type VRFOwnerConfig struct { + OwnerAddress string + UseVRFOwner bool +} + +type VRFJobSpecConfig struct { + ForwardingAllowed bool + CoordinatorAddress string + FromAddresses []string + EVMChainID string + MinIncomingConfirmations int + PublicKey string + BatchFulfillmentEnabled bool + BatchFulfillmentGasMultiplier float64 + EstimateGasMultiplier float64 + PollPeriod time.Duration + RequestTimeout time.Duration + VRFOwnerConfig *VRFOwnerConfig +} diff --git a/integration-tests/actions/vrf/vrfv2/errors.go b/integration-tests/actions/vrf/vrfv2/errors.go new file mode 100644 index 00000000000..d6b24fe9e07 --- /dev/null +++ b/integration-tests/actions/vrf/vrfv2/errors.go @@ -0,0 +1,10 @@ +package vrfv2 + +const ( + ErrCreatingVRFv2Key = "error creating VRFv2 key" + ErrDeployVRFV2Wrapper = "error deploying VRFV2Wrapper" + ErrCreateVRFV2Jobs = "error creating VRF V2 Jobs" + ErrDeployVRFV2Contracts = "error deploying VRFV2 contracts" + ErrCreatingVRFv2Job = "error creating VRFv2 job" + ErrAdvancedConsumer = "error deploying VRFv2 Advanced Consumer" +) diff --git a/integration-tests/actions/vrf/vrfv2/vrfv2_models.go b/integration-tests/actions/vrf/vrfv2/vrfv2_models.go index be627b43e4f..3216af49904 100644 --- a/integration-tests/actions/vrf/vrfv2/vrfv2_models.go +++ b/integration-tests/actions/vrf/vrfv2/vrfv2_models.go @@ -1,44 +1,10 @@ package vrfv2 import ( - "math/big" - - "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" ) -type VRFV2EncodedProvingKey [2]*big.Int - -// VRFV2JobInfo defines a jobs into and proving key info -type VRFV2JobInfo struct { - Job *client.Job - VRFKey *client.VRFKey - EncodedProvingKey VRFV2EncodedProvingKey - KeyHash [32]byte -} - -type VRFV2Contracts struct { - Coordinator contracts.VRFCoordinatorV2 - VRFOwner contracts.VRFOwner - BHS contracts.BlockHashStore - LoadTestConsumers []contracts.VRFv2LoadTestConsumer -} - type VRFV2WrapperContracts struct { VRFV2Wrapper contracts.VRFV2Wrapper LoadTestConsumers []contracts.VRFv2WrapperLoadTestConsumer } - -// VRFV2PlusKeyData defines a jobs into and proving key info -type VRFV2KeyData struct { - VRFKey *client.VRFKey - EncodedProvingKey VRFV2EncodedProvingKey - KeyHash [32]byte -} - -type VRFV2Data struct { - VRFV2KeyData - VRFJob *client.Job - PrimaryEthAddress string - ChainID *big.Int -} diff --git a/integration-tests/actions/vrf/vrfv2/vrfv2_steps.go b/integration-tests/actions/vrf/vrfv2/vrfv2_steps.go index 276105d20ef..3813a970a2b 100644 --- a/integration-tests/actions/vrf/vrfv2/vrfv2_steps.go +++ b/integration-tests/actions/vrf/vrfv2/vrfv2_steps.go @@ -9,10 +9,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/rs/zerolog" + "golang.org/x/sync/errgroup" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + testconfig "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner" @@ -23,6 +25,7 @@ import ( chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/integration-tests/actions" + vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" @@ -30,57 +33,6 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/types" ) -var ( - ErrNodePrimaryKey = "error getting node's primary ETH key" - ErrNodeNewTxKey = "error creating node's EVM transaction key" - ErrCreatingProvingKeyHash = "error creating a keyHash from the proving key" - ErrRegisteringProvingKey = "error registering a proving key on Coordinator contract" - ErrRegisterProvingKey = "error registering proving keys" - ErrEncodingProvingKey = "error encoding proving key" - ErrCreatingVRFv2Key = "error creating VRFv2 key" - ErrDeployBlockHashStore = "error deploying blockhash store" - ErrDeployCoordinator = "error deploying VRF CoordinatorV2" - ErrAdvancedConsumer = "error deploying VRFv2 Advanced Consumer" - ErrABIEncodingFunding = "error Abi encoding subscriptionID" - ErrSendingLinkToken = "error sending Link token" - ErrCreatingVRFv2Job = "error creating VRFv2 job" - ErrParseJob = "error parsing job definition" - ErrDeployVRFV2Contracts = "error deploying VRFV2 contracts" - ErrSetVRFCoordinatorConfig = "error setting config for VRF Coordinator contract" - ErrCreateVRFSubscription = "error creating VRF Subscription" - ErrAddConsumerToSub = "error adding consumer to VRF Subscription" - ErrFundSubWithLinkToken = "error funding subscription with Link tokens" - ErrCreateVRFV2Jobs = "error creating VRF V2 Jobs" - ErrRestartCLNode = "error restarting CL node" - ErrWaitTXsComplete = "error waiting for TXs to complete" - ErrRequestRandomness = "error requesting randomness" - ErrLoadingCoordinator = "error loading coordinator contract" - - ErrWaitRandomWordsRequestedEvent = "error waiting for RandomWordsRequested event" - ErrWaitRandomWordsFulfilledEvent = "error waiting for RandomWordsFulfilled event" - ErrDeployWrapper = "error deploying VRFV2PlusWrapper" -) - -type VRFOwnerConfig struct { - OwnerAddress string - useVRFOwner bool -} - -type VRFJobSpecConfig struct { - ForwardingAllowed bool - CoordinatorAddress string - FromAddresses []string - EVMChainID string - MinIncomingConfirmations int - PublicKey string - BatchFulfillmentEnabled bool - BatchFulfillmentGasMultiplier float64 - EstimateGasMultiplier float64 - PollPeriod time.Duration - RequestTimeout time.Duration - VRFOwnerConfig VRFOwnerConfig -} - func DeployVRFV2Contracts( env *test_env.CLClusterTestEnv, linkTokenContract contracts.LinkToken, @@ -88,35 +40,35 @@ func DeployVRFV2Contracts( consumerContractsAmount int, useVRFOwner bool, useTestCoordinator bool, -) (*VRFV2Contracts, error) { +) (*vrfcommon.VRFContracts, error) { bhs, err := env.ContractDeployer.DeployBlockhashStore() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrDeployBlockHashStore, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployBlockHashStore, err) } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } var coordinatorAddress string if useTestCoordinator { testCoordinator, err := env.ContractDeployer.DeployVRFCoordinatorTestV2(linkTokenContract.Address(), bhs.Address(), linkEthFeedContract.Address()) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinator, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployCoordinator, err) } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } coordinatorAddress = testCoordinator.Address() } else { coordinator, err := env.ContractDeployer.DeployVRFCoordinatorV2(linkTokenContract.Address(), bhs.Address(), linkEthFeedContract.Address()) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinator, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployCoordinator, err) } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } coordinatorAddress = coordinator.Address() } @@ -126,25 +78,35 @@ func DeployVRFV2Contracts( } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2(coordinatorAddress) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrLoadingCoordinator, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrLoadingCoordinator, err) } if useVRFOwner { vrfOwner, err := env.ContractDeployer.DeployVRFOwner(coordinatorAddress) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinator, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployCoordinator, err) } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } - return &VRFV2Contracts{coordinator, vrfOwner, bhs, consumers}, nil - } - return &VRFV2Contracts{coordinator, nil, bhs, consumers}, nil + return &vrfcommon.VRFContracts{ + CoordinatorV2: coordinator, + VRFOwner: vrfOwner, + BHS: bhs, + VRFV2Consumer: consumers, + }, nil + } + return &vrfcommon.VRFContracts{ + CoordinatorV2: coordinator, + VRFOwner: nil, + BHS: bhs, + VRFV2Consumer: consumers, + }, nil } func DeployVRFV2Consumers(contractDeployer contracts.ContractDeployer, coordinatorAddress string, consumerContractsAmount int) ([]contracts.VRFv2LoadTestConsumer, error) { @@ -181,11 +143,11 @@ func DeployVRFV2DirectFundingContracts( ) (*VRFV2WrapperContracts, error) { vrfv2Wrapper, err := contractDeployer.DeployVRFV2Wrapper(linkTokenAddress, linkEthFeedAddress, coordinator.Address()) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrDeployWrapper, err) + return nil, fmt.Errorf("%s, err %w", ErrDeployVRFV2Wrapper, err) } err = chainClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } consumers, err := DeployVRFV2WrapperConsumers(contractDeployer, linkTokenAddress, vrfv2Wrapper, consumerContractsAmount) @@ -194,14 +156,14 @@ func DeployVRFV2DirectFundingContracts( } err = chainClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } return &VRFV2WrapperContracts{vrfv2Wrapper, consumers}, nil } func CreateVRFV2Job( chainlinkNode *client.ChainlinkClient, - vrfJobSpecConfig VRFJobSpecConfig, + vrfJobSpecConfig vrfcommon.VRFJobSpecConfig, ) (*client.Job, error) { jobUUID := uuid.New() os := &client.VRFV2TxPipelineSpec{ @@ -211,7 +173,7 @@ func CreateVRFV2Job( } ost, err := os.String() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrParseJob, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrParseJob, err) } spec := &client.VRFV2JobSpec{ @@ -229,13 +191,13 @@ func CreateVRFV2Job( PollPeriod: vrfJobSpecConfig.PollPeriod, RequestTimeout: vrfJobSpecConfig.RequestTimeout, } - if vrfJobSpecConfig.VRFOwnerConfig.useVRFOwner { + if vrfJobSpecConfig.VRFOwnerConfig.UseVRFOwner { spec.VRFOwner = vrfJobSpecConfig.VRFOwnerConfig.OwnerAddress spec.UseVRFOwner = true } if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrParseJob, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrParseJob, err) } job, err := chainlinkNode.MustCreateJob(spec) @@ -249,17 +211,17 @@ func VRFV2RegisterProvingKey( vrfKey *client.VRFKey, oracleAddress string, coordinator contracts.VRFCoordinatorV2, -) (VRFV2EncodedProvingKey, error) { +) (vrfcommon.VRFEncodedProvingKey, error) { provingKey, err := actions.EncodeOnChainVRFProvingKey(*vrfKey) if err != nil { - return VRFV2EncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrEncodingProvingKey, err) + return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrEncodingProvingKey, err) } err = coordinator.RegisterProvingKey( oracleAddress, provingKey, ) if err != nil { - return VRFV2EncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrRegisterProvingKey, err) + return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrRegisterProvingKey, err) } return provingKey, nil } @@ -273,11 +235,11 @@ func FundVRFCoordinatorV2Subscription( ) error { encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint64"}]`, subscriptionID) if err != nil { - return fmt.Errorf("%s, err %w", ErrABIEncodingFunding, err) + return fmt.Errorf("%s, err %w", vrfcommon.ErrABIEncodingFunding, err) } _, err = linkToken.TransferAndCall(coordinator.Address(), linkFundingAmountJuels, encodedSubId) if err != nil { - return fmt.Errorf("%s, err %w", ErrSendingLinkToken, err) + return fmt.Errorf("%s, err %w", vrfcommon.ErrSendingLinkToken, err) } return chainClient.WaitForEvents() } @@ -285,6 +247,7 @@ func FundVRFCoordinatorV2Subscription( // SetupVRFV2Environment will create specified number of subscriptions and add the same conumer/s to each of them func SetupVRFV2Environment( env *test_env.CLClusterTestEnv, + nodesToCreate []vrfcommon.VRFNodeType, vrfv2TestConfig types.VRFv2TestConfig, useVRFOwner bool, useTestCoordinator bool, @@ -295,170 +258,243 @@ func SetupVRFV2Environment( numberOfConsumers int, numberOfSubToCreate int, l zerolog.Logger, -) (*VRFV2Contracts, []uint64, *VRFV2Data, error) { +) (*vrfcommon.VRFContracts, []uint64, *vrfcommon.VRFKeyData, map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode, error) { l.Info().Msg("Starting VRFV2 environment setup") - l.Info().Msg("Deploying VRFV2 contracts") - vrfv2Contracts, err := DeployVRFV2Contracts( + vrfv2Config := vrfv2TestConfig.GetVRFv2Config().General + + vrfContracts, subIDs, err := SetupContracts( env, linkToken, mockNativeLINKFeed, numberOfConsumers, useVRFOwner, useTestCoordinator, + vrfv2Config, + numberOfSubToCreate, + l, ) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrDeployVRFV2Contracts, err) + return nil, nil, nil, nil, err } - vrfv2Config := vrfv2TestConfig.GetVRFv2Config().General - vrfCoordinatorV2FeeConfig := vrf_coordinator_v2.VRFCoordinatorV2FeeConfig{ - FulfillmentFlatFeeLinkPPMTier1: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier1, - FulfillmentFlatFeeLinkPPMTier2: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier2, - FulfillmentFlatFeeLinkPPMTier3: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier3, - FulfillmentFlatFeeLinkPPMTier4: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier4, - FulfillmentFlatFeeLinkPPMTier5: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier5, - ReqsForTier2: big.NewInt(*vrfv2Config.ReqsForTier2), - ReqsForTier3: big.NewInt(*vrfv2Config.ReqsForTier3), - ReqsForTier4: big.NewInt(*vrfv2Config.ReqsForTier4), - ReqsForTier5: big.NewInt(*vrfv2Config.ReqsForTier5)} - l.Info().Str("Coordinator", vrfv2Contracts.Coordinator.Address()).Msg("Setting Coordinator Config") - err = vrfv2Contracts.Coordinator.SetConfig( - *vrfv2Config.MinimumConfirmations, - *vrfv2Config.MaxGasLimitCoordinatorConfig, - *vrfv2Config.StalenessSeconds, - *vrfv2Config.GasAfterPaymentCalculation, - big.NewInt(*vrfv2Config.FallbackWeiPerUnitLink), - vrfCoordinatorV2FeeConfig, - ) - if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrSetVRFCoordinatorConfig, err) - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) - } - l.Info(). - Str("Coordinator", vrfv2Contracts.Coordinator.Address()). - Int("Number of Subs to create", numberOfSubToCreate). - Msg("Creating and funding subscriptions, adding consumers") - subIDs, err := CreateFundSubsAndAddConsumers( - env, - big.NewFloat(*vrfv2Config.SubscriptionFundingAmountLink), - linkToken, - vrfv2Contracts.Coordinator, vrfv2Contracts.LoadTestConsumers, numberOfSubToCreate) - if err != nil { - return nil, nil, nil, err + var nodesMap = make(map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode) + for i, nodeType := range nodesToCreate { + nodesMap[nodeType] = &vrfcommon.VRFNode{ + CLNode: env.ClCluster.Nodes[i], + } } - l.Info().Str("Node URL", env.ClCluster.NodeAPIs()[0].URL()).Msg("Creating VRF Key on the Node") - vrfKey, err := env.ClCluster.NodeAPIs()[0].MustCreateVRFKey() + l.Info().Str("Node URL", nodesMap[vrfcommon.VRF].CLNode.API.URL()).Msg("Creating VRF Key on the Node") + vrfKey, err := nodesMap[vrfcommon.VRF].CLNode.API.MustCreateVRFKey() if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2Key, err) + return nil, nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2Key, err) } pubKeyCompressed := vrfKey.Data.ID - - l.Info().Str("Coordinator", vrfv2Contracts.Coordinator.Address()).Msg("Registering Proving Key") - provingKey, err := VRFV2RegisterProvingKey(vrfKey, registerProvingKeyAgainstAddress, vrfv2Contracts.Coordinator) + l.Info(). + Str("Node URL", nodesMap[vrfcommon.VRF].CLNode.API.URL()). + Str("Keyhash", vrfKey.Data.Attributes.Hash). + Str("VRF Compressed Key", vrfKey.Data.Attributes.Compressed). + Str("VRF Uncompressed Key", vrfKey.Data.Attributes.Uncompressed). + Msg("VRF Key created on the Node") + + l.Info().Str("Coordinator", vrfContracts.CoordinatorV2.Address()).Msg("Registering Proving Key") + provingKey, err := VRFV2RegisterProvingKey(vrfKey, registerProvingKeyAgainstAddress, vrfContracts.CoordinatorV2) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrRegisteringProvingKey, err) + return nil, nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRegisteringProvingKey, err) } - keyHash, err := vrfv2Contracts.Coordinator.HashOfKey(context.Background(), provingKey) + keyHash, err := vrfContracts.CoordinatorV2.HashOfKey(context.Background(), provingKey) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreatingProvingKeyHash, err) + return nil, nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrCreatingProvingKeyHash, err) } chainID := env.EVMClient.GetChainID() - newNativeTokenKeyAddresses, err := CreateAndFundSendingKeys(env, vrfv2TestConfig, numberOfTxKeysToCreate, chainID) - if err != nil { - return nil, nil, nil, err - } - nativeTokenPrimaryKeyAddress, err := env.ClCluster.NodeAPIs()[0].PrimaryEthAddress() + vrfTXKeyAddressStrings, vrfTXKeyAddresses, err := vrfcommon.CreateFundAndGetSendingKeys( + env.EVMClient, + nodesMap[vrfcommon.VRF], + *vrfv2TestConfig.GetCommonConfig().ChainlinkNodeFunding, + numberOfTxKeysToCreate, + chainID, + ) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrNodePrimaryKey, err) + return nil, nil, nil, nil, err } - allNativeTokenKeyAddressStrings := append(newNativeTokenKeyAddresses, nativeTokenPrimaryKeyAddress) - allNativeTokenKeyAddresses := make([]common.Address, len(allNativeTokenKeyAddressStrings)) + nodesMap[vrfcommon.VRF].TXKeyAddressStrings = vrfTXKeyAddressStrings - for _, addressString := range allNativeTokenKeyAddressStrings { - allNativeTokenKeyAddresses = append(allNativeTokenKeyAddresses, common.HexToAddress(addressString)) - } - - var vrfOwnerConfig VRFOwnerConfig + var vrfOwnerConfig *vrfcommon.VRFOwnerConfig if useVRFOwner { - err := setupVRFOwnerContract(env, vrfv2Contracts, allNativeTokenKeyAddressStrings, allNativeTokenKeyAddresses, l) + err := setupVRFOwnerContract(env, vrfContracts, vrfTXKeyAddressStrings, vrfTXKeyAddresses, l) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } - vrfOwnerConfig = VRFOwnerConfig{ - OwnerAddress: vrfv2Contracts.VRFOwner.Address(), - useVRFOwner: useVRFOwner, + vrfOwnerConfig = &vrfcommon.VRFOwnerConfig{ + OwnerAddress: vrfContracts.VRFOwner.Address(), + UseVRFOwner: useVRFOwner, } } else { - vrfOwnerConfig = VRFOwnerConfig{ + vrfOwnerConfig = &vrfcommon.VRFOwnerConfig{ OwnerAddress: "", - useVRFOwner: useVRFOwner, + UseVRFOwner: useVRFOwner, } } - vrfJobSpecConfig := VRFJobSpecConfig{ - ForwardingAllowed: false, - CoordinatorAddress: vrfv2Contracts.Coordinator.Address(), - FromAddresses: allNativeTokenKeyAddressStrings, + g := errgroup.Group{} + if vrfNode, exists := nodesMap[vrfcommon.VRF]; exists { + g.Go(func() error { + err := setupVRFNode(vrfContracts, chainID, vrfv2Config, pubKeyCompressed, vrfOwnerConfig, l, vrfNode) + if err != nil { + return err + } + return nil + }) + } + + if bhsNode, exists := nodesMap[vrfcommon.BHS]; exists { + g.Go(func() error { + err := vrfcommon.SetupBHSNode( + env, + vrfv2TestConfig.GetVRFv2Config().General, + numberOfTxKeysToCreate, + chainID, + vrfContracts.CoordinatorV2.Address(), + vrfContracts.BHS.Address(), + *vrfv2TestConfig.GetCommonConfig().ChainlinkNodeFunding, + l, + bhsNode, + ) + if err != nil { + return err + } + return nil + }) + } + + if err := g.Wait(); err != nil { + return nil, nil, nil, nil, fmt.Errorf("VRF node setup ended up with an error: %w", err) + } + + vrfKeyData := vrfcommon.VRFKeyData{ + VRFKey: vrfKey, + EncodedProvingKey: provingKey, + KeyHash: keyHash, + } + + l.Info().Msg("VRFV2 environment setup is finished") + return vrfContracts, subIDs, &vrfKeyData, nodesMap, nil +} + +func setupVRFNode(contracts *vrfcommon.VRFContracts, chainID *big.Int, vrfv2Config *testconfig.General, pubKeyCompressed string, vrfOwnerConfig *vrfcommon.VRFOwnerConfig, l zerolog.Logger, vrfNode *vrfcommon.VRFNode) error { + vrfJobSpecConfig := vrfcommon.VRFJobSpecConfig{ + ForwardingAllowed: *vrfv2Config.VRFJobForwardingAllowed, + CoordinatorAddress: contracts.CoordinatorV2.Address(), + FromAddresses: vrfNode.TXKeyAddressStrings, EVMChainID: chainID.String(), MinIncomingConfirmations: int(*vrfv2Config.MinimumConfirmations), PublicKey: pubKeyCompressed, - EstimateGasMultiplier: 1, - BatchFulfillmentEnabled: false, - BatchFulfillmentGasMultiplier: 1.15, - PollPeriod: time.Second * 1, - RequestTimeout: time.Hour * 24, + EstimateGasMultiplier: *vrfv2Config.VRFJobEstimateGasMultiplier, + BatchFulfillmentEnabled: *vrfv2Config.VRFJobBatchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: *vrfv2Config.VRFJobBatchFulfillmentGasMultiplier, + PollPeriod: vrfv2Config.VRFJobPollPeriod.Duration, + RequestTimeout: vrfv2Config.VRFJobRequestTimeout.Duration, VRFOwnerConfig: vrfOwnerConfig, } l.Info().Msg("Creating VRFV2 Job") vrfV2job, err := CreateVRFV2Job( - env.ClCluster.NodeAPIs()[0], + vrfNode.CLNode.API, vrfJobSpecConfig, ) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreateVRFV2Jobs, err) + return fmt.Errorf("%s, err %w", ErrCreateVRFV2Jobs, err) } + vrfNode.Job = vrfV2job // this part is here because VRFv2 can work with only a specific key // [[EVM.KeySpecific]] // Key = '...' - nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, - node.WithVRFv2EVMEstimator(allNativeTokenKeyAddressStrings, *vrfv2Config.CLNodeMaxGasPriceGWei), + nodeConfig := node.NewConfig(vrfNode.CLNode.NodeConfig, + node.WithLogPollInterval(1*time.Second), + node.WithVRFv2EVMEstimator(vrfNode.TXKeyAddressStrings, *vrfv2Config.CLNodeMaxGasPriceGWei), ) l.Info().Msg("Restarting Node with new sending key PriceMax configuration") - err = env.ClCluster.Nodes[0].Restart(nodeConfig) + err = vrfNode.CLNode.Restart(nodeConfig) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrRestartCLNode, err) + return fmt.Errorf("%s, err %w", vrfcommon.ErrRestartCLNode, err) } + return nil +} - vrfv2KeyData := VRFV2KeyData{ - VRFKey: vrfKey, - EncodedProvingKey: provingKey, - KeyHash: keyHash, +func SetupContracts( + env *test_env.CLClusterTestEnv, + linkToken contracts.LinkToken, + mockNativeLINKFeed contracts.MockETHLINKFeed, + numberOfConsumers int, + useVRFOwner bool, + useTestCoordinator bool, + vrfv2Config *testconfig.General, + numberOfSubToCreate int, + l zerolog.Logger, +) (*vrfcommon.VRFContracts, []uint64, error) { + l.Info().Msg("Deploying VRFV2 contracts") + vrfContracts, err := DeployVRFV2Contracts( + env, + linkToken, + mockNativeLINKFeed, + numberOfConsumers, + useVRFOwner, + useTestCoordinator, + ) + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrDeployVRFV2Contracts, err) } - data := VRFV2Data{ - vrfv2KeyData, - vrfV2job, - nativeTokenPrimaryKeyAddress, - chainID, - } + vrfCoordinatorV2FeeConfig := vrf_coordinator_v2.VRFCoordinatorV2FeeConfig{ + FulfillmentFlatFeeLinkPPMTier1: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier1, + FulfillmentFlatFeeLinkPPMTier2: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier2, + FulfillmentFlatFeeLinkPPMTier3: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier3, + FulfillmentFlatFeeLinkPPMTier4: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier4, + FulfillmentFlatFeeLinkPPMTier5: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier5, + ReqsForTier2: big.NewInt(*vrfv2Config.ReqsForTier2), + ReqsForTier3: big.NewInt(*vrfv2Config.ReqsForTier3), + ReqsForTier4: big.NewInt(*vrfv2Config.ReqsForTier4), + ReqsForTier5: big.NewInt(*vrfv2Config.ReqsForTier5)} - l.Info().Msg("VRFV2 environment setup is finished") - return vrfv2Contracts, subIDs, &data, nil + l.Info().Str("Coordinator", vrfContracts.CoordinatorV2.Address()).Msg("Setting Coordinator Config") + err = vrfContracts.CoordinatorV2.SetConfig( + *vrfv2Config.MinimumConfirmations, + *vrfv2Config.MaxGasLimitCoordinatorConfig, + *vrfv2Config.StalenessSeconds, + *vrfv2Config.GasAfterPaymentCalculation, + big.NewInt(*vrfv2Config.FallbackWeiPerUnitLink), + vrfCoordinatorV2FeeConfig, + ) + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrSetVRFCoordinatorConfig, err) + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + l.Info(). + Str("Coordinator", vrfContracts.CoordinatorV2.Address()). + Int("Number of Subs to create", numberOfSubToCreate). + Msg("Creating and funding subscriptions, adding consumers") + subIDs, err := CreateFundSubsAndAddConsumers( + env, + big.NewFloat(*vrfv2Config.SubscriptionFundingAmountLink), + linkToken, + vrfContracts.CoordinatorV2, vrfContracts.VRFV2Consumer, numberOfSubToCreate) + if err != nil { + return nil, nil, err + } + return vrfContracts, subIDs, nil } -func setupVRFOwnerContract(env *test_env.CLClusterTestEnv, vrfv2Contracts *VRFV2Contracts, allNativeTokenKeyAddressStrings []string, allNativeTokenKeyAddresses []common.Address, l zerolog.Logger) error { +func setupVRFOwnerContract(env *test_env.CLClusterTestEnv, contracts *vrfcommon.VRFContracts, allNativeTokenKeyAddressStrings []string, allNativeTokenKeyAddresses []common.Address, l zerolog.Logger) error { l.Info().Msg("Setting up VRFOwner contract") l.Info(). - Str("Coordinator", vrfv2Contracts.Coordinator.Address()). - Str("VRFOwner", vrfv2Contracts.VRFOwner.Address()). + Str("Coordinator", contracts.CoordinatorV2.Address()). + Str("VRFOwner", contracts.VRFOwner.Address()). Msg("Transferring ownership of Coordinator to VRFOwner") - err := vrfv2Contracts.Coordinator.TransferOwnership(common.HexToAddress(vrfv2Contracts.VRFOwner.Address())) + err := contracts.CoordinatorV2.TransferOwnership(common.HexToAddress(contracts.VRFOwner.Address())) if err != nil { return nil } @@ -467,9 +503,9 @@ func setupVRFOwnerContract(env *test_env.CLClusterTestEnv, vrfv2Contracts *VRFV2 return nil } l.Info(). - Str("VRFOwner", vrfv2Contracts.VRFOwner.Address()). + Str("VRFOwner", contracts.VRFOwner.Address()). Msg("Accepting VRF Ownership") - err = vrfv2Contracts.VRFOwner.AcceptVRFOwnership() + err = contracts.VRFOwner.AcceptVRFOwnership() if err != nil { return nil } @@ -479,15 +515,15 @@ func setupVRFOwnerContract(env *test_env.CLClusterTestEnv, vrfv2Contracts *VRFV2 } l.Info(). Strs("Authorized Senders", allNativeTokenKeyAddressStrings). - Str("VRFOwner", vrfv2Contracts.VRFOwner.Address()). + Str("VRFOwner", contracts.VRFOwner.Address()). Msg("Setting authorized senders for VRFOwner contract") - err = vrfv2Contracts.VRFOwner.SetAuthorizedSenders(allNativeTokenKeyAddresses) + err = contracts.VRFOwner.SetAuthorizedSenders(allNativeTokenKeyAddresses) if err != nil { return nil } err = env.EVMClient.WaitForEvents() if err != nil { - return fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } return err } @@ -515,7 +551,7 @@ func SetupVRFV2WrapperEnvironment( } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } vrfv2Config := vrfv2TestConfig.GetVRFv2Config() @@ -533,7 +569,7 @@ func SetupVRFV2WrapperEnvironment( } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } // Fetch wrapper subscription ID @@ -543,7 +579,7 @@ func SetupVRFV2WrapperEnvironment( } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } // Fund wrapper subscription @@ -562,31 +598,12 @@ func SetupVRFV2WrapperEnvironment( } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } return wrapperContracts, &wrapperSubID, nil } -func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, testConfig tc.CommonTestConfig, numberOfNativeTokenAddressesToCreate int, chainID *big.Int) ([]string, error) { - var newNativeTokenKeyAddresses []string - for i := 0; i < numberOfNativeTokenAddressesToCreate; i++ { - newTxKey, response, err := env.ClCluster.NodeAPIs()[0].CreateTxKey("evm", chainID.String()) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrNodeNewTxKey, err) - } - if response.StatusCode != 200 { - return nil, fmt.Errorf("error creating transaction key - response code, err %d", response.StatusCode) - } - newNativeTokenKeyAddresses = append(newNativeTokenKeyAddresses, newTxKey.Data.ID) - err = actions.FundAddress(env.EVMClient, newTxKey.Data.ID, big.NewFloat(*testConfig.GetCommonConfig().ChainlinkNodeFunding)) - if err != nil { - return nil, err - } - } - return newNativeTokenKeyAddresses, nil -} - func CreateFundSubsAndAddConsumers( env *test_env.CLClusterTestEnv, subscriptionFundingAmountLink *big.Float, @@ -616,7 +633,7 @@ func CreateFundSubsAndAddConsumers( err = env.EVMClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } return subIDs, nil } @@ -634,7 +651,7 @@ func CreateSubsAndFund( } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } err = FundSubscriptions(env, subscriptionFundingAmountLink, linkToken, coordinator, subs) if err != nil { @@ -668,7 +685,7 @@ func AddConsumersToSubs( for _, consumer := range consumers { err := coordinator.AddConsumer(subID, consumer.Address()) if err != nil { - return fmt.Errorf("%s, err %w", ErrAddConsumerToSub, err) + return fmt.Errorf("%s, err %w", vrfcommon.ErrAddConsumerToSub, err) } } } @@ -678,16 +695,16 @@ func AddConsumersToSubs( func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts.VRFCoordinatorV2) (uint64, error) { tx, err := coordinator.CreateSubscription() if err != nil { - return 0, fmt.Errorf("%s, err %w", ErrCreateVRFSubscription, err) + return 0, fmt.Errorf("%s, err %w", vrfcommon.ErrCreateVRFSubscription, err) } err = env.EVMClient.WaitForEvents() if err != nil { - return 0, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return 0, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } receipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) if err != nil { - return 0, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return 0, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } //SubscriptionsCreated Log should be emitted with the subscription ID @@ -708,12 +725,12 @@ func FundSubscriptions( amountJuels := conversions.EtherToWei(subscriptionFundingAmountLink) err := FundVRFCoordinatorV2Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) if err != nil { - return fmt.Errorf("%s, err %w", ErrFundSubWithLinkToken, err) + return fmt.Errorf("%s, err %w", vrfcommon.ErrFundSubWithLinkToken, err) } } err := env.EVMClient.WaitForEvents() if err != nil { - return fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } return nil } @@ -723,7 +740,7 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( consumer contracts.VRFv2WrapperLoadTestConsumer, coordinator contracts.VRFCoordinatorV2, subID uint64, - vrfv2Data *VRFV2Data, + vrfv2KeyData *vrfcommon.VRFKeyData, minimumConfirmations uint16, callbackGasLimit uint32, numberOfWords uint32, @@ -739,7 +756,7 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( randomnessRequestCountPerRequest, ) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrRequestRandomness, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRequestRandomness, err) } wrapperAddress, err := consumer.GetWrapper(context.Background()) if err != nil { @@ -748,7 +765,7 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( fulfillmentEvents, err := WaitForRequestAndFulfillmentEvents( wrapperAddress.String(), coordinator, - vrfv2Data, + vrfv2KeyData, subID, randomWordsFulfilledEventTimeout, l, @@ -761,7 +778,7 @@ func RequestRandomnessAndWaitForFulfillment( consumer contracts.VRFv2LoadTestConsumer, coordinator contracts.VRFCoordinatorV2, subID uint64, - vrfv2Data *VRFV2Data, + vrfKeyData *vrfcommon.VRFKeyData, minimumConfirmations uint16, callbackGasLimit uint32, numberOfWords uint32, @@ -771,7 +788,7 @@ func RequestRandomnessAndWaitForFulfillment( ) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { logRandRequest(l, consumer.Address(), coordinator.Address(), subID, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) _, err := consumer.RequestRandomness( - vrfv2Data.KeyHash, + vrfKeyData.KeyHash, subID, minimumConfirmations, callbackGasLimit, @@ -779,13 +796,13 @@ func RequestRandomnessAndWaitForFulfillment( randomnessRequestCountPerRequest, ) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrRequestRandomness, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRequestRandomness, err) } fulfillmentEvents, err := WaitForRequestAndFulfillmentEvents( consumer.Address(), coordinator, - vrfv2Data, + vrfKeyData, subID, randomWordsFulfilledEventTimeout, l, @@ -798,7 +815,7 @@ func RequestRandomnessWithForceFulfillAndWaitForFulfillment( consumer contracts.VRFv2LoadTestConsumer, coordinator contracts.VRFCoordinatorV2, vrfOwner contracts.VRFOwner, - vrfv2Data *VRFV2Data, + vrfv2KeyData *vrfcommon.VRFKeyData, minimumConfirmations uint16, callbackGasLimit uint32, numberOfWords uint32, @@ -810,7 +827,7 @@ func RequestRandomnessWithForceFulfillAndWaitForFulfillment( ) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSet, *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, *vrf_owner.VRFOwnerRandomWordsForced, error) { logRandRequest(l, consumer.Address(), coordinator.Address(), 0, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) _, err := consumer.RequestRandomWordsWithForceFulfill( - vrfv2Data.KeyHash, + vrfv2KeyData.KeyHash, minimumConfirmations, callbackGasLimit, numberOfWords, @@ -819,17 +836,17 @@ func RequestRandomnessWithForceFulfillAndWaitForFulfillment( linkAddress, ) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrRequestRandomness, err) + return nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRequestRandomness, err) } randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfv2Data.KeyHash}, + [][32]byte{vrfv2KeyData.KeyHash}, nil, []common.Address{common.HexToAddress(consumer.Address())}, time.Minute*1, ) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsRequestedEvent, err) + return nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsRequestedEvent, err) } LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent) @@ -888,7 +905,7 @@ func RequestRandomnessWithForceFulfillAndWaitForFulfillment( case randomWordsForcedEvent = <-randWordsForcedEventChannel: LogRandomWordsForcedEvent(l, vrfOwner, randomWordsForcedEvent) case <-time.After(randomWordsFulfilledEventTimeout): - return nil, nil, nil, fmt.Errorf("timeout waiting for ConfigSet, RandomWordsFulfilled and RandomWordsForced events") + err = fmt.Errorf("timeout waiting for ConfigSet, RandomWordsFulfilled and RandomWordsForced events") } } return configSetEvent, randomWordsFulfilledEvent, randomWordsForcedEvent, err @@ -897,30 +914,29 @@ func RequestRandomnessWithForceFulfillAndWaitForFulfillment( func WaitForRequestAndFulfillmentEvents( consumerAddress string, coordinator contracts.VRFCoordinatorV2, - vrfv2Data *VRFV2Data, + vrfv2KeyData *vrfcommon.VRFKeyData, subID uint64, randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, ) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfv2Data.KeyHash}, + [][32]byte{vrfv2KeyData.KeyHash}, []uint64{subID}, []common.Address{common.HexToAddress(consumerAddress)}, time.Minute*1, ) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsRequestedEvent, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsRequestedEvent, err) } - LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent) + randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( []*big.Int{randomWordsRequestedEvent.RequestId}, randomWordsFulfilledEventTimeout, ) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsFulfilledEvent, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsFulfilledEvent, err) } - LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent) return randomWordsFulfilledEvent, err } @@ -985,7 +1001,7 @@ func LogRandomnessRequestedEvent( coordinator contracts.VRFCoordinatorV2, randomWordsRequestedEvent *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, ) { - l.Debug(). + l.Info(). Str("Coordinator", coordinator.Address()). Str("Request ID", randomWordsRequestedEvent.RequestId.String()). Uint64("Subscription ID", randomWordsRequestedEvent.SubId). @@ -1002,7 +1018,7 @@ func LogRandomWordsFulfilledEvent( coordinator contracts.VRFCoordinatorV2, randomWordsFulfilledEvent *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, ) { - l.Debug(). + l.Info(). Str("Coordinator", coordinator.Address()). Str("Total Payment", randomWordsFulfilledEvent.Payment.String()). Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). @@ -1036,7 +1052,7 @@ func logRandRequest( randomnessRequestCountPerRequest uint16, randomnessRequestCountPerRequestDeviation uint16, ) { - l.Debug(). + l.Info(). Str("Consumer", consumer). Str("Coordinator", coordinator). Uint64("SubID", subID). diff --git a/integration-tests/actions/vrf/vrfv2plus/errors.go b/integration-tests/actions/vrf/vrfv2plus/errors.go new file mode 100644 index 00000000000..d39e2002c13 --- /dev/null +++ b/integration-tests/actions/vrf/vrfv2plus/errors.go @@ -0,0 +1,17 @@ +package vrfv2plus + +const ( + ErrCreatingVRFv2PlusKey = "error creating VRFv2Plus key" + ErrAdvancedConsumer = "error deploying VRFv2Plus Advanced Consumer" + ErrCreatingVRFv2PlusJob = "error creating VRFv2Plus job" + ErrDeployVRFV2_5Contracts = "error deploying VRFV2_5 contracts" + ErrAddConsumerToSub = "error adding consumer to VRF Subscription" + ErrFundSubWithNativeToken = "error funding subscription with native token" + ErrSetLinkNativeLinkFeed = "error setting Link and ETH/LINK feed for VRF Coordinator contract" + ErrCreateVRFV2PlusJobs = "error creating VRF V2 Plus Jobs" + ErrRequestRandomnessDirectFundingLinkPayment = "error requesting randomness with direct funding and link payment" + ErrRequestRandomnessDirectFundingNativePayment = "error requesting randomness with direct funding and native payment" + ErrLinkTotalBalance = "error waiting for RandomWordsFulfilled event" + ErrNativeTokenBalance = "error waiting for RandomWordsFulfilled event" + ErrDeployWrapper = "error deploying VRFV2PlusWrapper" +) diff --git a/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_models.go b/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_models.go index c227d490eb9..a2ca8ec582b 100644 --- a/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_models.go +++ b/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_models.go @@ -1,34 +1,9 @@ package vrfv2plus import ( - "math/big" - - "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" ) -type VRFV2PlusEncodedProvingKey [2]*big.Int - -// VRFV2PlusKeyData defines a jobs into and proving key info -type VRFV2PlusKeyData struct { - VRFKey *client.VRFKey - EncodedProvingKey VRFV2PlusEncodedProvingKey - KeyHash [32]byte -} - -type VRFV2PlusData struct { - VRFV2PlusKeyData - VRFJob *client.Job - PrimaryEthAddress string - ChainID *big.Int -} - -type VRFV2_5Contracts struct { - Coordinator contracts.VRFCoordinatorV2_5 - BHS contracts.BlockHashStore - LoadTestConsumers []contracts.VRFv2PlusLoadTestConsumer -} - type VRFV2PlusWrapperContracts struct { VRFV2PlusWrapper contracts.VRFV2PlusWrapper LoadTestConsumers []contracts.VRFv2PlusWrapperLoadTestConsumer diff --git a/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_steps.go index cddd9d65e3d..23a778f229e 100644 --- a/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_steps.go @@ -7,8 +7,13 @@ import ( "sync" "time" + "golang.org/x/sync/errgroup" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" + vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" + testconfig "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2" + "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer" @@ -21,86 +26,33 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" "github.com/smartcontractkit/chainlink/integration-tests/types" - "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "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 ( - ErrNodePrimaryKey = "error getting node's primary ETH key" - ErrNodeNewTxKey = "error creating node's EVM transaction key" - ErrCreatingProvingKeyHash = "error creating a keyHash from the proving key" - ErrRegisteringProvingKey = "error registering a proving key on Coordinator contract" - ErrRegisterProvingKey = "error registering proving keys" - ErrEncodingProvingKey = "error encoding proving key" - ErrCreatingVRFv2PlusKey = "error creating VRFv2Plus key" - ErrDeployBlockHashStore = "error deploying blockhash store" - ErrDeployCoordinator = "error deploying VRF CoordinatorV2Plus" - ErrAdvancedConsumer = "error deploying VRFv2Plus Advanced Consumer" - ErrABIEncodingFunding = "error Abi encoding subscriptionID" - ErrSendingLinkToken = "error sending Link token" - ErrCreatingVRFv2PlusJob = "error creating VRFv2Plus job" - ErrParseJob = "error parsing job definition" - ErrDeployVRFV2_5Contracts = "error deploying VRFV2_5 contracts" - ErrSetVRFCoordinatorConfig = "error setting config for VRF Coordinator contract" - ErrCreateVRFSubscription = "error creating VRF Subscription" - ErrAddConsumerToSub = "error adding consumer to VRF Subscription" - ErrFundSubWithNativeToken = "error funding subscription with native token" - ErrSetLinkNativeLinkFeed = "error setting Link and ETH/LINK feed for VRF Coordinator contract" - ErrFundSubWithLinkToken = "error funding subscription with Link tokens" - ErrCreateVRFV2PlusJobs = "error creating VRF V2 Plus Jobs" - ErrGetPrimaryKey = "error getting primary ETH key address" - ErrRestartCLNode = "error restarting CL node" - ErrWaitTXsComplete = "error waiting for TXs to complete" - ErrRequestRandomness = "error requesting randomness" - ErrRequestRandomnessDirectFundingLinkPayment = "error requesting randomness with direct funding and link payment" - ErrRequestRandomnessDirectFundingNativePayment = "error requesting randomness with direct funding and native payment" - - ErrWaitRandomWordsRequestedEvent = "error waiting for RandomWordsRequested event" - ErrWaitRandomWordsFulfilledEvent = "error waiting for RandomWordsFulfilled event" - ErrLinkTotalBalance = "error waiting for RandomWordsFulfilled event" - ErrNativeTokenBalance = "error waiting for RandomWordsFulfilled event" - ErrDeployWrapper = "error deploying VRFV2PlusWrapper" -) - -type VRFJobSpecConfig struct { - ForwardingAllowed bool - CoordinatorAddress string - FromAddresses []string - EVMChainID string - MinIncomingConfirmations int - PublicKey string - BatchFulfillmentEnabled bool - BatchFulfillmentGasMultiplier float64 - EstimateGasMultiplier float64 - PollPeriod time.Duration - RequestTimeout time.Duration -} - func DeployVRFV2_5Contracts( contractDeployer contracts.ContractDeployer, chainClient blockchain.EVMClient, consumerContractsAmount int, -) (*VRFV2_5Contracts, error) { +) (*vrfcommon.VRFContracts, error) { bhs, err := contractDeployer.DeployBlockhashStore() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrDeployBlockHashStore, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployBlockHashStore, err) } err = chainClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } coordinator, err := contractDeployer.DeployVRFCoordinatorV2_5(bhs.Address()) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinator, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployCoordinator, err) } err = chainClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } consumers, err := DeployVRFV2PlusConsumers(contractDeployer, coordinator, consumerContractsAmount) if err != nil { @@ -108,9 +60,13 @@ func DeployVRFV2_5Contracts( } err = chainClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } - return &VRFV2_5Contracts{coordinator, bhs, consumers}, nil + return &vrfcommon.VRFContracts{ + CoordinatorV2Plus: coordinator, + BHS: bhs, + VRFV2PlusConsumer: consumers, + }, nil } func DeployVRFV2PlusConsumers(contractDeployer contracts.ContractDeployer, coordinator contracts.VRFCoordinatorV2_5, consumerContractsAmount int) ([]contracts.VRFv2PlusLoadTestConsumer, error) { @@ -127,7 +83,7 @@ func DeployVRFV2PlusConsumers(contractDeployer contracts.ContractDeployer, coord func CreateVRFV2PlusJob( chainlinkNode *client.ChainlinkClient, - vrfJobSpecConfig VRFJobSpecConfig, + vrfJobSpecConfig vrfcommon.VRFJobSpecConfig, ) (*client.Job, error) { jobUUID := uuid.New() os := &client.VRFV2PlusTxPipelineSpec{ @@ -137,7 +93,7 @@ func CreateVRFV2PlusJob( } ost, err := os.String() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrParseJob, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrParseJob, err) } job, err := chainlinkNode.MustCreateJob(&client.VRFV2PlusJobSpec{ @@ -165,17 +121,17 @@ func VRFV2_5RegisterProvingKey( vrfKey *client.VRFKey, coordinator contracts.VRFCoordinatorV2_5, gasLaneMaxGas uint64, -) (VRFV2PlusEncodedProvingKey, error) { +) (vrfcommon.VRFEncodedProvingKey, error) { provingKey, err := actions.EncodeOnChainVRFProvingKey(*vrfKey) if err != nil { - return VRFV2PlusEncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrEncodingProvingKey, err) + return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrEncodingProvingKey, err) } err = coordinator.RegisterProvingKey( provingKey, gasLaneMaxGas, ) if err != nil { - return VRFV2PlusEncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrRegisterProvingKey, err) + return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrRegisterProvingKey, err) } return provingKey, nil } @@ -183,16 +139,16 @@ func VRFV2_5RegisterProvingKey( func VRFV2PlusUpgradedVersionRegisterProvingKey( vrfKey *client.VRFKey, coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, -) (VRFV2PlusEncodedProvingKey, error) { +) (vrfcommon.VRFEncodedProvingKey, error) { provingKey, err := actions.EncodeOnChainVRFProvingKey(*vrfKey) if err != nil { - return VRFV2PlusEncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrEncodingProvingKey, err) + return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrEncodingProvingKey, err) } err = coordinator.RegisterProvingKey( provingKey, ) if err != nil { - return VRFV2PlusEncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrRegisterProvingKey, err) + return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrRegisterProvingKey, err) } return provingKey, nil } @@ -206,11 +162,11 @@ func FundVRFCoordinatorV2_5Subscription( ) error { encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint256"}]`, subscriptionID) if err != nil { - return fmt.Errorf("%s, err %w", ErrABIEncodingFunding, err) + return fmt.Errorf("%s, err %w", vrfcommon.ErrABIEncodingFunding, err) } _, err = linkToken.TransferAndCall(coordinator.Address(), linkFundingAmountJuels, encodedSubId) if err != nil { - return fmt.Errorf("%s, err %w", ErrSendingLinkToken, err) + return fmt.Errorf("%s, err %w", vrfcommon.ErrSendingLinkToken, err) } return chainClient.WaitForEvents() } @@ -218,6 +174,7 @@ func FundVRFCoordinatorV2_5Subscription( // SetupVRFV2_5Environment will create specified number of subscriptions and add the same conumer/s to each of them func SetupVRFV2_5Environment( env *test_env.CLClusterTestEnv, + nodesToCreate []vrfcommon.VRFNodeType, vrfv2PlusTestConfig types.VRFv2PlusTestConfig, linkToken contracts.LinkToken, mockNativeLINKFeed contracts.MockETHLINKFeed, @@ -225,17 +182,17 @@ func SetupVRFV2_5Environment( numberOfConsumers int, numberOfSubToCreate int, l zerolog.Logger, -) (*VRFV2_5Contracts, []*big.Int, *VRFV2PlusData, error) { +) (*vrfcommon.VRFContracts, []*big.Int, *vrfcommon.VRFKeyData, map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode, error) { l.Info().Msg("Starting VRFV2 Plus environment setup") l.Info().Msg("Deploying VRFV2 Plus contracts") - vrfv2_5Contracts, err := DeployVRFV2_5Contracts(env.ContractDeployer, env.EVMClient, numberOfConsumers) + vrfContracts, err := DeployVRFV2_5Contracts(env.ContractDeployer, env.EVMClient, numberOfConsumers) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrDeployVRFV2_5Contracts, err) + return nil, nil, nil, nil, fmt.Errorf("%s, err %w", ErrDeployVRFV2_5Contracts, err) } - l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Msg("Setting Coordinator Config") + l.Info().Str("Coordinator", vrfContracts.CoordinatorV2Plus.Address()).Msg("Setting Coordinator Config") vrfv2PlusConfig := vrfv2PlusTestConfig.GetVRFv2PlusConfig().General - err = vrfv2_5Contracts.Coordinator.SetConfig( + err = vrfContracts.CoordinatorV2Plus.SetConfig( *vrfv2PlusConfig.MinimumConfirmations, *vrfv2PlusConfig.MaxGasLimitCoordinatorConfig, *vrfv2PlusConfig.StalenessSeconds, @@ -247,20 +204,20 @@ func SetupVRFV2_5Environment( *vrfv2PlusConfig.LinkPremiumPercentage, ) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrSetVRFCoordinatorConfig, err) + return nil, nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrSetVRFCoordinatorConfig, err) } - l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Msg("Setting Link and ETH/LINK feed") - err = vrfv2_5Contracts.Coordinator.SetLINKAndLINKNativeFeed(linkToken.Address(), mockNativeLINKFeed.Address()) + l.Info().Str("Coordinator", vrfContracts.CoordinatorV2Plus.Address()).Msg("Setting Link and ETH/LINK feed") + err = vrfContracts.CoordinatorV2Plus.SetLINKAndLINKNativeFeed(linkToken.Address(), mockNativeLINKFeed.Address()) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrSetLinkNativeLinkFeed, err) + return nil, nil, nil, nil, fmt.Errorf("%s, err %w", ErrSetLinkNativeLinkFeed, err) } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } l.Info(). - Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()). + Str("Coordinator", vrfContracts.CoordinatorV2Plus.Address()). Int("Number of Subs to create", numberOfSubToCreate). Msg("Creating and funding subscriptions, adding consumers") subIDs, err := CreateFundSubsAndAddConsumers( @@ -268,110 +225,139 @@ func SetupVRFV2_5Environment( big.NewFloat(*vrfv2PlusConfig.SubscriptionFundingAmountNative), big.NewFloat(*vrfv2PlusConfig.SubscriptionFundingAmountLink), linkToken, - vrfv2_5Contracts.Coordinator, vrfv2_5Contracts.LoadTestConsumers, + vrfContracts.CoordinatorV2Plus, vrfContracts.VRFV2PlusConsumer, numberOfSubToCreate, vrfv2plus_config.BillingType(*vrfv2PlusConfig.SubscriptionBillingType)) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err + } + + var nodesMap = make(map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode) + for i, nodeType := range nodesToCreate { + nodesMap[nodeType] = &vrfcommon.VRFNode{ + CLNode: env.ClCluster.Nodes[i], + } } - l.Info().Str("Node URL", env.ClCluster.NodeAPIs()[0].URL()).Msg("Creating VRF Key on the Node") - vrfKey, err := env.ClCluster.NodeAPIs()[0].MustCreateVRFKey() + l.Info().Str("Node URL", nodesMap[vrfcommon.VRF].CLNode.API.URL()).Msg("Creating VRF Key on the Node") + vrfKey, err := nodesMap[vrfcommon.VRF].CLNode.API.MustCreateVRFKey() if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2PlusKey, err) + return nil, nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2PlusKey, err) } pubKeyCompressed := vrfKey.Data.ID + l.Info(). + Str("Node URL", nodesMap[vrfcommon.VRF].CLNode.API.URL()). + Str("Keyhash", vrfKey.Data.Attributes.Hash). + Str("VRF Compressed Key", vrfKey.Data.Attributes.Compressed). + Str("VRF Uncompressed Key", vrfKey.Data.Attributes.Uncompressed). + Msg("VRF Key created on the Node") - l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Msg("Registering Proving Key") - provingKey, err := VRFV2_5RegisterProvingKey(vrfKey, vrfv2_5Contracts.Coordinator, uint64(*vrfv2PlusConfig.CLNodeMaxGasPriceGWei)*1e9) + l.Info().Str("Coordinator", vrfContracts.CoordinatorV2Plus.Address()).Msg("Registering Proving Key") + provingKey, err := VRFV2_5RegisterProvingKey(vrfKey, vrfContracts.CoordinatorV2Plus, uint64(*vrfv2PlusConfig.CLNodeMaxGasPriceGWei)*1e9) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrRegisteringProvingKey, err) + return nil, nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRegisteringProvingKey, err) } - keyHash, err := vrfv2_5Contracts.Coordinator.HashOfKey(context.Background(), provingKey) + keyHash, err := vrfContracts.CoordinatorV2Plus.HashOfKey(context.Background(), provingKey) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreatingProvingKeyHash, err) + return nil, nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrCreatingProvingKeyHash, err) } chainID := env.EVMClient.GetChainID() - newNativeTokenKeyAddresses, err := CreateAndFundSendingKeys(env, vrfv2PlusTestConfig, numberOfTxKeysToCreate, chainID) + vrfTXKeyAddressStrings, _, err := vrfcommon.CreateFundAndGetSendingKeys( + env.EVMClient, + nodesMap[vrfcommon.VRF], + *vrfv2PlusTestConfig.GetCommonConfig().ChainlinkNodeFunding, + numberOfTxKeysToCreate, + chainID, + ) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } - nativeTokenPrimaryKeyAddress, err := env.ClCluster.NodeAPIs()[0].PrimaryEthAddress() - if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrNodePrimaryKey, err) + nodesMap[vrfcommon.VRF].TXKeyAddressStrings = vrfTXKeyAddressStrings + + g := errgroup.Group{} + if vrfNode, exists := nodesMap[vrfcommon.VRF]; exists { + g.Go(func() error { + err := setupVRFNode(vrfContracts, chainID, vrfv2PlusConfig.General, pubKeyCompressed, l, vrfNode) + if err != nil { + return err + } + return nil + }) + } + + if bhsNode, exists := nodesMap[vrfcommon.BHS]; exists { + g.Go(func() error { + err := vrfcommon.SetupBHSNode( + env, + vrfv2PlusConfig.General, + numberOfTxKeysToCreate, + chainID, + vrfContracts.CoordinatorV2Plus.Address(), + vrfContracts.BHS.Address(), + *vrfv2PlusTestConfig.GetCommonConfig().ChainlinkNodeFunding, + l, + bhsNode, + ) + if err != nil { + return err + } + return nil + }) } - allNativeTokenKeyAddresses := append(newNativeTokenKeyAddresses, nativeTokenPrimaryKeyAddress) - vrfJobSpecConfig := VRFJobSpecConfig{ - ForwardingAllowed: false, - CoordinatorAddress: vrfv2_5Contracts.Coordinator.Address(), - FromAddresses: allNativeTokenKeyAddresses, + if err := g.Wait(); err != nil { + return nil, nil, nil, nil, fmt.Errorf("VRF node setup ended up with an error: %w", err) + } + + vrfKeyData := vrfcommon.VRFKeyData{ + VRFKey: vrfKey, + EncodedProvingKey: provingKey, + KeyHash: keyHash, + } + + l.Info().Msg("VRFV2 Plus environment setup is finished") + return vrfContracts, subIDs, &vrfKeyData, nodesMap, nil +} + +func setupVRFNode(contracts *vrfcommon.VRFContracts, chainID *big.Int, vrfv2Config *testconfig.General, pubKeyCompressed string, l zerolog.Logger, vrfNode *vrfcommon.VRFNode) error { + vrfJobSpecConfig := vrfcommon.VRFJobSpecConfig{ + ForwardingAllowed: *vrfv2Config.VRFJobForwardingAllowed, + CoordinatorAddress: contracts.CoordinatorV2Plus.Address(), + FromAddresses: vrfNode.TXKeyAddressStrings, EVMChainID: chainID.String(), - MinIncomingConfirmations: int(*vrfv2PlusConfig.MinimumConfirmations), + MinIncomingConfirmations: int(*vrfv2Config.MinimumConfirmations), PublicKey: pubKeyCompressed, - EstimateGasMultiplier: 1, - BatchFulfillmentEnabled: false, - BatchFulfillmentGasMultiplier: 1.15, - PollPeriod: time.Second * 1, - RequestTimeout: time.Hour * 24, + EstimateGasMultiplier: *vrfv2Config.VRFJobEstimateGasMultiplier, + BatchFulfillmentEnabled: *vrfv2Config.VRFJobBatchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: *vrfv2Config.VRFJobBatchFulfillmentGasMultiplier, + PollPeriod: vrfv2Config.VRFJobPollPeriod.Duration, + RequestTimeout: vrfv2Config.VRFJobRequestTimeout.Duration, + VRFOwnerConfig: nil, } l.Info().Msg("Creating VRFV2 Plus Job") job, err := CreateVRFV2PlusJob( - env.ClCluster.NodeAPIs()[0], + vrfNode.CLNode.API, vrfJobSpecConfig, ) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreateVRFV2PlusJobs, err) + return fmt.Errorf("%s, err %w", ErrCreateVRFV2PlusJobs, err) } + vrfNode.Job = job // this part is here because VRFv2 can work with only a specific key // [[EVM.KeySpecific]] // Key = '...' - nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, + nodeConfig := node.NewConfig(vrfNode.CLNode.NodeConfig, node.WithLogPollInterval(1*time.Second), - node.WithVRFv2EVMEstimator(allNativeTokenKeyAddresses, *vrfv2PlusConfig.CLNodeMaxGasPriceGWei), + node.WithVRFv2EVMEstimator(vrfNode.TXKeyAddressStrings, *vrfv2Config.CLNodeMaxGasPriceGWei), ) - l.Info().Msg("Restarting Node with new sending key PriceMax configuration and log poll period configuration") - err = env.ClCluster.Nodes[0].Restart(nodeConfig) + l.Info().Msg("Restarting Node with new sending key PriceMax configuration") + err = vrfNode.CLNode.Restart(nodeConfig) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrRestartCLNode, err) - } - - vrfv2PlusKeyData := VRFV2PlusKeyData{ - VRFKey: vrfKey, - EncodedProvingKey: provingKey, - KeyHash: keyHash, + return fmt.Errorf("%s, err %w", vrfcommon.ErrRestartCLNode, err) } - - data := VRFV2PlusData{ - vrfv2PlusKeyData, - job, - nativeTokenPrimaryKeyAddress, - chainID, - } - - l.Info().Msg("VRFV2 Plus environment setup is finished") - return vrfv2_5Contracts, subIDs, &data, nil -} - -func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, commonTestConfig tc.CommonTestConfig, numberOfNativeTokenAddressesToCreate int, chainID *big.Int) ([]string, error) { - var newNativeTokenKeyAddresses []string - for i := 0; i < numberOfNativeTokenAddressesToCreate; i++ { - newTxKey, response, err := env.ClCluster.NodeAPIs()[0].CreateTxKey("evm", chainID.String()) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrNodeNewTxKey, err) - } - if response.StatusCode != 200 { - return nil, fmt.Errorf("error creating transaction key - response code, err %d", response.StatusCode) - } - newNativeTokenKeyAddresses = append(newNativeTokenKeyAddresses, newTxKey.Data.ID) - err = actions.FundAddress(env.EVMClient, newTxKey.Data.ID, big.NewFloat(*commonTestConfig.GetCommonConfig().ChainlinkNodeFunding)) - if err != nil { - return nil, err - } - } - return newNativeTokenKeyAddresses, nil + return nil } func CreateFundSubsAndAddConsumers( @@ -413,7 +399,7 @@ func CreateFundSubsAndAddConsumers( err = env.EVMClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } return subIDs, nil } @@ -433,7 +419,7 @@ func CreateSubsAndFund( } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } err = FundSubscriptions( env, @@ -485,16 +471,16 @@ func AddConsumersToSubs( func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts.VRFCoordinatorV2_5) (*big.Int, error) { tx, err := coordinator.CreateSubscription() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrCreateVRFSubscription, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrCreateVRFSubscription, err) } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } receipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } //SubscriptionsCreated Log should be emitted with the subscription ID @@ -529,7 +515,7 @@ func FundSubscriptions( amountJuels := conversions.EtherToWei(subscriptionFundingAmountLink) err := FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) if err != nil { - return fmt.Errorf("%s, err %w", ErrFundSubWithLinkToken, err) + return fmt.Errorf("%s, err %w", vrfcommon.ErrFundSubWithLinkToken, err) } case vrfv2plus_config.BillingType_Link_and_Native: //Native Billing @@ -545,7 +531,7 @@ func FundSubscriptions( amountJuels := conversions.EtherToWei(subscriptionFundingAmountLink) err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) if err != nil { - return fmt.Errorf("%s, err %w", ErrFundSubWithLinkToken, err) + return fmt.Errorf("%s, err %w", vrfcommon.ErrFundSubWithLinkToken, err) } default: return fmt.Errorf("invalid billing type: %s", subscriptionBillingType) @@ -553,7 +539,7 @@ func FundSubscriptions( } err := env.EVMClient.WaitForEvents() if err != nil { - return fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } return nil } @@ -585,7 +571,7 @@ func GetCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2_5) (linkT func RequestRandomnessAndWaitForFulfillment( consumer contracts.VRFv2PlusLoadTestConsumer, coordinator contracts.VRFCoordinatorV2_5, - vrfv2PlusData *VRFV2PlusData, + vrfKeyData *vrfcommon.VRFKeyData, subID *big.Int, isNativeBilling bool, minimumConfirmations uint16, @@ -596,9 +582,21 @@ func RequestRandomnessAndWaitForFulfillment( randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { - logRandRequest(l, consumer.Address(), coordinator.Address(), subID, isNativeBilling, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) + logRandRequest( + l, + consumer.Address(), + coordinator.Address(), + subID, + isNativeBilling, + minimumConfirmations, + callbackGasLimit, + numberOfWords, + vrfKeyData.KeyHash, + randomnessRequestCountPerRequest, + randomnessRequestCountPerRequestDeviation, + ) _, err := consumer.RequestRandomness( - vrfv2PlusData.KeyHash, + vrfKeyData.KeyHash, subID, minimumConfirmations, callbackGasLimit, @@ -607,13 +605,13 @@ func RequestRandomnessAndWaitForFulfillment( randomnessRequestCountPerRequest, ) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrRequestRandomness, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRequestRandomness, err) } return WaitForRequestAndFulfillmentEvents( consumer.Address(), coordinator, - vrfv2PlusData, + vrfKeyData, subID, isNativeBilling, randomWordsFulfilledEventTimeout, @@ -624,7 +622,7 @@ func RequestRandomnessAndWaitForFulfillment( func RequestRandomnessAndWaitForFulfillmentUpgraded( consumer contracts.VRFv2PlusLoadTestConsumer, coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, - vrfv2PlusData *VRFV2PlusData, + vrfKeyData *vrfcommon.VRFKeyData, subID *big.Int, isNativeBilling bool, minimumConfirmations uint16, @@ -634,9 +632,21 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( randomnessRequestCountPerRequestDeviation uint16, l zerolog.Logger, ) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { - logRandRequest(l, consumer.Address(), coordinator.Address(), subID, isNativeBilling, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) + logRandRequest( + l, + consumer.Address(), + coordinator.Address(), + subID, + isNativeBilling, + minimumConfirmations, + callbackGasLimit, + numberOfWords, + vrfKeyData.KeyHash, + randomnessRequestCountPerRequest, + randomnessRequestCountPerRequestDeviation, + ) _, err := consumer.RequestRandomness( - vrfv2PlusData.KeyHash, + vrfKeyData.KeyHash, subID, minimumConfirmations, callbackGasLimit, @@ -645,17 +655,17 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( randomnessRequestCountPerRequest, ) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrRequestRandomness, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRequestRandomness, err) } randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfv2PlusData.KeyHash}, + [][32]byte{vrfKeyData.KeyHash}, []*big.Int{subID}, []common.Address{common.HexToAddress(consumer.Address())}, time.Minute*1, ) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsRequestedEvent, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsRequestedEvent, err) } LogRandomnessRequestedEventUpgraded(l, coordinator, randomWordsRequestedEvent) @@ -666,7 +676,7 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( time.Minute*2, ) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsFulfilledEvent, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsFulfilledEvent, err) } LogRandomWordsFulfilledEventUpgraded(l, coordinator, randomWordsFulfilledEvent) @@ -698,7 +708,7 @@ func SetupVRFV2PlusWrapperEnvironment( err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } err = wrapperContracts.VRFV2PlusWrapper.SetConfig( *vrfv2PlusConfig.WrapperGasOverhead, @@ -717,7 +727,7 @@ func SetupVRFV2PlusWrapperEnvironment( err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } //fund sub @@ -728,7 +738,7 @@ func SetupVRFV2PlusWrapperEnvironment( err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } err = FundSubscriptions(env, big.NewFloat(*vrfv2PlusTestConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), big.NewFloat(*vrfv2PlusTestConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), linkToken, coordinator, []*big.Int{wrapperSubID}, vrfv2plus_config.BillingType(*vrfv2PlusTestConfig.GetVRFv2PlusConfig().General.SubscriptionBillingType)) @@ -746,7 +756,7 @@ func SetupVRFV2PlusWrapperEnvironment( } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } //fund consumer with Eth @@ -756,7 +766,7 @@ func SetupVRFV2PlusWrapperEnvironment( } err = env.EVMClient.WaitForEvents() if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } return wrapperContracts, wrapperSubID, nil } @@ -788,7 +798,7 @@ func DeployVRFV2PlusDirectFundingContracts( } err = chainClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } consumers, err := DeployVRFV2PlusWrapperConsumers(contractDeployer, linkTokenAddress, vrfv2PlusWrapper, consumerContractsAmount) @@ -797,7 +807,7 @@ func DeployVRFV2PlusDirectFundingContracts( } err = chainClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } return &VRFV2PlusWrapperContracts{vrfv2PlusWrapper, consumers}, nil } @@ -805,7 +815,7 @@ func DeployVRFV2PlusDirectFundingContracts( func DirectFundingRequestRandomnessAndWaitForFulfillment( consumer contracts.VRFv2PlusWrapperLoadTestConsumer, coordinator contracts.VRFCoordinatorV2_5, - vrfv2PlusData *VRFV2PlusData, + vrfKeyData *vrfcommon.VRFKeyData, subID *big.Int, isNativeBilling bool, minimumConfirmations uint16, @@ -816,7 +826,19 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { - logRandRequest(l, consumer.Address(), coordinator.Address(), subID, isNativeBilling, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) + logRandRequest( + l, + consumer.Address(), + coordinator.Address(), + subID, + isNativeBilling, + minimumConfirmations, + callbackGasLimit, + numberOfWords, + vrfKeyData.KeyHash, + randomnessRequestCountPerRequest, + randomnessRequestCountPerRequestDeviation, + ) if isNativeBilling { _, err := consumer.RequestRandomnessNative( minimumConfirmations, @@ -845,7 +867,7 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( return WaitForRequestAndFulfillmentEvents( wrapperAddress.String(), coordinator, - vrfv2PlusData, + vrfKeyData, subID, isNativeBilling, randomWordsFulfilledEventTimeout, @@ -856,20 +878,20 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( func WaitForRequestAndFulfillmentEvents( consumerAddress string, coordinator contracts.VRFCoordinatorV2_5, - vrfv2PlusData *VRFV2PlusData, + vrfKeyData *vrfcommon.VRFKeyData, subID *big.Int, isNativeBilling bool, randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfv2PlusData.KeyHash}, + [][32]byte{vrfKeyData.KeyHash}, []*big.Int{subID}, []common.Address{common.HexToAddress(consumerAddress)}, time.Minute*1, ) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsRequestedEvent, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsRequestedEvent, err) } LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, isNativeBilling) @@ -880,7 +902,7 @@ func WaitForRequestAndFulfillmentEvents( randomWordsFulfilledEventTimeout, ) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsFulfilledEvent, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsFulfilledEvent, err) } LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent, isNativeBilling) @@ -986,7 +1008,7 @@ func LogRandomnessRequestedEventUpgraded( Str("Request ID", randomWordsRequestedEvent.RequestId.String()). Str("Subscription ID", randomWordsRequestedEvent.SubId.String()). Str("Sender Address", randomWordsRequestedEvent.Sender.String()). - Interface("Keyhash", randomWordsRequestedEvent.KeyHash). + Interface("Keyhash", fmt.Sprintf("0x%x", randomWordsRequestedEvent.KeyHash)). Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). Uint32("Number of Words", randomWordsRequestedEvent.NumWords). Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). @@ -1014,13 +1036,13 @@ func LogRandomnessRequestedEvent( randomWordsRequestedEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested, isNativeBilling bool, ) { - l.Debug(). + l.Info(). 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). + Interface("Keyhash", fmt.Sprintf("0x%x", randomWordsRequestedEvent.KeyHash)). Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). Uint32("Number of Words", randomWordsRequestedEvent.NumWords). Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). @@ -1033,7 +1055,7 @@ func LogRandomWordsFulfilledEvent( randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, isNativeBilling bool, ) { - l.Debug(). + l.Info(). Bool("Native Billing", isNativeBilling). Str("Coordinator", coordinator.Address()). Str("Total Payment", randomWordsFulfilledEvent.Payment.String()). @@ -1044,16 +1066,16 @@ func LogRandomWordsFulfilledEvent( Msg("RandomWordsFulfilled Event (TX metadata)") } -func LogMigrationCompletedEvent(l zerolog.Logger, migrationCompletedEvent *vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted, vrfv2PlusContracts *VRFV2_5Contracts) { - l.Debug(). +func LogMigrationCompletedEvent(l zerolog.Logger, migrationCompletedEvent *vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted, vrfv2PlusContracts *vrfcommon.VRFContracts) { + l.Info(). Str("Subscription ID", migrationCompletedEvent.SubId.String()). - Str("Migrated From Coordinator", vrfv2PlusContracts.Coordinator.Address()). + Str("Migrated From Coordinator", vrfv2PlusContracts.CoordinatorV2Plus.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(). + l.Info(). Str("New Coordinator", newCoordinator.Address()). Str("Subscription ID", subID.String()). Str("Juels Balance", migratedSubscription.Balance.String()). @@ -1070,7 +1092,7 @@ func LogFulfillmentDetailsLinkBilling( consumerStatus vrfv2plus_wrapper_load_test_consumer.GetRequestStatus, randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, ) { - l.Debug(). + l.Info(). Str("Consumer Balance Before Request (Link)", (*commonassets.Link)(wrapperConsumerJuelsBalanceBeforeRequest).Link()). Str("Consumer Balance After Request (Link)", (*commonassets.Link)(wrapperConsumerJuelsBalanceAfterRequest).Link()). Bool("Fulfilment Status", consumerStatus.Fulfilled). @@ -1091,7 +1113,7 @@ func LogFulfillmentDetailsNativeBilling( consumerStatus vrfv2plus_wrapper_load_test_consumer.GetRequestStatus, randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, ) { - l.Debug(). + l.Info(). Str("Consumer Balance Before Request", assets.FormatWei(wrapperConsumerBalanceBeforeRequestWei)). Str("Consumer Balance After Request", assets.FormatWei(wrapperConsumerBalanceAfterRequestWei)). Bool("Fulfilment Status", consumerStatus.Fulfilled). @@ -1114,9 +1136,10 @@ func logRandRequest( minimumConfirmations uint16, callbackGasLimit uint32, numberOfWords uint32, + keyHash [32]byte, randomnessRequestCountPerRequest uint16, randomnessRequestCountPerRequestDeviation uint16) { - l.Debug(). + l.Info(). Str("Consumer", consumer). Str("Coordinator", coordinator). Str("SubID", subID.String()). @@ -1124,6 +1147,7 @@ func logRandRequest( Uint16("MinimumConfirmations", minimumConfirmations). Uint32("CallbackGasLimit", callbackGasLimit). Uint32("NumberOfWords", numberOfWords). + Str("KeyHash", fmt.Sprintf("0x%x", keyHash)). Uint16("RandomnessRequestCountPerRequest", randomnessRequestCountPerRequest). Uint16("RandomnessRequestCountPerRequestDeviation", randomnessRequestCountPerRequestDeviation). Msg("Requesting randomness") diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go deleted file mode 100644 index 44b62b2663a..00000000000 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go +++ /dev/null @@ -1,51 +0,0 @@ -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 - CLNodeMaxGasPriceGWei int64 `envconfig:"MAX_GAS_PRICE_GWEI" default:"1000"` // Max gas price in GWei for the chainlink node - 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 float64 `envconfig:"SUBSCRIPTION_FUNDING_AMOUNT_LINK" default:"5"` // Amount of LINK to fund the subscription with - SubscriptionFundingAmountNative float64 `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 - FulfillmentFlatFeeLinkDiscountPPM uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_DISCOUNT_PPM" default:"0"` // Discount relative to native flat fee in ppm for native payment - NativePremiumPercentage uint8 `envconfig:"NATIVE_PREMIUM_PERCENTAGE" default:"2"` // Premium percentage for native payment - LinkPremiumPercentage uint8 `envconfig:"LINK_PREMIUM_PERCENTAGE" default:"2"` // Premium percentage for LINK payment - - NumberOfSubToCreate int `envconfig:"NUMBER_OF_SUB_TO_CREATE" default:"1"` // Number of subscriptions to create - - RandomnessRequestCountPerRequest uint16 `envconfig:"RANDOMNESS_REQUEST_COUNT_PER_REQUEST" default:"1"` // How many randomness requests to send per request - RandomnessRequestCountPerRequestDeviation uint16 `envconfig:"RANDOMNESS_REQUEST_COUNT_PER_REQUEST_DEVIATION" default:"0"` // How many randomness requests to send per request - - RandomWordsFulfilledEventTimeout time.Duration `envconfig:"RANDOM_WORDS_FULFILLED_EVENT_TIMEOUT" default:"2m"` // How long to wait for the RandomWordsFulfilled event to be emitted - - //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"` - //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 - LinkAddress string `envconfig:"LINK_ADDRESS" default:""` // Link address - SubID string `envconfig:"SUB_ID" default:""` // Subscription ID - KeyHash string `envconfig:"KEY_HASH" default:""` -} diff --git a/integration-tests/client/chainlink_models.go b/integration-tests/client/chainlink_models.go index 665ff3c7465..320c7a21cc4 100644 --- a/integration-tests/client/chainlink_models.go +++ b/integration-tests/client/chainlink_models.go @@ -1261,14 +1261,18 @@ observationSource = """ // BlockhashStoreJobSpec represents a blockhashstore job type BlockhashStoreJobSpec struct { - Name string `toml:"name"` - CoordinatorV2Address string `toml:"coordinatorV2Address"` // Address of the VRF CoordinatorV2 contract - WaitBlocks int `toml:"waitBlocks"` - LookbackBlocks int `toml:"lookbackBlocks"` - BlockhashStoreAddress string `toml:"blockhashStoreAddress"` - PollPeriod string `toml:"pollPeriod"` - RunTimeout string `toml:"runTimeout"` - EVMChainID string `toml:"evmChainID"` + Name string `toml:"name"` + CoordinatorV2Address string `toml:"coordinatorV2Address"` + CoordinatorV2PlusAddress string `toml:"coordinatorV2PlusAddress"` + BlockhashStoreAddress string `toml:"blockhashStoreAddress"` + ExternalJobID string `toml:"externalJobID"` + FromAddresses []string `toml:"fromAddresses"` + EVMChainID string `toml:"evmChainID"` + ForwardingAllowed bool `toml:"forwardingAllowed"` + PollPeriod time.Duration `toml:"pollPeriod"` + RunTimeout time.Duration `toml:"runTimeout"` + WaitBlocks int `toml:"waitBlocks"` + LookbackBlocks int `toml:"lookbackBlocks"` } // Type returns the type of the job @@ -1280,13 +1284,17 @@ func (b *BlockhashStoreJobSpec) String() (string, error) { type = "blockhashstore" schemaVersion = 1 name = "{{.Name}}" -coordinatorV2Address = "{{.CoordinatorV2Address}}" -waitBlocks = {{.WaitBlocks}} -lookbackBlocks = {{.LookbackBlocks}} -blockhashStoreAddress = "{{.BlockhashStoreAddress}}" -pollPeriod = "{{.PollPeriod}}" -runTimeout = "{{.RunTimeout}}" +forwardingAllowed = {{.ForwardingAllowed}} +coordinatorV2Address = "{{.CoordinatorV2Address}}" +coordinatorV2PlusAddress = "{{.CoordinatorV2PlusAddress}}" +blockhashStoreAddress = "{{.BlockhashStoreAddress}}" +fromAddresses = [{{range .FromAddresses}}"{{.}}",{{end}}] evmChainID = "{{.EVMChainID}}" +externalJobID = "{{.ExternalJobID}}" +waitBlocks = {{.WaitBlocks}} +lookbackBlocks = {{.LookbackBlocks}} +pollPeriod = "{{.PollPeriod}}" +runTimeout = "{{.RunTimeout}}" ` return MarshallTemplate(b, "BlockhashStore Job", vrfTemplateString) } diff --git a/integration-tests/contracts/contract_models.go b/integration-tests/contracts/contract_models.go index 3d738033d68..3409dc75d6e 100644 --- a/integration-tests/contracts/contract_models.go +++ b/integration-tests/contracts/contract_models.go @@ -210,6 +210,7 @@ type MockGasFeed interface { type BlockHashStore interface { Address() string + GetBlockHash(ctx context.Context, blockNumber *big.Int) ([32]byte, error) } type Staking interface { diff --git a/integration-tests/contracts/ethereum_vrf_contracts.go b/integration-tests/contracts/ethereum_vrf_contracts.go index 427ac4ccbf8..ea8a4f94817 100644 --- a/integration-tests/contracts/ethereum_vrf_contracts.go +++ b/integration-tests/contracts/ethereum_vrf_contracts.go @@ -134,6 +134,18 @@ func (v *EthereumBlockhashStore) Address() string { return v.address.Hex() } +func (v *EthereumBlockhashStore) GetBlockHash(ctx context.Context, blockNumber *big.Int) ([32]byte, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + } + blockHash, err := v.blockHashStore.GetBlockhash(opts, blockNumber) + if err != nil { + return [32]byte{}, err + } + return blockHash, nil +} + func (v *EthereumVRFCoordinator) Address() string { return v.address.Hex() } diff --git a/integration-tests/load/vrfv2/gun.go b/integration-tests/load/vrfv2/gun.go index 4746c73081a..9bf34f70b92 100644 --- a/integration-tests/load/vrfv2/gun.go +++ b/integration-tests/load/vrfv2/gun.go @@ -6,6 +6,7 @@ import ( "github.com/rs/zerolog" "github.com/smartcontractkit/wasp" + vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2" "github.com/smartcontractkit/chainlink/integration-tests/types" ) @@ -13,7 +14,7 @@ import ( /* SingleHashGun is a gun that constantly requests randomness for one feed */ type SingleHashGun struct { - contracts *vrfv2.VRFV2Contracts + contracts *vrfcommon.VRFContracts keyHash [32]byte subIDs []uint64 testConfig types.VRFv2TestConfig @@ -21,7 +22,7 @@ type SingleHashGun struct { } func NewSingleHashGun( - contracts *vrfv2.VRFV2Contracts, + contracts *vrfcommon.VRFContracts, keyHash [32]byte, subIDs []uint64, testConfig types.VRFv2TestConfig, @@ -46,11 +47,11 @@ func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.Response { _, err := vrfv2.RequestRandomnessAndWaitForFulfillment( m.logger, //the same consumer is used for all requests and in all subs - m.contracts.LoadTestConsumers[0], - m.contracts.Coordinator, + m.contracts.VRFV2Consumer[0], + m.contracts.CoordinatorV2, //randomly pick a subID from pool of subIDs m.subIDs[randInRange(0, len(m.subIDs)-1)], - &vrfv2.VRFV2Data{VRFV2KeyData: vrfv2.VRFV2KeyData{KeyHash: m.keyHash}}, + &vrfcommon.VRFKeyData{KeyHash: m.keyHash}, *vrfv2Config.MinimumConfirmations, *vrfv2Config.CallbackGasLimit, *vrfv2Config.NumberOfWords, diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go index 3a29e729dea..5eae49058cb 100644 --- a/integration-tests/load/vrfv2/vrfv2_test.go +++ b/integration-tests/load/vrfv2/vrfv2_test.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" "github.com/smartcontractkit/chainlink/integration-tests/actions" + vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2" "github.com/smartcontractkit/chainlink/integration-tests/contracts" @@ -29,8 +30,8 @@ import ( var ( env *test_env.CLClusterTestEnv - vrfv2Contracts *vrfv2.VRFV2Contracts - vrfv2Data *vrfv2.VRFV2Data + vrfContracts *vrfcommon.VRFContracts + vrfKeyData *vrfcommon.VRFKeyData subIDs []uint64 eoaWalletAddress string @@ -87,7 +88,7 @@ func TestVRFV2Performance(t *testing.T) { WithTestConfig(&testConfig). WithCustomCleanup( func() { - teardown(t, vrfv2Contracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, string(testType), &testConfig) + teardown(t, vrfContracts.VRFV2Consumer[0], lc, updatedLabels, testReporter, string(testType), &testConfig) if env.EVMClient.NetworkSimulated() { l.Info(). Str("Network Name", env.EVMClient.GetNetworkName()). @@ -113,7 +114,7 @@ func TestVRFV2Performance(t *testing.T) { consumers, err = vrfv2.DeployVRFV2Consumers(env.ContractDeployer, coordinator.Address(), 1) require.NoError(t, err) err = env.EVMClient.WaitForEvents() - require.NoError(t, err, vrfv2.ErrWaitTXsComplete) + require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) l.Info(). Str("Coordinator", *cfg.ExistingEnvConfig.CoordinatorAddress). Int("Number of Subs to create", *vrfv2Config.General.NumberOfSubToCreate). @@ -137,21 +138,16 @@ func TestVRFV2Performance(t *testing.T) { err = FundNodesIfNeeded(&testConfig, env.EVMClient, l) require.NoError(t, err) - vrfv2Contracts = &vrfv2.VRFV2Contracts{ - Coordinator: coordinator, - LoadTestConsumers: consumers, - BHS: nil, + vrfContracts = &vrfcommon.VRFContracts{ + CoordinatorV2: coordinator, + VRFV2Consumer: consumers, + BHS: nil, } - vrfv2Data = &vrfv2.VRFV2Data{ - VRFV2KeyData: vrfv2.VRFV2KeyData{ - VRFKey: nil, - EncodedProvingKey: [2]*big.Int{}, - KeyHash: common.HexToHash(*vrfv2Config.Performance.KeyHash), - }, - VRFJob: nil, - PrimaryEthAddress: "", - ChainID: nil, + vrfKeyData = &vrfcommon.VRFKeyData{ + VRFKey: nil, + EncodedProvingKey: [2]*big.Int{}, + KeyHash: common.HexToHash(*vrfv2Config.Performance.KeyHash), } } else { @@ -169,7 +165,7 @@ func TestVRFV2Performance(t *testing.T) { WithFunding(big.NewFloat(*testConfig.Common.ChainlinkNodeFunding)). WithCustomCleanup( func() { - teardown(t, vrfv2Contracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, string(testType), &testConfig) + teardown(t, vrfContracts.VRFV2Consumer[0], lc, updatedLabels, testReporter, string(testType), &testConfig) if env.EVMClient.NetworkSimulated() { l.Info(). @@ -200,8 +196,9 @@ func TestVRFV2Performance(t *testing.T) { useVRFOwner := true useTestCoordinator := true - vrfv2Contracts, subIDs, vrfv2Data, err = vrfv2.SetupVRFV2Environment( + vrfContracts, subIDs, vrfKeyData, _, err = vrfv2.SetupVRFV2Environment( env, + []vrfcommon.VRFNodeType{vrfcommon.VRF}, &testConfig, useVRFOwner, useTestCoordinator, @@ -220,9 +217,9 @@ func TestVRFV2Performance(t *testing.T) { l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") for _, subID := range subIDs { - subscription, err := vrfv2Contracts.Coordinator.GetSubscription(context.Background(), subID) + subscription, err := vrfContracts.CoordinatorV2.GetSubscription(context.Background(), subID) require.NoError(t, err, "error getting subscription information for subscription %d", subID) - vrfv2.LogSubDetails(l, subscription, subID, vrfv2Contracts.Coordinator) + vrfv2.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2) } singleFeedConfig := &wasp.Config{ @@ -231,8 +228,8 @@ func TestVRFV2Performance(t *testing.T) { GenName: "gun", RateLimitUnitDuration: vrfv2Config.Performance.RateLimitUnitDuration.Duration, Gun: NewSingleHashGun( - vrfv2Contracts, - vrfv2Data.KeyHash, + vrfContracts, + vrfKeyData.KeyHash, subIDs, &testConfig, l, @@ -241,8 +238,8 @@ func TestVRFV2Performance(t *testing.T) { LokiConfig: lokiConfig, CallTimeout: 2 * time.Minute, } - require.Len(t, vrfv2Contracts.LoadTestConsumers, 1, "only one consumer should be created for Load Test") - consumer := vrfv2Contracts.LoadTestConsumers[0] + require.Len(t, vrfContracts.VRFV2Consumer, 1, "only one consumer should be created for Load Test") + consumer := vrfContracts.VRFV2Consumer[0] err = consumer.ResetMetrics() require.NoError(t, err) MonitorLoadStats(lc, consumer, updatedLabels) @@ -280,12 +277,12 @@ func cancelSubsAndReturnFunds(subIDs []uint64, l zerolog.Logger) { Uint64("Returning funds from SubID", subID). Str("Returning funds to", eoaWalletAddress). Msg("Canceling subscription and returning funds to subscription owner") - pendingRequestsExist, err := vrfv2Contracts.Coordinator.PendingRequestsExist(context.Background(), subID) + pendingRequestsExist, err := vrfContracts.CoordinatorV2.PendingRequestsExist(context.Background(), subID) if err != nil { l.Error().Err(err).Msg("Error checking if pending requests exist") } if !pendingRequestsExist { - _, err := vrfv2Contracts.Coordinator.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) + _, err := vrfContracts.CoordinatorV2.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) if err != nil { l.Error().Err(err).Msg("Error canceling subscription") } diff --git a/integration-tests/load/vrfv2plus/gun.go b/integration-tests/load/vrfv2plus/gun.go index faf5e6ef211..bfd8ff868b5 100644 --- a/integration-tests/load/vrfv2plus/gun.go +++ b/integration-tests/load/vrfv2plus/gun.go @@ -8,6 +8,7 @@ import ( "github.com/rs/zerolog" "github.com/smartcontractkit/wasp" + vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2plus" vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" "github.com/smartcontractkit/chainlink/integration-tests/types" @@ -16,7 +17,7 @@ import ( /* SingleHashGun is a gun that constantly requests randomness for one feed */ type SingleHashGun struct { - contracts *vrfv2plus.VRFV2_5Contracts + contracts *vrfcommon.VRFContracts keyHash [32]byte subIDs []*big.Int testConfig types.VRFv2PlusTestConfig @@ -24,7 +25,7 @@ type SingleHashGun struct { } func NewSingleHashGun( - contracts *vrfv2plus.VRFV2_5Contracts, + contracts *vrfcommon.VRFContracts, keyHash [32]byte, subIDs []*big.Int, testConfig types.VRFv2PlusTestConfig, @@ -52,9 +53,9 @@ func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.Response { randomnessRequestCountPerRequest := deviateValue(*m.testConfig.GetVRFv2PlusConfig().General.RandomnessRequestCountPerRequest, *m.testConfig.GetVRFv2PlusConfig().General.RandomnessRequestCountPerRequestDeviation) _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( //the same consumer is used for all requests and in all subs - m.contracts.LoadTestConsumers[0], - m.contracts.Coordinator, - &vrfv2plus.VRFV2PlusData{VRFV2PlusKeyData: vrfv2plus.VRFV2PlusKeyData{KeyHash: m.keyHash}}, + m.contracts.VRFV2PlusConsumer[0], + m.contracts.CoordinatorV2Plus, + &vrfcommon.VRFKeyData{KeyHash: m.keyHash}, //randomly pick a subID from pool of subIDs m.subIDs[randInRange(0, len(m.subIDs)-1)], //randomly pick payment type diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index 51a3116dca2..877c5b3d1b7 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -21,6 +21,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/testreporters" "github.com/smartcontractkit/chainlink/integration-tests/actions" + vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" @@ -29,11 +30,11 @@ import ( ) var ( - env *test_env.CLClusterTestEnv - vrfv2PlusContracts *vrfv2plus.VRFV2_5Contracts - vrfv2PlusData *vrfv2plus.VRFV2PlusData - subIDs []*big.Int - eoaWalletAddress string + env *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + vrfv2PlusData *vrfcommon.VRFKeyData + subIDs []*big.Int + eoaWalletAddress string labels = map[string]string{ "branch": "vrfv2Plus_healthcheck", @@ -86,7 +87,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { WithTestConfig(&testConfig). WithCustomCleanup( func() { - teardown(t, vrfv2PlusContracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, string(testType), &testConfig) + teardown(t, vrfContracts.VRFV2PlusConsumer[0], lc, updatedLabels, testReporter, string(testType), &testConfig) if env.EVMClient.NetworkSimulated() { l.Info(). Str("Network Name", env.EVMClient.GetNetworkName()). @@ -112,7 +113,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { consumers, err = vrfv2plus.DeployVRFV2PlusConsumers(env.ContractDeployer, coordinator, 1) require.NoError(t, err) err = env.EVMClient.WaitForEvents() - require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) + require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) l.Info(). Str("Coordinator", *vrfv2PlusConfig.Performance.CoordinatorAddress). Int("Number of Subs to create", *vrfv2PlusConfig.General.NumberOfSubToCreate). @@ -141,21 +142,16 @@ func TestVRFV2PlusPerformance(t *testing.T) { err = FundNodesIfNeeded(&testConfig, env.EVMClient, l) require.NoError(t, err) - vrfv2PlusContracts = &vrfv2plus.VRFV2_5Contracts{ - Coordinator: coordinator, - LoadTestConsumers: consumers, + vrfContracts = &vrfcommon.VRFContracts{ + CoordinatorV2Plus: coordinator, + VRFV2PlusConsumer: consumers, BHS: nil, } - vrfv2PlusData = &vrfv2plus.VRFV2PlusData{ - VRFV2PlusKeyData: vrfv2plus.VRFV2PlusKeyData{ - VRFKey: nil, - EncodedProvingKey: [2]*big.Int{}, - KeyHash: common.HexToHash(*vrfv2PlusConfig.Performance.KeyHash), - }, - VRFJob: nil, - PrimaryEthAddress: "", - ChainID: nil, + vrfv2PlusData = &vrfcommon.VRFKeyData{ + VRFKey: nil, + EncodedProvingKey: [2]*big.Int{}, + KeyHash: common.HexToHash(*vrfv2PlusConfig.Performance.KeyHash), } } else { @@ -174,7 +170,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { WithFunding(big.NewFloat(*testConfig.Common.ChainlinkNodeFunding)). WithCustomCleanup( func() { - teardown(t, vrfv2PlusContracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, string(testType), &testConfig) + teardown(t, vrfContracts.VRFV2PlusConsumer[0], lc, updatedLabels, testReporter, string(testType), &testConfig) if env.EVMClient.NetworkSimulated() { l.Info(). @@ -202,8 +198,9 @@ func TestVRFV2PlusPerformance(t *testing.T) { linkToken, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err, "error deploying LINK contract") - vrfv2PlusContracts, subIDs, vrfv2PlusData, err = vrfv2plus.SetupVRFV2_5Environment( + vrfContracts, subIDs, vrfv2PlusData, _, err = vrfv2plus.SetupVRFV2_5Environment( env, + []vrfcommon.VRFNodeType{vrfcommon.VRF}, &testConfig, linkToken, mockETHLinkFeed, @@ -218,9 +215,9 @@ func TestVRFV2PlusPerformance(t *testing.T) { l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") for _, subID := range subIDs { - subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subID) + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information for subscription %s", subID.String()) - vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) + vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) } singleFeedConfig := &wasp.Config{ @@ -229,7 +226,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { GenName: "gun", RateLimitUnitDuration: vrfv2PlusConfig.Performance.RateLimitUnitDuration.Duration, Gun: NewSingleHashGun( - vrfv2PlusContracts, + vrfContracts, vrfv2PlusData.KeyHash, subIDs, &testConfig, @@ -239,8 +236,8 @@ func TestVRFV2PlusPerformance(t *testing.T) { LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), CallTimeout: 2 * time.Minute, } - require.Len(t, vrfv2PlusContracts.LoadTestConsumers, 1, "only one consumer should be created for Load Test") - consumer := vrfv2PlusContracts.LoadTestConsumers[0] + require.Len(t, vrfContracts.VRFV2PlusConsumer, 1, "only one consumer should be created for Load Test") + consumer := vrfContracts.VRFV2PlusConsumer[0] err = consumer.ResetMetrics() require.NoError(t, err) MonitorLoadStats(lc, consumer, updatedLabels) @@ -277,12 +274,12 @@ func cancelSubsAndReturnFunds(subIDs []*big.Int, l zerolog.Logger) { Str("Returning funds from SubID", subID.String()). Str("Returning funds to", eoaWalletAddress). Msg("Canceling subscription and returning funds to subscription owner") - pendingRequestsExist, err := vrfv2PlusContracts.Coordinator.PendingRequestsExist(context.Background(), subID) + pendingRequestsExist, err := vrfContracts.CoordinatorV2Plus.PendingRequestsExist(context.Background(), subID) if err != nil { l.Error().Err(err).Msg("Error checking if pending requests exist") } if !pendingRequestsExist { - _, err := vrfv2PlusContracts.Coordinator.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) + _, err := vrfContracts.CoordinatorV2Plus.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) if err != nil { l.Error().Err(err).Msg("Error canceling subscription") } diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index e4ff1600649..c289cd019c1 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -1,28 +1,32 @@ package smoke import ( - "context" + "fmt" "math/big" + "strings" + "sync" "testing" "time" "github.com/ethereum/go-ethereum/common" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" + "github.com/onsi/gomega" "github.com/stretchr/testify/require" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - "github.com/smartcontractkit/chainlink/integration-tests/actions" + vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2" + "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" ) func TestVRFv2Basic(t *testing.T) { @@ -58,8 +62,9 @@ func TestVRFv2Basic(t *testing.T) { defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() numberOfTxKeysToCreate := 1 - vrfv2Contracts, subIDs, vrfv2Data, err := vrfv2.SetupVRFV2Environment( + vrfv2Contracts, subIDs, vrfv2KeyData, nodesMap, err := vrfv2.SetupVRFV2Environment( env, + []vrfcommon.VRFNodeType{vrfcommon.VRF}, &config, useVRFOwner, useTestCoordinator, @@ -75,25 +80,25 @@ func TestVRFv2Basic(t *testing.T) { subID := subIDs[0] - subscription, err := vrfv2Contracts.Coordinator.GetSubscription(context.Background(), subID) + subscription, err := vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2.LogSubDetails(l, subscription, subID, vrfv2Contracts.Coordinator) + vrfv2.LogSubDetails(l, subscription, subID, vrfv2Contracts.CoordinatorV2) t.Run("Request Randomness", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) subBalanceBeforeRequest := subscription.Balance - jobRunsBeforeTest, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfv2Data.VRFJob.Data.ID) + jobRunsBeforeTest, err := nodesMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) require.NoError(t, err, "error reading job runs") // test and assert randomWordsFulfilledEvent, err := vrfv2.RequestRandomnessAndWaitForFulfillment( l, - vrfv2Contracts.LoadTestConsumers[0], - vrfv2Contracts.Coordinator, + vrfv2Contracts.VRFV2Consumer[0], + vrfv2Contracts.CoordinatorV2, subID, - vrfv2Data, + vrfv2KeyData, *configCopy.VRFv2.General.MinimumConfirmations, *configCopy.VRFv2.General.CallbackGasLimit, *configCopy.VRFv2.General.NumberOfWords, @@ -104,16 +109,16 @@ func TestVRFv2Basic(t *testing.T) { require.NoError(t, err, "error requesting randomness and waiting for fulfilment") expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - subscription, err = vrfv2Contracts.Coordinator.GetSubscription(context.Background(), subID) + subscription, err = vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") subBalanceAfterRequest := subscription.Balance require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) - jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfv2Data.VRFJob.Data.ID) + jobRuns, err := nodesMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) require.NoError(t, err, "error reading job runs") require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) - status, err := vrfv2Contracts.LoadTestConsumers[0].GetRequestStatus(context.Background(), randomWordsFulfilledEvent.RequestId) + status, err := vrfv2Contracts.VRFV2Consumer[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") @@ -132,8 +137,8 @@ func TestVRFv2Basic(t *testing.T) { &configCopy, linkToken, mockETHLinkFeed, - vrfv2Contracts.Coordinator, - vrfv2Data.KeyHash, + vrfv2Contracts.CoordinatorV2, + vrfv2KeyData.KeyHash, 1, ) require.NoError(t, err) @@ -142,7 +147,7 @@ func TestVRFv2Basic(t *testing.T) { wrapperConsumerJuelsBalanceBeforeRequest, err := linkToken.BalanceOf(testcontext.Get(t), wrapperConsumer.Address()) require.NoError(t, err, "Error getting wrapper consumer balance") - wrapperSubscription, err := vrfv2Contracts.Coordinator.GetSubscription(testcontext.Get(t), *wrapperSubID) + wrapperSubscription, err := vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), *wrapperSubID) require.NoError(t, err, "Error getting subscription information") subBalanceBeforeRequest := wrapperSubscription.Balance @@ -150,9 +155,9 @@ func TestVRFv2Basic(t *testing.T) { randomWordsFulfilledEvent, err := vrfv2.DirectFundingRequestRandomnessAndWaitForFulfillment( l, wrapperConsumer, - vrfv2Contracts.Coordinator, + vrfv2Contracts.CoordinatorV2, *wrapperSubID, - vrfv2Data, + vrfv2KeyData, *configCopy.VRFv2.General.MinimumConfirmations, *configCopy.VRFv2.General.CallbackGasLimit, *configCopy.VRFv2.General.NumberOfWords, @@ -164,7 +169,7 @@ func TestVRFv2Basic(t *testing.T) { // Check wrapper subscription balance expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - wrapperSubscription, err = vrfv2Contracts.Coordinator.GetSubscription(testcontext.Get(t), *wrapperSubID) + wrapperSubscription, err = vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), *wrapperSubID) require.NoError(t, err, "Error getting subscription information") subBalanceAfterRequest := wrapperSubscription.Balance require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) @@ -207,8 +212,8 @@ func TestVRFv2Basic(t *testing.T) { env, big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), linkToken, - vrfv2Contracts.Coordinator, - vrfv2Contracts.LoadTestConsumers, + vrfv2Contracts.CoordinatorV2, + vrfv2Contracts.VRFV2Consumer, 1, ) require.NoError(t, err) @@ -217,10 +222,10 @@ func TestVRFv2Basic(t *testing.T) { fulfilledEventLink, err := vrfv2.RequestRandomnessAndWaitForFulfillment( l, - vrfv2Contracts.LoadTestConsumers[0], - vrfv2Contracts.Coordinator, + vrfv2Contracts.VRFV2Consumer[0], + vrfv2Contracts.CoordinatorV2, subIDForOracleWithdraw, - vrfv2Data, + vrfv2KeyData, *configCopy.VRFv2.General.MinimumConfirmations, *configCopy.VRFv2.General.CallbackGasLimit, *configCopy.VRFv2.General.NumberOfWords, @@ -240,11 +245,11 @@ func TestVRFv2Basic(t *testing.T) { Str("Amount", amountToWithdrawLink.String()). Msg("Invoking Oracle Withdraw for LINK") - err = vrfv2Contracts.Coordinator.OracleWithdraw(common.HexToAddress(defaultWalletAddress), amountToWithdrawLink) + err = vrfv2Contracts.CoordinatorV2.OracleWithdraw(common.HexToAddress(defaultWalletAddress), amountToWithdrawLink) require.NoError(t, err, "Error withdrawing LINK from coordinator to default wallet") err = env.EVMClient.WaitForEvents() - require.NoError(t, err, vrfv2.ErrWaitTXsComplete) + require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) defaultWalletBalanceLinkAfterOracleWithdraw, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) require.NoError(t, err) @@ -263,8 +268,8 @@ func TestVRFv2Basic(t *testing.T) { env, big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), linkToken, - vrfv2Contracts.Coordinator, - vrfv2Contracts.LoadTestConsumers, + vrfv2Contracts.CoordinatorV2, + vrfv2Contracts.VRFV2Consumer, 1, ) require.NoError(t, err) @@ -276,7 +281,7 @@ func TestVRFv2Basic(t *testing.T) { testWalletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), testWalletAddress.String()) require.NoError(t, err) - subscriptionForCancelling, err := vrfv2Contracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) + subscriptionForCancelling, err := vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForCancelling) require.NoError(t, err, "error getting subscription information") subBalanceLink := subscriptionForCancelling.Balance @@ -287,10 +292,10 @@ func TestVRFv2Basic(t *testing.T) { Str("Returning funds to", testWalletAddress.String()). Msg("Canceling subscription and returning funds to subscription owner") - tx, err := vrfv2Contracts.Coordinator.CancelSubscription(subIDForCancelling, testWalletAddress) + tx, err := vrfv2Contracts.CoordinatorV2.CancelSubscription(subIDForCancelling, testWalletAddress) require.NoError(t, err, "Error canceling subscription") - subscriptionCanceledEvent, err := vrfv2Contracts.Coordinator.WaitForSubscriptionCanceledEvent([]uint64{subIDForCancelling}, time.Second*30) + subscriptionCanceledEvent, err := vrfv2Contracts.CoordinatorV2.WaitForSubscriptionCanceledEvent([]uint64{subIDForCancelling}, time.Second*30) require.NoError(t, err, "error waiting for subscription canceled event") cancellationTxReceipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) @@ -317,7 +322,7 @@ func TestVRFv2Basic(t *testing.T) { require.NoError(t, err) //Verify that sub was deleted from Coordinator - _, err = vrfv2Contracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) + _, err = vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForCancelling) require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") subFundsReturnedLinkActual := new(big.Int).Sub(testWalletBalanceLinkAfterSubCancelling, testWalletBalanceLinkBeforeSubCancelling) @@ -340,22 +345,22 @@ func TestVRFv2Basic(t *testing.T) { env, big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), linkToken, - vrfv2Contracts.Coordinator, - vrfv2Contracts.LoadTestConsumers, + vrfv2Contracts.CoordinatorV2, + vrfv2Contracts.VRFV2Consumer, 1, ) require.NoError(t, err) subIDForCancelling := subIDsForCancelling[0] - subscriptionForCancelling, err := vrfv2Contracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) + subscriptionForCancelling, err := vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForCancelling) require.NoError(t, err, "Error getting subscription information") - vrfv2.LogSubDetails(l, subscriptionForCancelling, subIDForCancelling, vrfv2Contracts.Coordinator) + vrfv2.LogSubDetails(l, subscriptionForCancelling, subIDForCancelling, vrfv2Contracts.CoordinatorV2) // No GetActiveSubscriptionIds function available - skipping check - pendingRequestsExist, err := vrfv2Contracts.Coordinator.PendingRequestsExist(testcontext.Get(t), subIDForCancelling) + pendingRequestsExist, err := vrfv2Contracts.CoordinatorV2.PendingRequestsExist(testcontext.Get(t), subIDForCancelling) require.NoError(t, err) require.False(t, pendingRequestsExist, "Pending requests should not exist") @@ -363,10 +368,10 @@ func TestVRFv2Basic(t *testing.T) { randomWordsFulfilledEventTimeout := 5 * time.Second _, err = vrfv2.RequestRandomnessAndWaitForFulfillment( l, - vrfv2Contracts.LoadTestConsumers[0], - vrfv2Contracts.Coordinator, + vrfv2Contracts.VRFV2Consumer[0], + vrfv2Contracts.CoordinatorV2, subIDForCancelling, - vrfv2Data, + vrfv2KeyData, *configCopy.VRFv2.General.MinimumConfirmations, *configCopy.VRFv2.General.CallbackGasLimit, *configCopy.VRFv2.General.NumberOfWords, @@ -376,14 +381,14 @@ func TestVRFv2Basic(t *testing.T) { ) require.Error(t, err, "Error should occur while waiting for fulfilment due to low sub balance") - pendingRequestsExist, err = vrfv2Contracts.Coordinator.PendingRequestsExist(testcontext.Get(t), subIDForCancelling) + pendingRequestsExist, err = vrfv2Contracts.CoordinatorV2.PendingRequestsExist(testcontext.Get(t), subIDForCancelling) require.NoError(t, err) require.True(t, pendingRequestsExist, "Pending requests should exist after unfilfulled requests due to low sub balance") walletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) require.NoError(t, err) - subscriptionForCancelling, err = vrfv2Contracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) + subscriptionForCancelling, err = vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForCancelling) require.NoError(t, err, "Error getting subscription information") subBalanceLink := subscriptionForCancelling.Balance @@ -394,10 +399,10 @@ func TestVRFv2Basic(t *testing.T) { Msg("Canceling subscription and returning funds to subscription owner") // Call OwnerCancelSubscription - tx, err := vrfv2Contracts.Coordinator.OwnerCancelSubscription(subIDForCancelling) + tx, err := vrfv2Contracts.CoordinatorV2.OwnerCancelSubscription(subIDForCancelling) require.NoError(t, err, "Error canceling subscription") - subscriptionCanceledEvent, err := vrfv2Contracts.Coordinator.WaitForSubscriptionCanceledEvent([]uint64{subIDForCancelling}, time.Second*30) + subscriptionCanceledEvent, err := vrfv2Contracts.CoordinatorV2.WaitForSubscriptionCanceledEvent([]uint64{subIDForCancelling}, time.Second*30) require.NoError(t, err, "error waiting for subscription canceled event") cancellationTxReceipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) @@ -424,7 +429,7 @@ func TestVRFv2Basic(t *testing.T) { require.NoError(t, err) // Verify that subscription was deleted from Coordinator contract - _, err = vrfv2Contracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) + _, err = vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForCancelling) l.Info(). Str("Expected error message", err.Error()) require.Error(t, err, "Error did not occur when fetching deleted subscription from the Coordinator after owner cancelation") @@ -481,8 +486,9 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() numberOfTxKeysToCreate := 2 - vrfv2Contracts, subIDs, vrfv2Data, err := vrfv2.SetupVRFV2Environment( + vrfv2Contracts, subIDs, vrfv2KeyData, nodesMap, err := vrfv2.SetupVRFV2Environment( env, + []vrfcommon.VRFNodeType{vrfcommon.VRF}, &config, useVRFOwner, useTestCoordinator, @@ -498,13 +504,13 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { subID := subIDs[0] - subscription, err := vrfv2Contracts.Coordinator.GetSubscription(context.Background(), subID) + subscription, err := vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2.LogSubDetails(l, subscription, subID, vrfv2Contracts.Coordinator) + vrfv2.LogSubDetails(l, subscription, subID, vrfv2Contracts.CoordinatorV2) t.Run("Request Randomness with multiple sending keys", func(t *testing.T) { - txKeys, _, err := env.ClCluster.Nodes[0].API.ReadTxKeys("evm") + txKeys, _, err := nodesMap[vrfcommon.VRF].CLNode.API.ReadTxKeys("evm") require.NoError(t, err, "error reading tx keys") require.Equal(t, numberOfTxKeysToCreate+1, len(txKeys.Data)) @@ -513,10 +519,10 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { for i := 0; i < numberOfTxKeysToCreate+1; i++ { randomWordsFulfilledEvent, err := vrfv2.RequestRandomnessAndWaitForFulfillment( l, - vrfv2Contracts.LoadTestConsumers[0], - vrfv2Contracts.Coordinator, + vrfv2Contracts.VRFV2Consumer[0], + vrfv2Contracts.CoordinatorV2, subID, - vrfv2Data, + vrfv2KeyData, *config.VRFv2.General.MinimumConfirmations, *config.VRFv2.General.CallbackGasLimit, *config.VRFv2.General.NumberOfWords, @@ -528,7 +534,7 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { //todo - move TransactionByHash to EVMClient in CTF fulfillmentTx, _, err := env.EVMClient.(*blockchain.EthereumMultinodeClient).DefaultClient.(*blockchain.EthereumClient). - Client.TransactionByHash(context.Background(), randomWordsFulfilledEvent.Raw.TxHash) + Client.TransactionByHash(testcontext.Get(t), randomWordsFulfilledEvent.Raw.TxHash) require.NoError(t, err, "error getting tx from hash") fulfillmentTxFromAddress, err := actions.GetTxFromAddress(fulfillmentTx) require.NoError(t, err, "error getting tx from address") @@ -579,8 +585,9 @@ func TestVRFOwner(t *testing.T) { defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() numberOfTxKeysToCreate := 1 - vrfv2Contracts, subIDs, vrfv2Data, err := vrfv2.SetupVRFV2Environment( + vrfv2Contracts, subIDs, vrfv2Data, _, err := vrfv2.SetupVRFV2Environment( env, + []vrfcommon.VRFNodeType{vrfcommon.VRF}, &config, useVRFOwner, useTestCoordinator, @@ -596,44 +603,44 @@ func TestVRFOwner(t *testing.T) { subID := subIDs[0] - subscription, err := vrfv2Contracts.Coordinator.GetSubscription(context.Background(), subID) + subscription, err := vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2.LogSubDetails(l, subscription, subID, vrfv2Contracts.Coordinator) + vrfv2.LogSubDetails(l, subscription, subID, vrfv2Contracts.CoordinatorV2) t.Run("Request Randomness With Force-Fulfill", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) - vrfCoordinatorOwner, err := vrfv2Contracts.Coordinator.GetOwner(testcontext.Get(t)) + vrfCoordinatorOwner, err := vrfv2Contracts.CoordinatorV2.GetOwner(testcontext.Get(t)) require.NoError(t, err) require.Equal(t, vrfv2Contracts.VRFOwner.Address(), vrfCoordinatorOwner.String()) err = linkToken.Transfer( - vrfv2Contracts.LoadTestConsumers[0].Address(), + vrfv2Contracts.VRFV2Consumer[0].Address(), conversions.EtherToWei(big.NewFloat(5)), ) require.NoError(t, err, "error transferring link to consumer contract") err = env.EVMClient.WaitForEvents() - require.NoError(t, err, vrfv2.ErrWaitTXsComplete) + require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - consumerLinkBalance, err := linkToken.BalanceOf(testcontext.Get(t), vrfv2Contracts.LoadTestConsumers[0].Address()) + consumerLinkBalance, err := linkToken.BalanceOf(testcontext.Get(t), vrfv2Contracts.VRFV2Consumer[0].Address()) require.NoError(t, err, "error getting consumer link balance") l.Info(). Str("Balance", conversions.WeiToEther(consumerLinkBalance).String()). - Str("Consumer", vrfv2Contracts.LoadTestConsumers[0].Address()). + Str("Consumer", vrfv2Contracts.VRFV2Consumer[0].Address()). Msg("Consumer Link Balance") err = mockETHLinkFeed.SetBlockTimestampDeduction(big.NewInt(3)) require.NoError(t, err) err = env.EVMClient.WaitForEvents() - require.NoError(t, err, vrfv2.ErrWaitTXsComplete) + require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) // test and assert _, randFulfilledEvent, _, err := vrfv2.RequestRandomnessWithForceFulfillAndWaitForFulfillment( l, - vrfv2Contracts.LoadTestConsumers[0], - vrfv2Contracts.Coordinator, + vrfv2Contracts.VRFV2Consumer[0], + vrfv2Contracts.CoordinatorV2, vrfv2Contracts.VRFOwner, vrfv2Data, *configCopy.VRFv2.General.MinimumConfirmations, @@ -648,7 +655,7 @@ func TestVRFOwner(t *testing.T) { require.NoError(t, err, "error requesting randomness with force-fulfillment and waiting for fulfilment") require.Equal(t, 0, randFulfilledEvent.Payment.Cmp(big.NewInt(0)), "Forced Fulfilled Randomness's Payment should be 0") - status, err := vrfv2Contracts.LoadTestConsumers[0].GetRequestStatus(context.Background(), randFulfilledEvent.RequestId) + status, err := vrfv2Contracts.VRFV2Consumer[0].GetRequestStatus(testcontext.Get(t), randFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") @@ -659,13 +666,13 @@ func TestVRFOwner(t *testing.T) { require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") } - coordinatorConfig, err := vrfv2Contracts.Coordinator.GetConfig(testcontext.Get(t)) + coordinatorConfig, err := vrfv2Contracts.CoordinatorV2.GetConfig(testcontext.Get(t)) require.NoError(t, err, "error getting coordinator config") - coordinatorFeeConfig, err := vrfv2Contracts.Coordinator.GetFeeConfig(testcontext.Get(t)) + coordinatorFeeConfig, err := vrfv2Contracts.CoordinatorV2.GetFeeConfig(testcontext.Get(t)) require.NoError(t, err, "error getting coordinator fee config") - coordinatorFallbackWeiPerUnitLinkConfig, err := vrfv2Contracts.Coordinator.GetFallbackWeiPerUnitLink(testcontext.Get(t)) + coordinatorFallbackWeiPerUnitLinkConfig, err := vrfv2Contracts.CoordinatorV2.GetFallbackWeiPerUnitLink(testcontext.Get(t)) require.NoError(t, err, "error getting coordinator FallbackWeiPerUnitLink") require.Equal(t, *configCopy.VRFv2.General.StalenessSeconds, coordinatorConfig.StalenessSeconds) @@ -676,3 +683,186 @@ func TestVRFOwner(t *testing.T) { require.Equal(t, *configCopy.VRFv2.General.FallbackWeiPerUnitLink, coordinatorFallbackWeiPerUnitLinkConfig.Int64()) }) } + +func TestVRFV2WithBHS(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + + config, err := tc.GetConfig("Smoke", tc.VRFv2) + require.NoError(t, err, "Error getting config") + + useVRFOwner := true + useTestCoordinator := true + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + + env, err := test_env.NewCLTestEnvBuilder(). + WithTestInstance(t). + WithTestConfig(&config). + WithPrivateEthereumNetwork(network). + WithCLNodes(2). + WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). + WithStandardCleanup(). + Build() + require.NoError(t, err, "error creating test env") + + env.ParallelTransactions(true) + + mockETHLinkFeed, err := env.ContractDeployer.DeployVRFMockETHLINKFeed(big.NewInt(*config.VRFv2.General.LinkNativeFeedResponse)) + + require.NoError(t, err) + linkToken, err := actions.DeployLINKToken(env.ContractDeployer) + require.NoError(t, err) + + // register proving key against oracle address (sending key) in order to test oracleWithdraw + defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() + + //Underfund Subscription + config.VRFv2.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0.000000000000000001)) // 1 Juel + + //decrease default span for checking blockhashes for unfulfilled requests + config.VRFv2.General.BHSJobWaitBlocks = ptr.Ptr(2) + config.VRFv2.General.BHSJobLookBackBlocks = ptr.Ptr(20) + + numberOfTxKeysToCreate := 0 + vrfv2Contracts, subIDs, vrfv2KeyData, nodesMap, err := vrfv2.SetupVRFV2Environment( + env, + []vrfcommon.VRFNodeType{vrfcommon.VRF, vrfcommon.BHS}, + &config, + useVRFOwner, + useTestCoordinator, + linkToken, + mockETHLinkFeed, + defaultWalletAddress, + numberOfTxKeysToCreate, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up VRF v2 env") + + subID := subIDs[0] + + subscription, err := vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subID) + require.NoError(t, err, "error getting subscription information") + + vrfv2.LogSubDetails(l, subscription, subID, vrfv2Contracts.CoordinatorV2) + + t.Run("BHS Job with complete E2E - wait 256 blocks to see if Rand Request is fulfilled", func(t *testing.T) { + t.Skip("Skipped since should be run on-demand on live testnet due to long execution time") + //BHS node should fill in blockhashes into BHS contract depending on the waitBlocks and lookBackBlocks settings + configCopy := config.MustCopy().(tc.TestConfig) + _, err := vrfv2Contracts.VRFV2Consumer[0].RequestRandomness( + vrfv2KeyData.KeyHash, + subID, + *configCopy.VRFv2.General.MinimumConfirmations, + *configCopy.VRFv2.General.CallbackGasLimit, + *configCopy.VRFv2.General.NumberOfWords, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, + ) + require.NoError(t, err, "error requesting randomness") + + randomWordsRequestedEvent, err := vrfv2Contracts.CoordinatorV2.WaitForRandomWordsRequestedEvent( + [][32]byte{vrfv2KeyData.KeyHash}, + []uint64{subID}, + []common.Address{common.HexToAddress(vrfv2Contracts.VRFV2Consumer[0].Address())}, + time.Minute*1, + ) + require.NoError(t, err, "error waiting for randomness requested event") + vrfv2.LogRandomnessRequestedEvent(l, vrfv2Contracts.CoordinatorV2, randomWordsRequestedEvent) + randRequestBlockNumber := randomWordsRequestedEvent.Raw.BlockNumber + var wg sync.WaitGroup + wg.Add(1) + //Wait at least 256 blocks + _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(257), env.EVMClient, &wg, time.Second*260, t) + wg.Wait() + require.NoError(t, err) + err = vrfv2.FundSubscriptions(env, big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), linkToken, vrfv2Contracts.CoordinatorV2, subIDs) + require.NoError(t, err, "error funding subscriptions") + randomWordsFulfilledEvent, err := vrfv2Contracts.CoordinatorV2.WaitForRandomWordsFulfilledEvent( + []*big.Int{randomWordsRequestedEvent.RequestId}, + time.Second*30, + ) + require.NoError(t, err, "error waiting for randomness fulfilled event") + vrfv2.LogRandomWordsFulfilledEvent(l, vrfv2Contracts.CoordinatorV2, randomWordsFulfilledEvent) + status, err := vrfv2Contracts.VRFV2Consumer[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) + require.NoError(t, err, "error getting rand request status") + require.True(t, status.Fulfilled) + l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") + }) + + t.Run("BHS Job should fill in blockhashes into BHS contract for unfulfilled requests", func(t *testing.T) { + //BHS node should fill in blockhashes into BHS contract depending on the waitBlocks and lookBackBlocks settings + configCopy := config.MustCopy().(tc.TestConfig) + _, err := vrfv2Contracts.VRFV2Consumer[0].RequestRandomness( + vrfv2KeyData.KeyHash, + subID, + *configCopy.VRFv2.General.MinimumConfirmations, + *configCopy.VRFv2.General.CallbackGasLimit, + *configCopy.VRFv2.General.NumberOfWords, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, + ) + require.NoError(t, err, "error requesting randomness") + + randomWordsRequestedEvent, err := vrfv2Contracts.CoordinatorV2.WaitForRandomWordsRequestedEvent( + [][32]byte{vrfv2KeyData.KeyHash}, + []uint64{subID}, + []common.Address{common.HexToAddress(vrfv2Contracts.VRFV2Consumer[0].Address())}, + time.Minute*1, + ) + require.NoError(t, err, "error waiting for randomness requested event") + vrfv2.LogRandomnessRequestedEvent(l, vrfv2Contracts.CoordinatorV2, randomWordsRequestedEvent) + randRequestBlockNumber := randomWordsRequestedEvent.Raw.BlockNumber + + _, err = vrfv2Contracts.BHS.GetBlockHash(testcontext.Get(t), big.NewInt(int64(randRequestBlockNumber))) + require.Error(t, err, "error not occurred when getting blockhash for a blocknumber which was not stored in BHS contract") + + var wg sync.WaitGroup + wg.Add(1) + _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(*config.VRFv2.General.BHSJobWaitBlocks), env.EVMClient, &wg, time.Minute*1, t) + wg.Wait() + require.NoError(t, err, "error waiting for blocknumber to be") + + err = env.EVMClient.WaitForEvents() + require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) + metrics, err := vrfv2Contracts.VRFV2Consumer[0].GetLoadTestMetrics(testcontext.Get(t)) + require.Equal(t, 0, metrics.RequestCount.Cmp(big.NewInt(1))) + require.Equal(t, 0, metrics.FulfilmentCount.Cmp(big.NewInt(0))) + + var clNodeTxs *client.TransactionsData + var txHash string + gom := gomega.NewGomegaWithT(t) + gom.Eventually(func(g gomega.Gomega) { + clNodeTxs, _, err = nodesMap[vrfcommon.BHS].CLNode.API.ReadTransactions() + g.Expect(err).ShouldNot(gomega.HaveOccurred(), "error getting CL Node transactions") + l.Debug().Int("Number of TXs", len(clNodeTxs.Data)).Msg("BHS Node txs") + g.Expect(len(clNodeTxs.Data)).Should(gomega.BeNumerically("==", 1), "Expected 1 tx posted by BHS Node, but found %d", len(clNodeTxs.Data)) + txHash = clNodeTxs.Data[0].Attributes.Hash + }, "2m", "1s").Should(gomega.Succeed()) + + require.Equal(t, strings.ToLower(vrfv2Contracts.BHS.Address()), strings.ToLower(clNodeTxs.Data[0].Attributes.To)) + + bhsStoreTx, _, err := actions.GetTxByHash(testcontext.Get(t), env.EVMClient, common.HexToHash(txHash)) + require.NoError(t, err, "error getting tx from hash") + + bhsStoreTxInputData, err := actions.DecodeTxInputData(blockhash_store.BlockhashStoreABI, bhsStoreTx.Data()) + l.Info(). + Str("Block Number", bhsStoreTxInputData["n"].(*big.Int).String()). + Msg("BHS Node's Store Blockhash for Blocknumber Method TX") + require.Equal(t, randRequestBlockNumber, bhsStoreTxInputData["n"].(*big.Int).Uint64()) + + err = env.EVMClient.WaitForEvents() + require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) + + var randRequestBlockHash [32]byte + gom.Eventually(func(g gomega.Gomega) { + randRequestBlockHash, err = vrfv2Contracts.BHS.GetBlockHash(testcontext.Get(t), big.NewInt(int64(randRequestBlockNumber))) + g.Expect(err).ShouldNot(gomega.HaveOccurred(), "error getting blockhash for a blocknumber which was stored in BHS contract") + }, "2m", "1s").Should(gomega.Succeed()) + l.Info(). + Str("Randomness Request's Blockhash", randomWordsRequestedEvent.Raw.BlockHash.String()). + Str("Block Hash stored by BHS contract", fmt.Sprintf("0x%x", randRequestBlockHash)). + Msg("BHS Contract's stored Blockhash for Randomness Request") + require.Equal(t, 0, randomWordsRequestedEvent.Raw.BlockHash.Cmp(randRequestBlockHash)) + }) +} diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index b81ebd79d66..701cae9a027 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -1,22 +1,26 @@ package smoke import ( - "context" "fmt" "math/big" + "strings" + "sync" "testing" "time" "github.com/ethereum/go-ethereum/common" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" + "github.com/onsi/gomega" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2plus" + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" @@ -59,8 +63,9 @@ func TestVRFv2Plus(t *testing.T) { defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() numberOfTxKeysToCreate := 2 - vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment( + vrfv2PlusContracts, subIDs, vrfv2PlusData, nodesMap, err := vrfv2plus.SetupVRFV2_5Environment( env, + []vrfcommon.VRFNodeType{vrfcommon.VRF}, &config, linkToken, mockETHLinkFeed, @@ -73,23 +78,23 @@ func TestVRFv2Plus(t *testing.T) { subID := subIDs[0] - subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subID) + subscription, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) + vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.CoordinatorV2Plus) t.Run("Link Billing", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) var isNativeBilling = false subBalanceBeforeRequest := subscription.Balance - jobRunsBeforeTest, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfv2PlusData.VRFJob.Data.ID) + jobRunsBeforeTest, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) require.NoError(t, err, "error reading job runs") // test and assert randomWordsFulfilledEvent, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( - vrfv2PlusContracts.LoadTestConsumers[0], - vrfv2PlusContracts.Coordinator, + vrfv2PlusContracts.VRFV2PlusConsumer[0], + vrfv2PlusContracts.CoordinatorV2Plus, vrfv2PlusData, subID, isNativeBilling, @@ -104,16 +109,16 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err, "error requesting randomness and waiting for fulfilment") expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - subscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subID) + subscription, err = vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") subBalanceAfterRequest := subscription.Balance require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) - jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfv2PlusData.VRFJob.Data.ID) + jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) require.NoError(t, err, "error reading job runs") require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) - status, err := vrfv2PlusContracts.LoadTestConsumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) + status, err := vrfv2PlusContracts.VRFV2PlusConsumer[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") @@ -131,13 +136,13 @@ func TestVRFv2Plus(t *testing.T) { var isNativeBilling = true subNativeTokenBalanceBeforeRequest := subscription.NativeBalance - jobRunsBeforeTest, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfv2PlusData.VRFJob.Data.ID) + jobRunsBeforeTest, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) require.NoError(t, err, "error reading job runs") // test and assert randomWordsFulfilledEvent, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( - vrfv2PlusContracts.LoadTestConsumers[0], - vrfv2PlusContracts.Coordinator, + vrfv2PlusContracts.VRFV2PlusConsumer[0], + vrfv2PlusContracts.CoordinatorV2Plus, vrfv2PlusData, subID, isNativeBilling, @@ -151,16 +156,16 @@ func TestVRFv2Plus(t *testing.T) { ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") expectedSubBalanceWei := new(big.Int).Sub(subNativeTokenBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - subscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subID) + subscription, err = vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err) subBalanceAfterRequest := subscription.NativeBalance require.Equal(t, expectedSubBalanceWei, subBalanceAfterRequest) - jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfv2PlusData.VRFJob.Data.ID) + jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) require.NoError(t, err, "error reading job runs") require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) - status, err := vrfv2PlusContracts.LoadTestConsumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) + status, err := vrfv2PlusContracts.VRFV2PlusConsumer[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") @@ -178,7 +183,7 @@ func TestVRFv2Plus(t *testing.T) { &configCopy, linkToken, mockETHLinkFeed, - vrfv2PlusContracts.Coordinator, + vrfv2PlusContracts.CoordinatorV2Plus, vrfv2PlusData.KeyHash, 1, ) @@ -192,13 +197,13 @@ func TestVRFv2Plus(t *testing.T) { wrapperConsumerJuelsBalanceBeforeRequest, err := linkToken.BalanceOf(testcontext.Get(t), wrapperContracts.LoadTestConsumers[0].Address()) require.NoError(t, err, "error getting wrapper consumer balance") - wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), wrapperSubID) + wrapperSubscription, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), wrapperSubID) require.NoError(t, err, "error getting subscription information") subBalanceBeforeRequest := wrapperSubscription.Balance randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment( wrapperContracts.LoadTestConsumers[0], - vrfv2PlusContracts.Coordinator, + vrfv2PlusContracts.CoordinatorV2Plus, vrfv2PlusData, wrapperSubID, isNativeBilling, @@ -213,7 +218,7 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err, "error requesting randomness and waiting for fulfilment") expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), wrapperSubID) + wrapperSubscription, err = vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), wrapperSubID) require.NoError(t, err, "error getting subscription information") subBalanceAfterRequest := wrapperSubscription.Balance require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) @@ -246,13 +251,13 @@ func TestVRFv2Plus(t *testing.T) { wrapperConsumerBalanceBeforeRequestWei, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) require.NoError(t, err, "error getting wrapper consumer balance") - wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), wrapperSubID) + wrapperSubscription, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), wrapperSubID) require.NoError(t, err, "error getting subscription information") subBalanceBeforeRequest := wrapperSubscription.NativeBalance randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment( wrapperContracts.LoadTestConsumers[0], - vrfv2PlusContracts.Coordinator, + vrfv2PlusContracts.CoordinatorV2Plus, vrfv2PlusData, wrapperSubID, isNativeBilling, @@ -267,7 +272,7 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err, "error requesting randomness and waiting for fulfilment") expectedSubBalanceWei := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), wrapperSubID) + wrapperSubscription, err = vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), wrapperSubID) require.NoError(t, err, "error getting subscription information") subBalanceAfterRequest := wrapperSubscription.NativeBalance require.Equal(t, expectedSubBalanceWei, subBalanceAfterRequest) @@ -300,8 +305,8 @@ func TestVRFv2Plus(t *testing.T) { big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), linkToken, - vrfv2PlusContracts.Coordinator, - vrfv2PlusContracts.LoadTestConsumers, + vrfv2PlusContracts.CoordinatorV2Plus, + vrfv2PlusContracts.VRFV2PlusConsumer, 1, vrfv2plus_config.BillingType(*configCopy.GetVRFv2PlusConfig().General.SubscriptionBillingType), ) @@ -317,7 +322,7 @@ func TestVRFv2Plus(t *testing.T) { testWalletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), testWalletAddress.String()) require.NoError(t, err) - subscriptionForCancelling, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) + subscriptionForCancelling, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForCancelling) require.NoError(t, err, "error getting subscription information") subBalanceLink := subscriptionForCancelling.Balance @@ -328,10 +333,10 @@ func TestVRFv2Plus(t *testing.T) { Str("Returning funds from SubID", subIDForCancelling.String()). Str("Returning funds to", testWalletAddress.String()). Msg("Canceling subscription and returning funds to subscription owner") - tx, err := vrfv2PlusContracts.Coordinator.CancelSubscription(subIDForCancelling, testWalletAddress) + tx, err := vrfv2PlusContracts.CoordinatorV2Plus.CancelSubscription(subIDForCancelling, testWalletAddress) require.NoError(t, err, "Error canceling subscription") - subscriptionCanceledEvent, err := vrfv2PlusContracts.Coordinator.WaitForSubscriptionCanceledEvent(subIDForCancelling, time.Second*30) + subscriptionCanceledEvent, err := vrfv2PlusContracts.CoordinatorV2Plus.WaitForSubscriptionCanceledEvent(subIDForCancelling, time.Second*30) require.NoError(t, err, "error waiting for subscription canceled event") cancellationTxReceipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) @@ -363,7 +368,7 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err) //Verify that sub was deleted from Coordinator - _, err = vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) + _, err = vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForCancelling) require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") subFundsReturnedNativeActual := new(big.Int).Sub(testWalletBalanceNativeAfterSubCancelling, testWalletBalanceNativeBeforeSubCancelling) @@ -400,8 +405,8 @@ func TestVRFv2Plus(t *testing.T) { big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), linkToken, - vrfv2PlusContracts.Coordinator, - vrfv2PlusContracts.LoadTestConsumers, + vrfv2PlusContracts.CoordinatorV2Plus, + vrfv2PlusContracts.VRFV2PlusConsumer, 1, vrfv2plus_config.BillingType(*configCopy.GetVRFv2PlusConfig().General.SubscriptionBillingType), ) @@ -409,24 +414,24 @@ func TestVRFv2Plus(t *testing.T) { subIDForCancelling := subIDsForCancelling[0] - subscriptionForCancelling, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) + subscriptionForCancelling, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForCancelling) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscriptionForCancelling, subIDForCancelling, vrfv2PlusContracts.Coordinator) + vrfv2plus.LogSubDetails(l, subscriptionForCancelling, subIDForCancelling, vrfv2PlusContracts.CoordinatorV2Plus) - activeSubscriptionIdsBeforeSubCancellation, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) + activeSubscriptionIdsBeforeSubCancellation, err := vrfv2PlusContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) require.NoError(t, err) require.True(t, it_utils.BigIntSliceContains(activeSubscriptionIdsBeforeSubCancellation, subIDForCancelling)) - pendingRequestsExist, err := vrfv2PlusContracts.Coordinator.PendingRequestsExist(testcontext.Get(t), subIDForCancelling) + pendingRequestsExist, err := vrfv2PlusContracts.CoordinatorV2Plus.PendingRequestsExist(testcontext.Get(t), subIDForCancelling) require.NoError(t, err) require.False(t, pendingRequestsExist, "Pending requests should not exist") randomWordsFulfilledEventTimeout := 5 * time.Second _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( - vrfv2PlusContracts.LoadTestConsumers[0], - vrfv2PlusContracts.Coordinator, + vrfv2PlusContracts.VRFV2PlusConsumer[0], + vrfv2PlusContracts.CoordinatorV2Plus, vrfv2PlusData, subIDForCancelling, false, @@ -442,8 +447,8 @@ func TestVRFv2Plus(t *testing.T) { require.Error(t, err, "error should occur for waiting for fulfilment due to low sub balance") _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( - vrfv2PlusContracts.LoadTestConsumers[0], - vrfv2PlusContracts.Coordinator, + vrfv2PlusContracts.VRFV2PlusConsumer[0], + vrfv2PlusContracts.CoordinatorV2Plus, vrfv2PlusData, subIDForCancelling, true, @@ -458,7 +463,7 @@ func TestVRFv2Plus(t *testing.T) { require.Error(t, err, "error should occur for waiting for fulfilment due to low sub balance") - pendingRequestsExist, err = vrfv2PlusContracts.Coordinator.PendingRequestsExist(testcontext.Get(t), subIDForCancelling) + pendingRequestsExist, err = vrfv2PlusContracts.CoordinatorV2Plus.PendingRequestsExist(testcontext.Get(t), subIDForCancelling) require.NoError(t, err) require.True(t, pendingRequestsExist, "Pending requests should exist after unfulfilled rand requests due to low sub balance") @@ -468,7 +473,7 @@ func TestVRFv2Plus(t *testing.T) { walletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) require.NoError(t, err) - subscriptionForCancelling, err = vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) + subscriptionForCancelling, err = vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForCancelling) require.NoError(t, err, "error getting subscription information") subBalanceLink := subscriptionForCancelling.Balance @@ -479,10 +484,10 @@ func TestVRFv2Plus(t *testing.T) { Str("Returning funds from SubID", subIDForCancelling.String()). Str("Returning funds to", defaultWalletAddress). Msg("Canceling subscription and returning funds to subscription owner") - tx, err := vrfv2PlusContracts.Coordinator.OwnerCancelSubscription(subIDForCancelling) + tx, err := vrfv2PlusContracts.CoordinatorV2Plus.OwnerCancelSubscription(subIDForCancelling) require.NoError(t, err, "Error canceling subscription") - subscriptionCanceledEvent, err := vrfv2PlusContracts.Coordinator.WaitForSubscriptionCanceledEvent(subIDForCancelling, time.Second*30) + subscriptionCanceledEvent, err := vrfv2PlusContracts.CoordinatorV2Plus.WaitForSubscriptionCanceledEvent(subIDForCancelling, time.Second*30) require.NoError(t, err, "error waiting for subscription canceled event") cancellationTxReceipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) @@ -514,8 +519,7 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err) //Verify that sub was deleted from Coordinator - _, err = vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) - fmt.Println("err", err) + _, err = vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForCancelling) require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") subFundsReturnedNativeActual := new(big.Int).Sub(walletBalanceNativeAfterSubCancelling, walletBalanceNativeBeforeSubCancelling) @@ -543,7 +547,7 @@ func TestVRFv2Plus(t *testing.T) { //require.Equal(t, subFundsReturnedNativeExpected, subFundsReturnedNativeActual, "Returned funds are not equal to sub balance that was cancelled") require.Equal(t, 0, subBalanceLink.Cmp(subFundsReturnedLinkActual), "Returned LINK funds are not equal to sub balance that was cancelled") - activeSubscriptionIdsAfterSubCancellation, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) + activeSubscriptionIdsAfterSubCancellation, err := vrfv2PlusContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) require.NoError(t, err, "error getting active subscription ids") require.False( @@ -560,8 +564,8 @@ func TestVRFv2Plus(t *testing.T) { big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), linkToken, - vrfv2PlusContracts.Coordinator, - vrfv2PlusContracts.LoadTestConsumers, + vrfv2PlusContracts.CoordinatorV2Plus, + vrfv2PlusContracts.VRFV2PlusConsumer, 1, vrfv2plus_config.BillingType(*configCopy.GetVRFv2PlusConfig().General.SubscriptionBillingType), ) @@ -569,8 +573,8 @@ func TestVRFv2Plus(t *testing.T) { subIDForWithdraw := subIDsForWithdraw[0] fulfilledEventLink, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( - vrfv2PlusContracts.LoadTestConsumers[0], - vrfv2PlusContracts.Coordinator, + vrfv2PlusContracts.VRFV2PlusConsumer[0], + vrfv2PlusContracts.CoordinatorV2Plus, vrfv2PlusData, subIDForWithdraw, false, @@ -585,8 +589,8 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err) fulfilledEventNative, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( - vrfv2PlusContracts.LoadTestConsumers[0], - vrfv2PlusContracts.Coordinator, + vrfv2PlusContracts.VRFV2PlusConsumer[0], + vrfv2PlusContracts.CoordinatorV2Plus, vrfv2PlusData, subIDForWithdraw, true, @@ -612,7 +616,7 @@ func TestVRFv2Plus(t *testing.T) { Str("Amount", amountToWithdrawLink.String()). Msg("Invoking Oracle Withdraw for LINK") - err = vrfv2PlusContracts.Coordinator.Withdraw( + err = vrfv2PlusContracts.CoordinatorV2Plus.Withdraw( common.HexToAddress(defaultWalletAddress), ) require.NoError(t, err, "error withdrawing LINK from coordinator to default wallet") @@ -623,13 +627,13 @@ func TestVRFv2Plus(t *testing.T) { Str("Amount", amountToWithdrawNative.String()). Msg("Invoking Oracle Withdraw for Native") - err = vrfv2PlusContracts.Coordinator.WithdrawNative( + err = vrfv2PlusContracts.CoordinatorV2Plus.WithdrawNative( common.HexToAddress(defaultWalletAddress), ) require.NoError(t, err, "error withdrawing Native tokens from coordinator to default wallet") err = env.EVMClient.WaitForEvents() - require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) + require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) defaultWalletBalanceNativeAfterWithdraw, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) require.NoError(t, err) @@ -674,8 +678,9 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { require.NoError(t, err, "error deploying LINK contract") numberOfTxKeysToCreate := 2 - vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment( + vrfv2PlusContracts, subIDs, vrfv2PlusData, _, err := vrfv2plus.SetupVRFV2_5Environment( env, + []vrfcommon.VRFNodeType{vrfcommon.VRF}, &config, linkToken, mockETHLinkFeed, @@ -688,10 +693,10 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { subID := subIDs[0] - subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subID) + subscription, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) + vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.CoordinatorV2Plus) t.Run("Request Randomness with multiple sending keys", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) @@ -704,8 +709,8 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { var fulfillmentTxFromAddresses []string for i := 0; i < numberOfTxKeysToCreate+1; i++ { randomWordsFulfilledEvent, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( - vrfv2PlusContracts.LoadTestConsumers[0], - vrfv2PlusContracts.Coordinator, + vrfv2PlusContracts.VRFV2PlusConsumer[0], + vrfv2PlusContracts.CoordinatorV2Plus, vrfv2PlusData, subID, isNativeBilling, @@ -720,8 +725,7 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { require.NoError(t, err, "error requesting randomness and waiting for fulfilment") //todo - move TransactionByHash to EVMClient in CTF - fulfillmentTx, _, err := env.EVMClient.(*blockchain.EthereumMultinodeClient).DefaultClient.(*blockchain.EthereumClient). - Client.TransactionByHash(context.Background(), randomWordsFulfilledEvent.Raw.TxHash) + fulfillmentTx, _, err := actions.GetTxByHash(testcontext.Get(t), env.EVMClient, randomWordsFulfilledEvent.Raw.TxHash) require.NoError(t, err, "error getting tx from hash") fulfillmentTxFromAddress, err := actions.GetTxFromAddress(fulfillmentTx) require.NoError(t, err, "error getting tx from address") @@ -767,8 +771,9 @@ func TestVRFv2PlusMigration(t *testing.T) { linkAddress, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err, "error deploying LINK contract") - vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment( + vrfv2PlusContracts, subIDs, vrfv2PlusData, nodesMap, err := vrfv2plus.SetupVRFV2_5Environment( env, + []vrfcommon.VRFNodeType{vrfcommon.VRF}, &config, linkAddress, mockETHLinkFeedAddress, @@ -781,17 +786,17 @@ func TestVRFv2PlusMigration(t *testing.T) { subID := subIDs[0] - subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subID) + subscription, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) + vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.CoordinatorV2Plus) - activeSubIdsOldCoordinatorBeforeMigration, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) + activeSubIdsOldCoordinatorBeforeMigration, err := vrfv2PlusContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) require.NoError(t, err, "error occurred getting active sub ids") require.Len(t, activeSubIdsOldCoordinatorBeforeMigration, 1, "Active Sub Ids length is not equal to 1") require.Equal(t, subID, activeSubIdsOldCoordinatorBeforeMigration[0]) - oldSubscriptionBeforeMigration, err := vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subID) + oldSubscriptionBeforeMigration, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") //Migration Process @@ -799,10 +804,10 @@ func TestVRFv2PlusMigration(t *testing.T) { require.NoError(t, err, "error deploying VRF CoordinatorV2PlusUpgradedVersion") err = env.EVMClient.WaitForEvents() - require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) + require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) _, err = vrfv2plus.VRFV2PlusUpgradedVersionRegisterProvingKey(vrfv2PlusData.VRFKey, newCoordinator) - require.NoError(t, err, fmt.Errorf("%s, err: %w", vrfv2plus.ErrRegisteringProvingKey, err)) + require.NoError(t, err, fmt.Errorf("%s, err: %w", vrfcommon.ErrRegisteringProvingKey, err)) vrfv2PlusConfig := config.VRFv2Plus.General err = newCoordinator.SetConfig( @@ -821,13 +826,13 @@ func TestVRFv2PlusMigration(t *testing.T) { err = newCoordinator.SetLINKAndLINKNativeFeed(linkAddress.Address(), mockETHLinkFeedAddress.Address()) require.NoError(t, err, vrfv2plus.ErrSetLinkNativeLinkFeed) err = env.EVMClient.WaitForEvents() - require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) + require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - vrfJobSpecConfig := vrfv2plus.VRFJobSpecConfig{ + vrfJobSpecConfig := vrfcommon.VRFJobSpecConfig{ ForwardingAllowed: false, CoordinatorAddress: newCoordinator.Address(), - FromAddresses: []string{vrfv2PlusData.PrimaryEthAddress}, - EVMChainID: vrfv2PlusData.ChainID.String(), + FromAddresses: nodesMap[vrfcommon.VRF].TXKeyAddressStrings, + EVMChainID: env.EVMClient.GetChainID().String(), MinIncomingConfirmations: int(*vrfv2PlusConfig.MinimumConfirmations), PublicKey: vrfv2PlusData.VRFKey.Data.ID, EstimateGasMultiplier: 1, @@ -843,31 +848,31 @@ func TestVRFv2PlusMigration(t *testing.T) { ) require.NoError(t, err, vrfv2plus.ErrCreateVRFV2PlusJobs) - err = vrfv2PlusContracts.Coordinator.RegisterMigratableCoordinator(newCoordinator.Address()) + err = vrfv2PlusContracts.CoordinatorV2Plus.RegisterMigratableCoordinator(newCoordinator.Address()) require.NoError(t, err, "error registering migratable coordinator") err = env.EVMClient.WaitForEvents() - require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) + require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - oldCoordinatorLinkTotalBalanceBeforeMigration, oldCoordinatorEthTotalBalanceBeforeMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfv2PlusContracts.Coordinator) + oldCoordinatorLinkTotalBalanceBeforeMigration, oldCoordinatorEthTotalBalanceBeforeMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfv2PlusContracts.CoordinatorV2Plus) require.NoError(t, err) migratedCoordinatorLinkTotalBalanceBeforeMigration, migratedCoordinatorEthTotalBalanceBeforeMigration, err := vrfv2plus.GetUpgradedCoordinatorTotalBalance(newCoordinator) require.NoError(t, err) err = env.EVMClient.WaitForEvents() - require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) + require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - err = vrfv2PlusContracts.Coordinator.Migrate(subID, newCoordinator.Address()) - require.NoError(t, err, "error migrating sub id ", subID.String(), " from ", vrfv2PlusContracts.Coordinator.Address(), " to new Coordinator address ", newCoordinator.Address()) - migrationCompletedEvent, err := vrfv2PlusContracts.Coordinator.WaitForMigrationCompletedEvent(time.Minute * 1) + err = vrfv2PlusContracts.CoordinatorV2Plus.Migrate(subID, newCoordinator.Address()) + require.NoError(t, err, "error migrating sub id ", subID.String(), " from ", vrfv2PlusContracts.CoordinatorV2Plus.Address(), " to new Coordinator address ", newCoordinator.Address()) + migrationCompletedEvent, err := vrfv2PlusContracts.CoordinatorV2Plus.WaitForMigrationCompletedEvent(time.Minute * 1) require.NoError(t, err, "error waiting for MigrationCompleted event") err = env.EVMClient.WaitForEvents() - require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) + require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) vrfv2plus.LogMigrationCompletedEvent(l, migrationCompletedEvent, vrfv2PlusContracts) - oldCoordinatorLinkTotalBalanceAfterMigration, oldCoordinatorEthTotalBalanceAfterMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfv2PlusContracts.Coordinator) + oldCoordinatorLinkTotalBalanceAfterMigration, oldCoordinatorEthTotalBalanceAfterMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfv2PlusContracts.CoordinatorV2Plus) require.NoError(t, err) migratedCoordinatorLinkTotalBalanceAfterMigration, migratedCoordinatorEthTotalBalanceAfterMigration, err := vrfv2plus.GetUpgradedCoordinatorTotalBalance(newCoordinator) @@ -879,7 +884,7 @@ func TestVRFv2PlusMigration(t *testing.T) { vrfv2plus.LogSubDetailsAfterMigration(l, newCoordinator, subID, migratedSubscription) //Verify that Coordinators were updated in Consumers - for _, consumer := range vrfv2PlusContracts.LoadTestConsumers { + for _, consumer := range vrfv2PlusContracts.VRFV2PlusConsumer { coordinatorAddressInConsumerAfterMigration, err := consumer.GetCoordinator(testcontext.Get(t)) require.NoError(t, err, "error getting Coordinator from Consumer contract") require.Equal(t, newCoordinator.Address(), coordinatorAddressInConsumerAfterMigration.String()) @@ -896,10 +901,10 @@ func TestVRFv2PlusMigration(t *testing.T) { require.Equal(t, oldSubscriptionBeforeMigration.Consumers, migratedSubscription.Consumers) //Verify that old sub was deleted from old Coordinator - _, err = vrfv2PlusContracts.Coordinator.GetSubscription(testcontext.Get(t), subID) + _, err = vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") - _, err = vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) + _, err = vrfv2PlusContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) require.Error(t, err, "error not occurred getting active sub ids. Should occur since it should revert when sub id array is empty") activeSubIdsMigratedCoordinator, err := newCoordinator.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) @@ -920,7 +925,7 @@ func TestVRFv2PlusMigration(t *testing.T) { //Verify rand requests fulfills with Link Token billing _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillmentUpgraded( - vrfv2PlusContracts.LoadTestConsumers[0], + vrfv2PlusContracts.VRFV2PlusConsumer[0], newCoordinator, vrfv2PlusData, subID, @@ -936,7 +941,7 @@ func TestVRFv2PlusMigration(t *testing.T) { //Verify rand requests fulfills with Native Token billing _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillmentUpgraded( - vrfv2PlusContracts.LoadTestConsumers[1], + vrfv2PlusContracts.VRFV2PlusConsumer[1], newCoordinator, vrfv2PlusData, subID, @@ -950,3 +955,188 @@ func TestVRFv2PlusMigration(t *testing.T) { ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") } + +func TestVRFV2PlusWithBHS(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + + config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + require.NoError(t, err, "Error getting config") + + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + + env, err := test_env.NewCLTestEnvBuilder(). + WithTestInstance(t). + WithTestConfig(&config). + WithPrivateEthereumNetwork(network). + WithCLNodes(2). + WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). + WithStandardCleanup(). + Build() + require.NoError(t, err, "error creating test env") + + env.ParallelTransactions(true) + + mockETHLinkFeed, err := env.ContractDeployer.DeployVRFMockETHLINKFeed(big.NewInt(*config.VRFv2Plus.General.LinkNativeFeedResponse)) + + require.NoError(t, err) + linkToken, err := actions.DeployLINKToken(env.ContractDeployer) + require.NoError(t, err) + + //Underfund Subscription + config.VRFv2Plus.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0.000000000000000001)) // 1 Juel + + //decrease default span for checking blockhashes for unfulfilled requests + config.VRFv2Plus.General.BHSJobWaitBlocks = ptr.Ptr(2) + config.VRFv2Plus.General.BHSJobLookBackBlocks = ptr.Ptr(20) + + numberOfTxKeysToCreate := 0 + vrfContracts, subIDs, vrfKeyData, nodesMap, err := vrfv2plus.SetupVRFV2_5Environment( + env, + []vrfcommon.VRFNodeType{vrfcommon.VRF, vrfcommon.BHS}, + &config, + linkToken, + mockETHLinkFeed, + numberOfTxKeysToCreate, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up VRF v2_5 env") + + subID := subIDs[0] + + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + require.NoError(t, err, "error getting subscription information") + + vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + var isNativeBilling = false + t.Run("BHS Job with complete E2E - wait 256 blocks to see if Rand Request is fulfilled", func(t *testing.T) { + t.Skip("Skipped since should be run on-demand on live testnet due to long execution time") + //BHS node should fill in blockhashes into BHS contract depending on the waitBlocks and lookBackBlocks settings + configCopy := config.MustCopy().(tc.TestConfig) + _, err := vrfContracts.VRFV2PlusConsumer[0].RequestRandomness( + vrfKeyData.KeyHash, + subID, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + isNativeBilling, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + ) + require.NoError(t, err, "error requesting randomness") + + randomWordsRequestedEvent, err := vrfContracts.CoordinatorV2Plus.WaitForRandomWordsRequestedEvent( + [][32]byte{vrfKeyData.KeyHash}, + []*big.Int{subID}, + []common.Address{common.HexToAddress(vrfContracts.VRFV2PlusConsumer[0].Address())}, + time.Minute*1, + ) + require.NoError(t, err, "error waiting for randomness requested event") + vrfv2plus.LogRandomnessRequestedEvent(l, vrfContracts.CoordinatorV2Plus, randomWordsRequestedEvent, isNativeBilling) + randRequestBlockNumber := randomWordsRequestedEvent.Raw.BlockNumber + var wg sync.WaitGroup + wg.Add(1) + //Wait at least 256 blocks + _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(257), env.EVMClient, &wg, time.Second*260, t) + wg.Wait() + require.NoError(t, err) + err = vrfv2plus.FundSubscriptions( + env, + big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionFundingAmountNative), + big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionFundingAmountLink), + linkToken, + vrfContracts.CoordinatorV2Plus, + subIDs, + vrfv2plus_config.BillingType_Link, + ) + require.NoError(t, err, "error funding subscriptions") + randomWordsFulfilledEvent, err := vrfContracts.CoordinatorV2Plus.WaitForRandomWordsFulfilledEvent( + []*big.Int{subID}, + []*big.Int{randomWordsRequestedEvent.RequestId}, + time.Second*30, + ) + require.NoError(t, err, "error waiting for randomness fulfilled event") + vrfv2plus.LogRandomWordsFulfilledEvent(l, vrfContracts.CoordinatorV2Plus, randomWordsFulfilledEvent, isNativeBilling) + status, err := vrfContracts.VRFV2PlusConsumer[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) + require.NoError(t, err, "error getting rand request status") + require.True(t, status.Fulfilled) + l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") + }) + + t.Run("BHS Job should fill in blockhashes into BHS contract for unfulfilled requests", func(t *testing.T) { + //BHS node should fill in blockhashes into BHS contract depending on the waitBlocks and lookBackBlocks settings + configCopy := config.MustCopy().(tc.TestConfig) + _, err := vrfContracts.VRFV2PlusConsumer[0].RequestRandomness( + vrfKeyData.KeyHash, + subID, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + isNativeBilling, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + ) + require.NoError(t, err, "error requesting randomness") + + randomWordsRequestedEvent, err := vrfContracts.CoordinatorV2Plus.WaitForRandomWordsRequestedEvent( + [][32]byte{vrfKeyData.KeyHash}, + []*big.Int{subID}, + []common.Address{common.HexToAddress(vrfContracts.VRFV2PlusConsumer[0].Address())}, + time.Minute*1, + ) + require.NoError(t, err, "error waiting for randomness requested event") + vrfv2plus.LogRandomnessRequestedEvent(l, vrfContracts.CoordinatorV2Plus, randomWordsRequestedEvent, isNativeBilling) + randRequestBlockNumber := randomWordsRequestedEvent.Raw.BlockNumber + _, err = vrfContracts.BHS.GetBlockHash(testcontext.Get(t), big.NewInt(int64(randRequestBlockNumber))) + require.Error(t, err, "error not occurred when getting blockhash for a blocknumber which was not stored in BHS contract") + + var wg sync.WaitGroup + wg.Add(1) + _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(*config.VRFv2Plus.General.BHSJobWaitBlocks+10), env.EVMClient, &wg, time.Minute*1, t) + wg.Wait() + require.NoError(t, err, "error waiting for blocknumber to be") + + err = env.EVMClient.WaitForEvents() + require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) + metrics, err := vrfContracts.VRFV2PlusConsumer[0].GetLoadTestMetrics(testcontext.Get(t)) + require.Equal(t, 0, metrics.RequestCount.Cmp(big.NewInt(1))) + require.Equal(t, 0, metrics.FulfilmentCount.Cmp(big.NewInt(0))) + + var clNodeTxs *client.TransactionsData + var txHash string + gom := gomega.NewGomegaWithT(t) + gom.Eventually(func(g gomega.Gomega) { + clNodeTxs, _, err = nodesMap[vrfcommon.BHS].CLNode.API.ReadTransactions() + g.Expect(err).ShouldNot(gomega.HaveOccurred(), "error getting CL Node transactions") + l.Debug().Int("Number of TXs", len(clNodeTxs.Data)).Msg("BHS Node txs") + g.Expect(len(clNodeTxs.Data)).Should(gomega.BeNumerically("==", 1), "Expected 1 tx posted by BHS Node, but found %d", len(clNodeTxs.Data)) + txHash = clNodeTxs.Data[0].Attributes.Hash + }, "2m", "1s").Should(gomega.Succeed()) + + require.Equal(t, strings.ToLower(vrfContracts.BHS.Address()), strings.ToLower(clNodeTxs.Data[0].Attributes.To)) + + bhsStoreTx, _, err := actions.GetTxByHash(testcontext.Get(t), env.EVMClient, common.HexToHash(txHash)) + require.NoError(t, err, "error getting tx from hash") + + bhsStoreTxInputData, err := actions.DecodeTxInputData(blockhash_store.BlockhashStoreABI, bhsStoreTx.Data()) + l.Info(). + Str("Block Number", bhsStoreTxInputData["n"].(*big.Int).String()). + Msg("BHS Node's Store Blockhash for Blocknumber Method TX") + require.Equal(t, randRequestBlockNumber, bhsStoreTxInputData["n"].(*big.Int).Uint64()) + + err = env.EVMClient.WaitForEvents() + require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) + + var randRequestBlockHash [32]byte + gom.Eventually(func(g gomega.Gomega) { + randRequestBlockHash, err = vrfContracts.BHS.GetBlockHash(testcontext.Get(t), big.NewInt(int64(randRequestBlockNumber))) + g.Expect(err).ShouldNot(gomega.HaveOccurred(), "error getting blockhash for a blocknumber which was stored in BHS contract") + }, "2m", "1s").Should(gomega.Succeed()) + l.Info(). + Str("Randomness Request's Blockhash", randomWordsRequestedEvent.Raw.BlockHash.String()). + Str("Block Hash stored by BHS contract", fmt.Sprintf("0x%x", randRequestBlockHash)). + Msg("BHS Contract's stored Blockhash for Randomness Request") + require.Equal(t, 0, randomWordsRequestedEvent.Raw.BlockHash.Cmp(randRequestBlockHash)) + }) +} diff --git a/integration-tests/testconfig/vrfv2/config.go b/integration-tests/testconfig/vrfv2/config.go index f539d91799c..dca1319e8d8 100644 --- a/integration-tests/testconfig/vrfv2/config.go +++ b/integration-tests/testconfig/vrfv2/config.go @@ -198,7 +198,7 @@ func (c *SubFunding) Validate() error { } type General struct { - CLNodeMaxGasPriceGWei *int64 `toml:"max_gas_price_gwei"` // Max gas price in GWei for the chainlink node + CLNodeMaxGasPriceGWei *int64 `toml:"cl_node_max_gas_price_gwei"` // Max gas price in GWei for the chainlink node LinkNativeFeedResponse *int64 `toml:"link_native_feed_response"` // Response of the LINK/ETH feed MinimumConfirmations *uint16 `toml:"minimum_confirmations" ` // Minimum number of confirmations for the VRF Coordinator SubscriptionFundingAmountLink *float64 `toml:"subscription_funding_amount_link"` // Amount of LINK to fund the subscription with @@ -232,6 +232,20 @@ type General struct { WrapperMaxNumberOfWords *uint8 `toml:"wrapper_max_number_of_words"` WrapperConsumerFundingAmountNativeToken *float64 `toml:"wrapper_consumer_funding_amount_native_token"` WrapperConsumerFundingAmountLink *int64 `toml:"wrapper_consumer_funding_amount_link"` + + //VRF Job Config + VRFJobForwardingAllowed *bool `toml:"vrf_job_forwarding_allowed"` + VRFJobEstimateGasMultiplier *float64 `toml:"vrf_job_estimate_gas_multiplier"` + VRFJobBatchFulfillmentEnabled *bool `toml:"vrf_job_batch_fulfillment_enabled"` + VRFJobBatchFulfillmentGasMultiplier *float64 `toml:"vrf_job_batch_fulfillment_gas_multiplier"` + VRFJobPollPeriod *blockchain.StrDuration `toml:"vrf_job_poll_period"` + VRFJobRequestTimeout *blockchain.StrDuration `toml:"vrf_job_request_timeout"` + + //BHS Job Config + BHSJobWaitBlocks *int `toml:"bhs_job_wait_blocks"` + BHSJobLookBackBlocks *int `toml:"bhs_job_lookback_blocks"` + BHSJobPollPeriod *blockchain.StrDuration `toml:"bhs_job_poll_period"` + BHSJobRunTimeout *blockchain.StrDuration `toml:"bhs_job_run_timeout"` } func (c *General) Validate() error { @@ -326,5 +340,43 @@ func (c *General) Validate() error { return errors.New(ErrDeviationShouldBeLessThanOriginal) } + if c.VRFJobForwardingAllowed == nil { + return errors.New("vrf_job_forwarding_allowed must be set") + } + + if c.VRFJobBatchFulfillmentEnabled == nil { + return errors.New("vrf_job_batch_fulfillment_enabled must be set") + } + if c.VRFJobEstimateGasMultiplier == nil || *c.VRFJobEstimateGasMultiplier < 0 { + return errors.New("vrf_job_estimate_gas_multiplier must be set to a non-negative value") + } + if c.VRFJobBatchFulfillmentGasMultiplier == nil || *c.VRFJobBatchFulfillmentGasMultiplier < 0 { + return errors.New("vrf_job_batch_fulfillment_gas_multiplier must be set to a non-negative value") + } + + if c.VRFJobPollPeriod == nil || c.VRFJobPollPeriod.Duration == 0 { + return errors.New("vrf_job_poll_period must be set to a non-negative value") + } + + if c.VRFJobRequestTimeout == nil || c.VRFJobRequestTimeout.Duration == 0 { + return errors.New("vrf_job_request_timeout must be set to a non-negative value") + } + + if c.BHSJobLookBackBlocks == nil || *c.BHSJobLookBackBlocks < 0 { + return errors.New("bhs_job_lookback_blocks must be set to a non-negative value") + } + + if c.BHSJobPollPeriod == nil || c.BHSJobPollPeriod.Duration == 0 { + return errors.New("bhs_job_poll_period must be set to a non-negative value") + } + + if c.BHSJobRunTimeout == nil || c.BHSJobRunTimeout.Duration == 0 { + return errors.New("bhs_job_run_timeout must be set to a non-negative value") + } + + if c.BHSJobWaitBlocks == nil || *c.BHSJobWaitBlocks < 0 { + return errors.New("bhs_job_wait_blocks must be set to a non-negative value") + } + return nil } diff --git a/integration-tests/testconfig/vrfv2/vrfv2.toml b/integration-tests/testconfig/vrfv2/vrfv2.toml index 64e628c4afa..a4f4536208a 100644 --- a/integration-tests/testconfig/vrfv2/vrfv2.toml +++ b/integration-tests/testconfig/vrfv2/vrfv2.toml @@ -4,7 +4,7 @@ chainlink_node_funding = 0.1 [VRFv2] [VRFv2.General] -max_gas_price_gwei = 10 +cl_node_max_gas_price_gwei = 10 link_native_feed_response = 1000000000000000000 minimum_confirmations = 3 subscription_funding_amount_link = 5.0 @@ -34,6 +34,20 @@ wrapper_max_number_of_words = 10 wrapper_consumer_funding_amount_native_token = 1.0 wrapper_consumer_funding_amount_link = 10 +# VRF Job config +vrf_job_forwarding_allowed = false +vrf_job_estimate_gas_multiplier = 1.0 +vrf_job_batch_fulfillment_enabled = false +vrf_job_batch_fulfillment_gas_multiplier = 1.15 +vrf_job_poll_period = "1s" +vrf_job_request_timeout = "24h" + +# BHS Job config +bhs_job_wait_blocks = 30 +bhs_job_lookback_blocks = 250 +bhs_job_poll_period = "1s" +bhs_job_run_timeout = "24h" + # load test specific config [Load.VRFv2] [Load.VRFv2.Common] diff --git a/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml index ee84917260e..79f328e278f 100644 --- a/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml +++ b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml @@ -4,7 +4,7 @@ chainlink_node_funding = 0.1 [VRFv2Plus] [VRFv2Plus.General] -max_gas_price_gwei = 10 +cl_node_max_gas_price_gwei = 10 link_native_feed_response = 1000000000000000000 minimum_confirmations = 3 subscription_billing_type = "LINK_AND_NATIVE" @@ -41,6 +41,20 @@ fulfillment_flat_fee_link_discount_ppm=100 native_premium_percentage=1 link_premium_percentage=1 +# VRF Job config +vrf_job_forwarding_allowed = false +vrf_job_estimate_gas_multiplier = 1.0 +vrf_job_batch_fulfillment_enabled = false +vrf_job_batch_fulfillment_gas_multiplier = 1.15 +vrf_job_poll_period = "1s" +vrf_job_request_timeout = "24h" + +# BHS Job config +bhs_job_wait_blocks = 30 +bhs_job_lookback_blocks = 250 +bhs_job_poll_period = "1s" +bhs_job_run_timeout = "24h" + # load test specific config [Load.VRFv2Plus] [Load.VRFv2Plus.Common]