From 59bf37c5f8ebfb368e93ef7b6f2ccad4b50b246d Mon Sep 17 00:00:00 2001 From: Ilja Pavlovs Date: Mon, 6 Nov 2023 11:03:45 +0200 Subject: [PATCH] =?UTF-8?q?VRF-669:=20adding=20CTF=20tests=20for=20VRF=20v?= =?UTF-8?q?2.5=20cancel=20subscription,=20oracle=20wi=E2=80=A6=20(#11159)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * VRF-669: adding CTF tests for VRF v2.5 cancel subscription, oracle withdraw; added fund return as a teardown for the WASP load test * VRF-669: updating tests to have better balance calculation * VRF-669: small update * VRF-669: enabling tests; making use of big.Int Cmp() method * VRF-669: adding sub cancellation test for the coordinator owner; code refactoring; fixing load test --- .github/workflows/integration-tests.yml | 2 +- integration-tests/actions/actions.go | 16 + .../vrfv2plus/vrfv2plus_config/config.go | 6 +- .../actions/vrfv2plus/vrfv2plus_steps.go | 118 +++- .../contracts/contract_vrf_models.go | 6 + .../contracts/ethereum_vrfv2plus_contracts.go | 101 ++++ integration-tests/load/vrfv2plus/config.go | 4 +- integration-tests/load/vrfv2plus/config.toml | 8 +- integration-tests/load/vrfv2plus/gun.go | 5 +- .../load/vrfv2plus/vrfv2plus_test.go | 62 +- integration-tests/smoke/vrfv2plus_test.go | 530 ++++++++++++++---- integration-tests/utils/common.go | 10 + 12 files changed, 737 insertions(+), 131 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 0456c5f9d42..928c716dd11 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -303,7 +303,7 @@ jobs: pyroscope_env: ci-smoke-vrf2-evm-simulated - name: vrfv2plus nodes: 1 - os: ubuntu-latest + os: ubuntu20.04-8cores-32GB pyroscope_env: ci-smoke-vrf2plus-evm-simulated - name: forwarder_ocr nodes: 1 diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index 010b431b56f..b45b8e83b95 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -2,8 +2,10 @@ package actions import ( + "crypto/ecdsa" "encoding/json" "fmt" + "github.com/ethereum/go-ethereum/crypto" "math/big" "strings" "testing" @@ -443,3 +445,17 @@ func DeployMockETHLinkFeed(cd contracts.ContractDeployer, answer *big.Int) (cont } return mockETHLINKFeed, err } + +// todo - move to CTF +func GenerateWallet() (common.Address, error) { + privateKey, err := crypto.GenerateKey() + if err != nil { + return common.Address{}, err + } + publicKey := privateKey.Public() + publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) + if !ok { + return common.Address{}, errors.New("cannot assert type: publicKey is not of type *ecdsa.PublicKey") + } + return crypto.PubkeyToAddress(*publicKeyECDSA), nil +} diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go index 10d4f19c244..a47103a8a18 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go @@ -7,8 +7,8 @@ type VRFV2PlusConfig struct { IsNativePayment bool `envconfig:"IS_NATIVE_PAYMENT" default:"false"` // Whether to use native payment or LINK token LinkNativeFeedResponse int64 `envconfig:"LINK_NATIVE_FEED_RESPONSE" default:"1000000000000000000"` // Response of the LINK/ETH feed MinimumConfirmations uint16 `envconfig:"MINIMUM_CONFIRMATIONS" default:"3"` // Minimum number of confirmations for the VRF Coordinator - SubscriptionFundingAmountLink int64 `envconfig:"SUBSCRIPTION_FUNDING_AMOUNT_LINK" default:"10"` // Amount of LINK to fund the subscription with - SubscriptionFundingAmountNative int64 `envconfig:"SUBSCRIPTION_FUNDING_AMOUNT_NATIVE" default:"1"` // Amount of native currency to fund the subscription with + 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 @@ -23,6 +23,8 @@ type VRFV2PlusConfig struct { 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"` diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go index 46f0ca58e69..e720116c210 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go @@ -3,6 +3,7 @@ package vrfv2plus import ( "context" "fmt" + "github.com/smartcontractkit/chainlink-testing-framework/utils" "math/big" "sync" "time" @@ -221,12 +222,18 @@ func VRFV2PlusUpgradedVersionRegisterProvingKey( return provingKey, nil } -func FundVRFCoordinatorV2_5Subscription(linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, chainClient blockchain.EVMClient, subscriptionID *big.Int, linkFundingAmount *big.Int) error { +func FundVRFCoordinatorV2_5Subscription( + linkToken contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2_5, + chainClient blockchain.EVMClient, + subscriptionID *big.Int, + linkFundingAmountJuels *big.Int, +) error { encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint256"}]`, subscriptionID) if err != nil { return errors.Wrap(err, ErrABIEncodingFunding) } - _, err = linkToken.TransferAndCall(coordinator.Address(), big.NewInt(0).Mul(linkFundingAmount, big.NewInt(1e18)), encodedSubId) + _, err = linkToken.TransferAndCall(coordinator.Address(), linkFundingAmountJuels, encodedSubId) if err != nil { return errors.Wrap(err, ErrSendingLinkToken) } @@ -236,9 +243,10 @@ func FundVRFCoordinatorV2_5Subscription(linkToken contracts.LinkToken, coordinat // 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, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, linkToken contracts.LinkToken, mockNativeLINKFeed contracts.MockETHLINKFeed, + registerProvingKeyAgainstAddress string, numberOfConsumers int, numberOfSubToCreate int, l zerolog.Logger, @@ -275,8 +283,12 @@ func SetupVRFV2_5Environment( if err != nil { return nil, nil, nil, errors.Wrap(err, ErrWaitTXsComplete) } - l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Msg("Creating and funding subscriptions, adding consumers") - subIDs, err := CreateFundSubsAndAddConsumers(env, vrfv2PlusConfig, linkToken, vrfv2_5Contracts.Coordinator, vrfv2_5Contracts.LoadTestConsumers, numberOfSubToCreate) + l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Int("Number of Subs to create", numberOfSubToCreate).Msg("Creating and funding subscriptions, adding consumers") + subIDs, err := CreateFundSubsAndAddConsumers( + env, + vrfv2PlusConfig, + linkToken, + vrfv2_5Contracts.Coordinator, vrfv2_5Contracts.LoadTestConsumers, numberOfSubToCreate) if err != nil { return nil, nil, nil, err } @@ -287,12 +299,8 @@ func SetupVRFV2_5Environment( } pubKeyCompressed := vrfKey.Data.ID - nativeTokenPrimaryKeyAddress, err := env.ClCluster.NodeAPIs()[0].PrimaryEthAddress() - if err != nil { - return nil, nil, nil, errors.Wrap(err, ErrNodePrimaryKey) - } l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Msg("Registering Proving Key") - provingKey, err := VRFV2_5RegisterProvingKey(vrfKey, nativeTokenPrimaryKeyAddress, vrfv2_5Contracts.Coordinator) + provingKey, err := VRFV2_5RegisterProvingKey(vrfKey, registerProvingKeyAgainstAddress, vrfv2_5Contracts.Coordinator) if err != nil { return nil, nil, nil, errors.Wrap(err, ErrRegisteringProvingKey) } @@ -303,6 +311,11 @@ func SetupVRFV2_5Environment( chainID := env.EVMClient.GetChainID() + nativeTokenPrimaryKeyAddress, err := env.ClCluster.NodeAPIs()[0].PrimaryEthAddress() + if err != nil { + return nil, nil, nil, errors.Wrap(err, ErrNodePrimaryKey) + } + l.Info().Msg("Creating VRFV2 Plus Job") job, err := CreateVRFV2PlusJob( env.ClCluster.NodeAPIs()[0], @@ -351,7 +364,7 @@ func SetupVRFV2_5Environment( func CreateFundSubsAndAddConsumers( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, consumers []contracts.VRFv2PlusLoadTestConsumer, @@ -385,7 +398,7 @@ func CreateFundSubsAndAddConsumers( func CreateSubsAndFund( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, subAmountToCreate int, @@ -439,7 +452,7 @@ func AddConsumersToSubs( func SetupVRFV2PlusWrapperEnvironment( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, linkToken contracts.LinkToken, mockNativeLINKFeed contracts.MockETHLINKFeed, coordinator contracts.VRFCoordinatorV2_5, @@ -574,19 +587,24 @@ func GetCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2_5) (linkT func FundSubscriptions( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, linkAddress contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, subIDs []*big.Int, ) error { for _, subID := range subIDs { //Native Billing - err := coordinator.FundSubscriptionWithNative(subID, big.NewInt(0).Mul(big.NewInt(vrfv2PlusConfig.SubscriptionFundingAmountNative), big.NewInt(1e18))) + amountWei := utils.EtherToWei(big.NewFloat(vrfv2PlusConfig.SubscriptionFundingAmountNative)) + err := coordinator.FundSubscriptionWithNative( + subID, + amountWei, + ) if err != nil { return errors.Wrap(err, ErrFundSubWithNativeToken) } //Link Billing - err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, big.NewInt(vrfv2PlusConfig.SubscriptionFundingAmountLink)) + amountJuels := utils.EtherToWei(big.NewFloat(vrfv2PlusConfig.SubscriptionFundingAmountLink)) + err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) if err != nil { return errors.Wrap(err, ErrFundSubWithLinkToken) } @@ -605,7 +623,8 @@ func RequestRandomnessAndWaitForFulfillment( subID *big.Int, isNativeBilling bool, randomnessRequestCountPerRequest uint16, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) @@ -622,7 +641,15 @@ func RequestRandomnessAndWaitForFulfillment( return nil, errors.Wrap(err, ErrRequestRandomness) } - return WaitForRequestAndFulfillmentEvents(consumer.Address(), coordinator, vrfv2PlusData, subID, isNativeBilling, l) + return WaitForRequestAndFulfillmentEvents( + consumer.Address(), + coordinator, + vrfv2PlusData, + subID, + isNativeBilling, + randomWordsFulfilledEventTimeout, + l, + ) } func RequestRandomnessAndWaitForFulfillmentUpgraded( @@ -631,7 +658,7 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, l zerolog.Logger, ) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) @@ -679,7 +706,8 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) @@ -708,7 +736,15 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( if err != nil { return nil, errors.Wrap(err, "error getting wrapper address") } - return WaitForRequestAndFulfillmentEvents(wrapperAddress.String(), coordinator, vrfv2PlusData, subID, isNativeBilling, l) + return WaitForRequestAndFulfillmentEvents( + wrapperAddress.String(), + coordinator, + vrfv2PlusData, + subID, + isNativeBilling, + randomWordsFulfilledEventTimeout, + l, + ) } func WaitForRequestAndFulfillmentEvents( @@ -717,6 +753,7 @@ func WaitForRequestAndFulfillmentEvents( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, + randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( @@ -734,7 +771,7 @@ func WaitForRequestAndFulfillmentEvents( randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( []*big.Int{subID}, []*big.Int{randomWordsRequestedEvent.RequestId}, - time.Minute*2, + randomWordsFulfilledEventTimeout, ) if err != nil { return nil, errors.Wrap(err, ErrWaitRandomWordsFulfilledEvent) @@ -777,6 +814,41 @@ func WaitForRequestCountEqualToFulfilmentCount(consumer contracts.VRFv2PlusLoadT } } +func ReturnFundsForFulfilledRequests(client blockchain.EVMClient, coordinator contracts.VRFCoordinatorV2_5, l zerolog.Logger) error { + linkTotalBalance, err := coordinator.GetLinkTotalBalance(context.Background()) + if err != nil { + return errors.Wrap(err, "Error getting LINK total balance") + } + defaultWallet := client.GetDefaultWallet().Address() + l.Info(). + Str("LINK amount", linkTotalBalance.String()). + Str("Returning to", defaultWallet). + Msg("Returning LINK for fulfilled requests") + err = coordinator.OracleWithdraw( + common.HexToAddress(defaultWallet), + linkTotalBalance, + ) + if err != nil { + return errors.Wrap(err, "Error withdrawing LINK from coordinator to default wallet") + } + nativeTotalBalance, err := coordinator.GetNativeTokenTotalBalance(context.Background()) + if err != nil { + return errors.Wrap(err, "Error getting NATIVE total balance") + } + l.Info(). + Str("Native Token amount", linkTotalBalance.String()). + Str("Returning to", defaultWallet). + Msg("Returning Native Token for fulfilled requests") + err = coordinator.OracleWithdrawNative( + common.HexToAddress(defaultWallet), + nativeTotalBalance, + ) + if err != nil { + return errors.Wrap(err, "Error withdrawing NATIVE from coordinator to default wallet") + } + return nil +} + func getLoadTestMetrics( consumer contracts.VRFv2PlusLoadTestConsumer, metricsChannel chan *contracts.VRFLoadTestMetrics, @@ -934,7 +1006,7 @@ func logRandRequest( coordinator string, subID *big.Int, isNativeBilling bool, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, l zerolog.Logger) { l.Debug(). Str("Consumer", consumer). diff --git a/integration-tests/contracts/contract_vrf_models.go b/integration-tests/contracts/contract_vrf_models.go index f0f57f58e75..c82924143b0 100644 --- a/integration-tests/contracts/contract_vrf_models.go +++ b/integration-tests/contracts/contract_vrf_models.go @@ -80,11 +80,17 @@ type VRFCoordinatorV2_5 interface { AddConsumer(subId *big.Int, consumerAddress string) error FundSubscriptionWithNative(subId *big.Int, nativeTokenAmount *big.Int) error Address() string + PendingRequestsExist(ctx context.Context, subID *big.Int) (bool, error) GetSubscription(ctx context.Context, subID *big.Int) (vrf_coordinator_v2_5.GetSubscription, error) + OwnerCancelSubscription(subID *big.Int) (*types.Transaction, error) + CancelSubscription(subID *big.Int, to common.Address) (*types.Transaction, error) + OracleWithdraw(recipient common.Address, amount *big.Int) error + OracleWithdrawNative(recipient common.Address, amount *big.Int) error GetNativeTokenTotalBalance(ctx context.Context) (*big.Int, error) GetLinkTotalBalance(ctx context.Context) (*big.Int, error) FindSubscriptionID(subID *big.Int) (*big.Int, error) WaitForSubscriptionCreatedEvent(timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCreated, error) + WaitForSubscriptionCanceledEvent(subID *big.Int, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCanceled, error) WaitForRandomWordsFulfilledEvent(subID []*big.Int, requestID []*big.Int, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) WaitForRandomWordsRequestedEvent(keyHash [][32]byte, subID []*big.Int, sender []common.Address, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested, error) WaitForMigrationCompletedEvent(timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted, error) diff --git a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go index 1488f97131a..330166dc79d 100644 --- a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go @@ -96,6 +96,18 @@ func (v *EthereumVRFCoordinatorV2_5) GetActiveSubscriptionIds(ctx context.Contex return activeSubscriptionIds, nil } +func (v *EthereumVRFCoordinatorV2_5) PendingRequestsExist(ctx context.Context, subID *big.Int) (bool, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + } + pendingRequestExists, err := v.coordinator.PendingRequestExists(opts, subID) + if err != nil { + return false, err + } + return pendingRequestExists, nil +} + func (v *EthereumVRFCoordinatorV2_5) GetSubscription(ctx context.Context, subID *big.Int) (vrf_coordinator_v2_5.GetSubscription, error) { opts := &bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), @@ -131,6 +143,75 @@ func (v *EthereumVRFCoordinatorV2_5) GetNativeTokenTotalBalance(ctx context.Cont return totalBalance, nil } +// OwnerCancelSubscription cancels subscription by Coordinator owner +// return funds to sub owner, +// does not check if pending requests for a sub exist +func (v *EthereumVRFCoordinatorV2_5) OwnerCancelSubscription(subID *big.Int) (*types.Transaction, error) { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + tx, err := v.coordinator.OwnerCancelSubscription( + opts, + subID, + ) + if err != nil { + return nil, err + } + return tx, v.client.ProcessTransaction(tx) +} + +// CancelSubscription cancels subscription by Sub owner, +// return funds to specified address, +// checks if pending requests for a sub exist +func (v *EthereumVRFCoordinatorV2_5) CancelSubscription(subID *big.Int, to common.Address) (*types.Transaction, error) { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + tx, err := v.coordinator.CancelSubscription( + opts, + subID, + to, + ) + if err != nil { + return nil, err + } + return tx, v.client.ProcessTransaction(tx) +} + +func (v *EthereumVRFCoordinatorV2_5) OracleWithdraw(recipient common.Address, amount *big.Int) error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.coordinator.OracleWithdraw( + opts, + recipient, + amount, + ) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} + +func (v *EthereumVRFCoordinatorV2_5) OracleWithdrawNative(recipient common.Address, amount *big.Int) error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.coordinator.OracleWithdrawNative( + opts, + recipient, + amount, + ) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} + func (v *EthereumVRFCoordinatorV2_5) SetConfig(minimumRequestConfirmations uint16, maxGasLimit uint32, stalenessSeconds uint32, gasAfterPaymentCalculation uint32, fallbackWeiPerUnitLink *big.Int, feeConfig vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig) error { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { @@ -287,6 +368,26 @@ func (v *EthereumVRFCoordinatorV2_5) WaitForSubscriptionCreatedEvent(timeout tim } } +func (v *EthereumVRFCoordinatorV2_5) WaitForSubscriptionCanceledEvent(subID *big.Int, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCanceled, error) { + eventsChannel := make(chan *vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCanceled) + subscription, err := v.coordinator.WatchSubscriptionCanceled(nil, eventsChannel, []*big.Int{subID}) + if err != nil { + return nil, err + } + defer subscription.Unsubscribe() + + for { + select { + case err := <-subscription.Err(): + return nil, err + case <-time.After(timeout): + return nil, fmt.Errorf("timeout waiting for SubscriptionCanceled event") + case sub := <-eventsChannel: + return sub, nil + } + } +} + func (v *EthereumVRFCoordinatorV2_5) WaitForRandomWordsFulfilledEvent(subID []*big.Int, requestID []*big.Int, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { randomWordsFulfilledEventsChannel := make(chan *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled) subscription, err := v.coordinator.WatchRandomWordsFulfilled(nil, randomWordsFulfilledEventsChannel, requestID, subID) diff --git a/integration-tests/load/vrfv2plus/config.go b/integration-tests/load/vrfv2plus/config.go index 50003c82865..a5439210c2d 100644 --- a/integration-tests/load/vrfv2plus/config.go +++ b/integration-tests/load/vrfv2plus/config.go @@ -57,8 +57,8 @@ type Funding struct { } type SubFunding struct { - SubFundsLink int64 `toml:"sub_funds_link"` - SubFundsNative int64 `toml:"sub_funds_native"` + SubFundsLink float64 `toml:"sub_funds_link"` + SubFundsNative float64 `toml:"sub_funds_native"` } type Soak struct { diff --git a/integration-tests/load/vrfv2plus/config.toml b/integration-tests/load/vrfv2plus/config.toml index 05e22bd51e8..e3200fafe22 100644 --- a/integration-tests/load/vrfv2plus/config.toml +++ b/integration-tests/load/vrfv2plus/config.toml @@ -9,8 +9,8 @@ node_funds = 10 [ExistingEnvConfig] coordinator_address = "0x27b61f155F772b291D1d9B478BeAd37B2Ae447b0" -consumer_address = "0x087F232165D9bA1A602f148025e5D0666953F64a" -sub_id = "52116875585187328970776211988181422347535732407068188096422095950800466618218" +#consumer_address = "0x087F232165D9bA1A602f148025e5D0666953F64a" +#sub_id = "52116875585187328970776211988181422347535732407068188096422095950800466618218" key_hash = "0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae" create_fund_subs_and_add_consumers = true link_address = "0x779877A7B0D9E8603169DdbD7836e478b4624789" @@ -31,7 +31,7 @@ rate_limit_unit_duration = "3s" rps = 1 randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting -number_of_sub_to_create = 5 +number_of_sub_to_create = 1 # approx 540 RPM - 3 tx requests per second with 4 rand requests in each tx [Stress] @@ -39,7 +39,7 @@ rate_limit_unit_duration = "1s" rps = 3 randomness_request_count_per_request = 4 # amount of randomness requests to make per one TX request randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting -number_of_sub_to_create = 5 +number_of_sub_to_create = 1 # approx 150 RPM - 1 tx request with 150 rand requests in each tx every 60 seconds [Spike] diff --git a/integration-tests/load/vrfv2plus/gun.go b/integration-tests/load/vrfv2plus/gun.go index c9947fa32f5..21be1c74ca7 100644 --- a/integration-tests/load/vrfv2plus/gun.go +++ b/integration-tests/load/vrfv2plus/gun.go @@ -15,7 +15,7 @@ type SingleHashGun struct { contracts *vrfv2plus.VRFV2_5Contracts keyHash [32]byte subIDs []*big.Int - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig logger zerolog.Logger } @@ -23,7 +23,7 @@ func NewSingleHashGun( contracts *vrfv2plus.VRFV2_5Contracts, keyHash [32]byte, subIDs []*big.Int, - vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, logger zerolog.Logger, ) *SingleHashGun { return &SingleHashGun{ @@ -52,6 +52,7 @@ func (m *SingleHashGun) Call(l *wasp.Generator) *wasp.CallResult { randBool(), randomnessRequestCountPerRequest, m.vrfv2PlusConfig, + m.vrfv2PlusConfig.RandomWordsFulfilledEventTimeout, m.logger, ) if err != nil { diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index e619cf78fd3..4d3de014bcd 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -27,6 +27,7 @@ var ( vrfv2PlusContracts *vrfv2plus.VRFV2_5Contracts vrfv2PlusData *vrfv2plus.VRFV2PlusData subIDs []*big.Int + eoaWalletAddress string labels = map[string]string{ "branch": "vrfv2Plus_healthcheck", @@ -85,6 +86,32 @@ func TestVRFV2PlusPerformance(t *testing.T) { WithCustomCleanup( func() { teardown(t, vrfv2PlusContracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2PlusConfig) + if env.EVMClient.NetworkSimulated() { + l.Info(). + Str("Network Name", env.EVMClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + //cancel subs and return funds to sub owner + for _, subID := range subIDs { + l.Info(). + 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) + if err != nil { + l.Error().Err(err).Msg("Error checking if pending requests exist") + } + if !pendingRequestsExist { + _, err := vrfv2PlusContracts.Coordinator.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) + if err != nil { + l.Error().Err(err).Msg("Error canceling subscription") + } + } else { + l.Error().Str("Sub ID", subID.String()).Msg("Pending requests exist for subscription, cannot cancel subscription and return funds") + } + + } + } }). Build() @@ -99,7 +126,14 @@ func TestVRFV2PlusPerformance(t *testing.T) { require.NoError(t, err) consumers, err = vrfv2plus.DeployVRFV2PlusConsumers(env.ContractDeployer, coordinator, 1) require.NoError(t, err) - subIDs, err = vrfv2plus.CreateFundSubsAndAddConsumers(env, &vrfv2PlusConfig, linkToken, coordinator, consumers, vrfv2PlusConfig.NumberOfSubToCreate) + subIDs, err = vrfv2plus.CreateFundSubsAndAddConsumers( + env, + vrfv2PlusConfig, + linkToken, + coordinator, + consumers, + vrfv2PlusConfig.NumberOfSubToCreate, + ) require.NoError(t, err) } else { consumer, err := env.ContractLoader.LoadVRFv2PlusLoadTestConsumer(vrfv2PlusConfig.ConsumerAddress) @@ -141,6 +175,25 @@ func TestVRFV2PlusPerformance(t *testing.T) { WithCustomCleanup( func() { teardown(t, vrfv2PlusContracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2PlusConfig) + + if env.EVMClient.NetworkSimulated() { + l.Info(). + Str("Network Name", env.EVMClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + for _, subID := range subIDs { + l.Info(). + Str("Returning funds from SubID", subID.String()). + Str("Returning funds to", eoaWalletAddress). + Msg("Canceling subscription and returning funds to subscription owner") + _, err := vrfv2PlusContracts.Coordinator.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) + if err != nil { + l.Error().Err(err).Msg("Error canceling subscription") + } + } + //err = vrfv2plus.ReturnFundsForFulfilledRequests(env.EVMClient, vrfv2PlusContracts.Coordinator, l) + //l.Error().Err(err).Msg("Error returning funds for fulfilled requests") + } if err := env.Cleanup(); err != nil { l.Error().Err(err).Msg("Error cleaning up test environment") } @@ -160,15 +213,18 @@ func TestVRFV2PlusPerformance(t *testing.T) { vrfv2PlusContracts, subIDs, vrfv2PlusData, err = vrfv2plus.SetupVRFV2_5Environment( env, - &vrfv2PlusConfig, + vrfv2PlusConfig, linkToken, mockETHLinkFeed, + //register proving key against EOA address in order to return funds to this address + env.EVMClient.GetDefaultWallet().Address(), 1, vrfv2PlusConfig.NumberOfSubToCreate, l, ) require.NoError(t, err, "error setting up VRF v2_5 env") } + eoaWalletAddress = env.EVMClient.GetDefaultWallet().Address() l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") for _, subID := range subIDs { @@ -186,7 +242,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { vrfv2PlusContracts, vrfv2PlusData.KeyHash, subIDs, - &vrfv2PlusConfig, + vrfv2PlusConfig, l, ), Labels: labels, diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index d7381c9cd33..acd548c88e2 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -2,6 +2,8 @@ package smoke import ( "context" + "fmt" + "github.com/smartcontractkit/chainlink/integration-tests/utils" "math/big" "testing" "time" @@ -45,7 +47,10 @@ func TestVRFv2Plus(t *testing.T) { linkToken, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err, "error deploying LINK contract") - vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, &vrfv2PlusConfig, linkToken, mockETHLinkFeed, 1, 1, l) + // register proving key against oracle address (sending key) in order to test oracleWithdraw + defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() + + vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, vrfv2PlusConfig, linkToken, mockETHLinkFeed, defaultWalletAddress, 1, 1, l) require.NoError(t, err, "error setting up VRF v2_5 env") subID := subIDs[0] @@ -55,7 +60,8 @@ func TestVRFv2Plus(t *testing.T) { vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) - t.Run("VRFV2 Plus With Link Billing", func(t *testing.T) { + t.Run("Link Billing", func(t *testing.T) { + testConfig := vrfv2PlusConfig var isNativeBilling = false subBalanceBeforeRequest := subscription.Balance @@ -69,8 +75,9 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, subID, isNativeBilling, - vrfv2PlusConfig.RandomnessRequestCountPerRequest, - &vrfv2PlusConfig, + testConfig.RandomnessRequestCountPerRequest, + testConfig, + testConfig.RandomWordsFulfilledEventTimeout, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -90,14 +97,14 @@ func TestVRFv2Plus(t *testing.T) { require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") - require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(status.RandomWords))) + require.Equal(t, testConfig.NumberOfWords, uint32(len(status.RandomWords))) for _, w := range status.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") } }) - - t.Run("VRFV2 Plus With Native Billing", func(t *testing.T) { + t.Run("Native Billing", func(t *testing.T) { + testConfig := vrfv2PlusConfig var isNativeBilling = true subNativeTokenBalanceBeforeRequest := subscription.NativeBalance @@ -111,8 +118,9 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, subID, isNativeBilling, - vrfv2PlusConfig.RandomnessRequestCountPerRequest, - &vrfv2PlusConfig, + testConfig.RandomnessRequestCountPerRequest, + testConfig, + testConfig.RandomWordsFulfilledEventTimeout, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -131,120 +139,451 @@ func TestVRFv2Plus(t *testing.T) { require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") - require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(status.RandomWords))) + require.Equal(t, testConfig.NumberOfWords, uint32(len(status.RandomWords))) for _, w := range status.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") } }) + t.Run("Direct Funding (VRFV2PlusWrapper)", func(t *testing.T) { + testConfig := vrfv2PlusConfig + wrapperContracts, wrapperSubID, err := vrfv2plus.SetupVRFV2PlusWrapperEnvironment( + env, + testConfig, + linkToken, + mockETHLinkFeed, + vrfv2PlusContracts.Coordinator, + vrfv2PlusData.KeyHash, + 1, + ) + require.NoError(t, err) - wrapperContracts, wrapperSubID, err := vrfv2plus.SetupVRFV2PlusWrapperEnvironment( - env, - &vrfv2PlusConfig, - linkToken, - mockETHLinkFeed, - vrfv2PlusContracts.Coordinator, - vrfv2PlusData.KeyHash, - 1, - ) - require.NoError(t, err) + t.Run("Link Billing", func(t *testing.T) { + testConfig := vrfv2PlusConfig + var isNativeBilling = false + + wrapperConsumerJuelsBalanceBeforeRequest, err := linkToken.BalanceOf(context.Background(), wrapperContracts.LoadTestConsumers[0].Address()) + require.NoError(t, err, "error getting wrapper consumer balance") + + wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + require.NoError(t, err, "error getting subscription information") + subBalanceBeforeRequest := wrapperSubscription.Balance + + randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment( + wrapperContracts.LoadTestConsumers[0], + vrfv2PlusContracts.Coordinator, + vrfv2PlusData, + wrapperSubID, + isNativeBilling, + testConfig, + testConfig.RandomWordsFulfilledEventTimeout, + l, + ) + require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + + expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) + wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + require.NoError(t, err, "error getting subscription information") + subBalanceAfterRequest := wrapperSubscription.Balance + require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) + + consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(context.Background(), randomWordsFulfilledEvent.RequestId) + require.NoError(t, err, "error getting rand request status") + require.True(t, consumerStatus.Fulfilled) + + expectedWrapperConsumerJuelsBalance := new(big.Int).Sub(wrapperConsumerJuelsBalanceBeforeRequest, consumerStatus.Paid) + + wrapperConsumerJuelsBalanceAfterRequest, err := linkToken.BalanceOf(context.Background(), wrapperContracts.LoadTestConsumers[0].Address()) + require.NoError(t, err, "error getting wrapper consumer balance") + require.Equal(t, expectedWrapperConsumerJuelsBalance, wrapperConsumerJuelsBalanceAfterRequest) + + //todo: uncomment when VRF-651 will be fixed + //require.Equal(t, 1, consumerStatus.Paid.Cmp(randomWordsFulfilledEvent.Payment), "Expected Consumer contract pay more than the Coordinator Sub") + vrfv2plus.LogFulfillmentDetailsLinkBilling(l, wrapperConsumerJuelsBalanceBeforeRequest, wrapperConsumerJuelsBalanceAfterRequest, consumerStatus, randomWordsFulfilledEvent) + + require.Equal(t, testConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) + for _, w := range consumerStatus.RandomWords { + l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") + require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") + } + }) + t.Run("Native Billing", func(t *testing.T) { + testConfig := vrfv2PlusConfig + var isNativeBilling = true + + wrapperConsumerBalanceBeforeRequestWei, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) + require.NoError(t, err, "error getting wrapper consumer balance") + + wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + require.NoError(t, err, "error getting subscription information") + subBalanceBeforeRequest := wrapperSubscription.NativeBalance + + randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment( + wrapperContracts.LoadTestConsumers[0], + vrfv2PlusContracts.Coordinator, + vrfv2PlusData, + wrapperSubID, + isNativeBilling, + testConfig, + testConfig.RandomWordsFulfilledEventTimeout, + l, + ) + require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + + expectedSubBalanceWei := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) + wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + require.NoError(t, err, "error getting subscription information") + subBalanceAfterRequest := wrapperSubscription.NativeBalance + require.Equal(t, expectedSubBalanceWei, subBalanceAfterRequest) + + consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(context.Background(), randomWordsFulfilledEvent.RequestId) + require.NoError(t, err, "error getting rand request status") + require.True(t, consumerStatus.Fulfilled) + + expectedWrapperConsumerWeiBalance := new(big.Int).Sub(wrapperConsumerBalanceBeforeRequestWei, consumerStatus.Paid) + + wrapperConsumerBalanceAfterRequestWei, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) + require.NoError(t, err, "error getting wrapper consumer balance") + require.Equal(t, expectedWrapperConsumerWeiBalance, wrapperConsumerBalanceAfterRequestWei) + + //todo: uncomment when VRF-651 will be fixed + //require.Equal(t, 1, consumerStatus.Paid.Cmp(randomWordsFulfilledEvent.Payment), "Expected Consumer contract pay more than the Coordinator Sub") + vrfv2plus.LogFulfillmentDetailsNativeBilling(l, wrapperConsumerBalanceBeforeRequestWei, wrapperConsumerBalanceAfterRequestWei, consumerStatus, randomWordsFulfilledEvent) + + require.Equal(t, testConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) + for _, w := range consumerStatus.RandomWords { + l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") + require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") + } + }) + }) + t.Run("Canceling Sub And Returning Funds", func(t *testing.T) { + testConfig := vrfv2PlusConfig + subIDsForCancelling, err := vrfv2plus.CreateFundSubsAndAddConsumers( + env, + testConfig, + linkToken, + vrfv2PlusContracts.Coordinator, + vrfv2PlusContracts.LoadTestConsumers, + 1, + ) + require.NoError(t, err) + subIDForCancelling := subIDsForCancelling[0] - t.Run("VRFV2 Plus With Direct Funding (VRFV2PlusWrapper) - Link Billing", func(t *testing.T) { - var isNativeBilling = false + testWalletAddress, err := actions.GenerateWallet() - wrapperConsumerJuelsBalanceBeforeRequest, err := linkToken.BalanceOf(context.Background(), wrapperContracts.LoadTestConsumers[0].Address()) - require.NoError(t, err, "error getting wrapper consumer balance") + testWalletBalanceNativeBeforeSubCancelling, err := env.EVMClient.BalanceAt(context.Background(), testWalletAddress) + require.NoError(t, err) + + testWalletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(context.Background(), testWalletAddress.String()) + require.NoError(t, err) - wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + subscriptionForCancelling, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subIDForCancelling) require.NoError(t, err, "error getting subscription information") - subBalanceBeforeRequest := wrapperSubscription.Balance - randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment( - wrapperContracts.LoadTestConsumers[0], + subBalanceLink := subscriptionForCancelling.Balance + subBalanceNative := subscriptionForCancelling.NativeBalance + l.Info(). + Str("Subscription Amount Native", subBalanceNative.String()). + Str("Subscription Amount Link", subBalanceLink.String()). + 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) + require.NoError(t, err, "Error canceling subscription") + + subscriptionCanceledEvent, err := vrfv2PlusContracts.Coordinator.WaitForSubscriptionCanceledEvent(subIDForCancelling, time.Second*30) + require.NoError(t, err, "error waiting for subscription canceled event") + + cancellationTxReceipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) + require.NoError(t, err, "error getting tx cancellation Tx Receipt") + + txGasUsed := new(big.Int).SetUint64(cancellationTxReceipt.GasUsed) + cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTxReceipt.EffectiveGasPrice) + + l.Info(). + Str("Cancellation Tx Fee Wei", cancellationTxFeeWei.String()). + Str("Effective Gas Price", cancellationTxReceipt.EffectiveGasPrice.String()). + Uint64("Gas Used", cancellationTxReceipt.GasUsed). + Msg("Cancellation TX Receipt") + + l.Info(). + Str("Returned Subscription Amount Native", subscriptionCanceledEvent.AmountNative.String()). + Str("Returned Subscription Amount Link", subscriptionCanceledEvent.AmountLink.String()). + Str("SubID", subscriptionCanceledEvent.SubId.String()). + Str("Returned to", subscriptionCanceledEvent.To.String()). + Msg("Subscription Canceled Event") + + require.Equal(t, subBalanceNative, subscriptionCanceledEvent.AmountNative, "SubscriptionCanceled event native amount is not equal to sub amount while canceling subscription") + require.Equal(t, subBalanceLink, subscriptionCanceledEvent.AmountLink, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") + + testWalletBalanceNativeAfterSubCancelling, err := env.EVMClient.BalanceAt(context.Background(), testWalletAddress) + require.NoError(t, err) + + testWalletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(context.Background(), testWalletAddress.String()) + require.NoError(t, err) + + //Verify that sub was deleted from Coordinator + _, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), 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) + subFundsReturnedLinkActual := new(big.Int).Sub(testWalletBalanceLinkAfterSubCancelling, testWalletBalanceLinkBeforeSubCancelling) + + subFundsReturnedNativeExpected := new(big.Int).Sub(subBalanceNative, cancellationTxFeeWei) + deltaSpentOnCancellationTxFee := new(big.Int).Sub(subBalanceNative, subFundsReturnedNativeActual) + l.Info(). + Str("Sub Balance - Native", subBalanceNative.String()). + Str("Delta Spent On Cancellation Tx Fee - `NativeBalance - subFundsReturnedNativeActual`", deltaSpentOnCancellationTxFee.String()). + Str("Cancellation Tx Fee Wei", cancellationTxFeeWei.String()). + Str("Sub Funds Returned Actual - Native", subFundsReturnedNativeActual.String()). + Str("Sub Funds Returned Expected - `NativeBalance - cancellationTxFeeWei`", subFundsReturnedNativeExpected.String()). + Str("Sub Funds Returned Actual - Link", subFundsReturnedLinkActual.String()). + Str("Sub Balance - Link", subBalanceLink.String()). + Msg("Sub funds returned") + + //todo - this fails on SIMULATED env as tx cost is calculated different as for testnets and it's not receipt.EffectiveGasPrice*receipt.GasUsed + //require.Equal(t, subFundsReturnedNativeExpected, subFundsReturnedNativeActual, "Returned funds are not equal to sub balance that was cancelled") + require.Equal(t, 1, testWalletBalanceNativeAfterSubCancelling.Cmp(testWalletBalanceNativeBeforeSubCancelling), "Native funds were not returned after sub cancellation") + require.Equal(t, 0, subBalanceLink.Cmp(subFundsReturnedLinkActual), "Returned LINK funds are not equal to sub balance that was cancelled") + + }) + t.Run("Owner Canceling Sub And Returning Funds While Having Pending Requests", func(t *testing.T) { + testConfig := vrfv2PlusConfig + //underfund subs in order rand fulfillments to fail + testConfig.SubscriptionFundingAmountNative = float64(0.000000000000000001) //1 Wei + testConfig.SubscriptionFundingAmountLink = float64(0.000000000000000001) //1 Juels + + subIDsForCancelling, err := vrfv2plus.CreateFundSubsAndAddConsumers( + env, + testConfig, + linkToken, vrfv2PlusContracts.Coordinator, - vrfv2PlusData, - wrapperSubID, - isNativeBilling, - &vrfv2PlusConfig, - l, + vrfv2PlusContracts.LoadTestConsumers, + 1, ) - require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + require.NoError(t, err) - expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + subIDForCancelling := subIDsForCancelling[0] + + subscriptionForCancelling, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subIDForCancelling) require.NoError(t, err, "error getting subscription information") - subBalanceAfterRequest := wrapperSubscription.Balance - require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) - consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(context.Background(), randomWordsFulfilledEvent.RequestId) - require.NoError(t, err, "error getting rand request status") - require.True(t, consumerStatus.Fulfilled) + vrfv2plus.LogSubDetails(l, subscriptionForCancelling, subIDForCancelling, vrfv2PlusContracts.Coordinator) - expectedWrapperConsumerJuelsBalance := new(big.Int).Sub(wrapperConsumerJuelsBalanceBeforeRequest, consumerStatus.Paid) + activeSubscriptionIdsBeforeSubCancellation, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(context.Background(), big.NewInt(0), big.NewInt(0)) + require.NoError(t, err) - wrapperConsumerJuelsBalanceAfterRequest, err := linkToken.BalanceOf(context.Background(), wrapperContracts.LoadTestConsumers[0].Address()) - require.NoError(t, err, "error getting wrapper consumer balance") - require.Equal(t, expectedWrapperConsumerJuelsBalance, wrapperConsumerJuelsBalanceAfterRequest) + require.True(t, utils.BigIntSliceContains(activeSubscriptionIdsBeforeSubCancellation, subIDForCancelling)) - //todo: uncomment when VRF-651 will be fixed - //require.Equal(t, 1, consumerStatus.Paid.Cmp(randomWordsFulfilledEvent.Payment), "Expected Consumer contract pay more than the Coordinator Sub") - vrfv2plus.LogFulfillmentDetailsLinkBilling(l, wrapperConsumerJuelsBalanceBeforeRequest, wrapperConsumerJuelsBalanceAfterRequest, consumerStatus, randomWordsFulfilledEvent) + pendingRequestsExist, err := vrfv2PlusContracts.Coordinator.PendingRequestsExist(context.Background(), subIDForCancelling) + require.NoError(t, err) + require.False(t, pendingRequestsExist, "Pending requests should not exist") - require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) - for _, w := range consumerStatus.RandomWords { - l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") - require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") - } - }) + _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( + vrfv2PlusContracts.LoadTestConsumers[0], + vrfv2PlusContracts.Coordinator, + vrfv2PlusData, + subIDForCancelling, + false, + testConfig.RandomnessRequestCountPerRequest, + testConfig, + 5*time.Second, + l, + ) - t.Run("VRFV2 Plus With Direct Funding (VRFV2PlusWrapper) - Native Billing", func(t *testing.T) { - var isNativeBilling = true + require.Error(t, err, "error should occur for waiting for fulfilment due to low sub balance") - wrapperConsumerBalanceBeforeRequestWei, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) - require.NoError(t, err, "error getting wrapper consumer balance") + _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( + vrfv2PlusContracts.LoadTestConsumers[0], + vrfv2PlusContracts.Coordinator, + vrfv2PlusData, + subIDForCancelling, + true, + testConfig.RandomnessRequestCountPerRequest, + testConfig, + testConfig.RandomWordsFulfilledEventTimeout, + l, + ) - wrapperSubscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) + require.Error(t, err, "error should occur for waiting for fulfilment due to low sub balance") + + pendingRequestsExist, err = vrfv2PlusContracts.Coordinator.PendingRequestsExist(context.Background(), subIDForCancelling) + require.NoError(t, err) + require.True(t, pendingRequestsExist, "Pending requests should exist after unfulfilled rand requests due to low sub balance") + + walletBalanceNativeBeforeSubCancelling, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(defaultWalletAddress)) + require.NoError(t, err) + + walletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(context.Background(), defaultWalletAddress) + require.NoError(t, err) + + subscriptionForCancelling, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subIDForCancelling) require.NoError(t, err, "error getting subscription information") - subBalanceBeforeRequest := wrapperSubscription.NativeBalance - randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment( - wrapperContracts.LoadTestConsumers[0], + subBalanceLink := subscriptionForCancelling.Balance + subBalanceNative := subscriptionForCancelling.NativeBalance + l.Info(). + Str("Subscription Amount Native", subBalanceNative.String()). + Str("Subscription Amount Link", subBalanceLink.String()). + 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) + require.NoError(t, err, "Error canceling subscription") + + subscriptionCanceledEvent, err := vrfv2PlusContracts.Coordinator.WaitForSubscriptionCanceledEvent(subIDForCancelling, time.Second*30) + require.NoError(t, err, "error waiting for subscription canceled event") + + cancellationTxReceipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) + require.NoError(t, err, "error getting tx cancellation Tx Receipt") + + txGasUsed := new(big.Int).SetUint64(cancellationTxReceipt.GasUsed) + cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTxReceipt.EffectiveGasPrice) + + l.Info(). + Str("Cancellation Tx Fee Wei", cancellationTxFeeWei.String()). + Str("Effective Gas Price", cancellationTxReceipt.EffectiveGasPrice.String()). + Uint64("Gas Used", cancellationTxReceipt.GasUsed). + Msg("Cancellation TX Receipt") + + l.Info(). + Str("Returned Subscription Amount Native", subscriptionCanceledEvent.AmountNative.String()). + Str("Returned Subscription Amount Link", subscriptionCanceledEvent.AmountLink.String()). + Str("SubID", subscriptionCanceledEvent.SubId.String()). + Str("Returned to", subscriptionCanceledEvent.To.String()). + Msg("Subscription Canceled Event") + + require.Equal(t, subBalanceNative, subscriptionCanceledEvent.AmountNative, "SubscriptionCanceled event native amount is not equal to sub amount while canceling subscription") + require.Equal(t, subBalanceLink, subscriptionCanceledEvent.AmountLink, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") + + walletBalanceNativeAfterSubCancelling, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(defaultWalletAddress)) + require.NoError(t, err) + + walletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(context.Background(), defaultWalletAddress) + require.NoError(t, err) + + //Verify that sub was deleted from Coordinator + _, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subIDForCancelling) + fmt.Println("err", err) + 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) + subFundsReturnedLinkActual := new(big.Int).Sub(walletBalanceLinkAfterSubCancelling, walletBalanceLinkBeforeSubCancelling) + + subFundsReturnedNativeExpected := new(big.Int).Sub(subBalanceNative, cancellationTxFeeWei) + deltaSpentOnCancellationTxFee := new(big.Int).Sub(subBalanceNative, subFundsReturnedNativeActual) + l.Info(). + Str("Sub Balance - Native", subBalanceNative.String()). + Str("Delta Spent On Cancellation Tx Fee - `NativeBalance - subFundsReturnedNativeActual`", deltaSpentOnCancellationTxFee.String()). + Str("Cancellation Tx Fee Wei", cancellationTxFeeWei.String()). + Str("Sub Funds Returned Actual - Native", subFundsReturnedNativeActual.String()). + Str("Sub Funds Returned Expected - `NativeBalance - cancellationTxFeeWei`", subFundsReturnedNativeExpected.String()). + Str("Sub Funds Returned Actual - Link", subFundsReturnedLinkActual.String()). + Str("Sub Balance - Link", subBalanceLink.String()). + Str("walletBalanceNativeBeforeSubCancelling", walletBalanceNativeBeforeSubCancelling.String()). + Str("walletBalanceNativeAfterSubCancelling", walletBalanceNativeAfterSubCancelling.String()). + Msg("Sub funds returned") + + //todo - need to use different wallet for each test to verify exact amount of Native/LINK returned + //todo - as defaultWallet is used in other tests in parallel which might affect the balance + //require.Equal(t, 1, walletBalanceNativeAfterSubCancelling.Cmp(walletBalanceNativeBeforeSubCancelling), "Native funds were not returned after sub cancellation") + + //todo - this fails on SIMULATED env as tx cost is calculated different as for testnets and it's not receipt.EffectiveGasPrice*receipt.GasUsed + //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(context.Background(), big.NewInt(0), big.NewInt(0)) + require.NoError(t, err, "error getting active subscription ids") + + require.False( + t, + utils.BigIntSliceContains(activeSubscriptionIdsAfterSubCancellation, subIDForCancelling), + "Active subscription ids should not contain sub id after sub cancellation", + ) + }) + t.Run("Oracle Withdraw", func(t *testing.T) { + testConfig := vrfv2PlusConfig + subIDsForOracleWithDraw, err := vrfv2plus.CreateFundSubsAndAddConsumers( + env, + testConfig, + linkToken, + vrfv2PlusContracts.Coordinator, + vrfv2PlusContracts.LoadTestConsumers, + 1, + ) + require.NoError(t, err) + subIDForOracleWithdraw := subIDsForOracleWithDraw[0] + + fulfilledEventLink, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( + vrfv2PlusContracts.LoadTestConsumers[0], vrfv2PlusContracts.Coordinator, vrfv2PlusData, - wrapperSubID, - isNativeBilling, - &vrfv2PlusConfig, + subIDForOracleWithdraw, + false, + testConfig.RandomnessRequestCountPerRequest, + testConfig, + testConfig.RandomWordsFulfilledEventTimeout, l, ) - require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + require.NoError(t, err) - expectedSubBalanceWei := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - wrapperSubscription, err = vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), wrapperSubID) - require.NoError(t, err, "error getting subscription information") - subBalanceAfterRequest := wrapperSubscription.NativeBalance - require.Equal(t, expectedSubBalanceWei, subBalanceAfterRequest) + fulfilledEventNative, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( + vrfv2PlusContracts.LoadTestConsumers[0], + vrfv2PlusContracts.Coordinator, + vrfv2PlusData, + subIDForOracleWithdraw, + true, + testConfig.RandomnessRequestCountPerRequest, + testConfig, + testConfig.RandomWordsFulfilledEventTimeout, + l, + ) + require.NoError(t, err) + amountToWithdrawLink := fulfilledEventLink.Payment - consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(context.Background(), randomWordsFulfilledEvent.RequestId) - require.NoError(t, err, "error getting rand request status") - require.True(t, consumerStatus.Fulfilled) + defaultWalletBalanceNativeBeforeOracleWithdraw, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(defaultWalletAddress)) + require.NoError(t, err) - expectedWrapperConsumerWeiBalance := new(big.Int).Sub(wrapperConsumerBalanceBeforeRequestWei, consumerStatus.Paid) + defaultWalletBalanceLinkBeforeOracleWithdraw, err := linkToken.BalanceOf(context.Background(), defaultWalletAddress) + require.NoError(t, err) - wrapperConsumerBalanceAfterRequestWei, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) - require.NoError(t, err, "error getting wrapper consumer balance") - require.Equal(t, expectedWrapperConsumerWeiBalance, wrapperConsumerBalanceAfterRequestWei) + l.Info(). + Str("Returning to", defaultWalletAddress). + Str("Amount", amountToWithdrawLink.String()). + Msg("Invoking Oracle Withdraw for LINK") - //todo: uncomment when VRF-651 will be fixed - //require.Equal(t, 1, consumerStatus.Paid.Cmp(randomWordsFulfilledEvent.Payment), "Expected Consumer contract pay more than the Coordinator Sub") - vrfv2plus.LogFulfillmentDetailsNativeBilling(l, wrapperConsumerBalanceBeforeRequestWei, wrapperConsumerBalanceAfterRequestWei, consumerStatus, randomWordsFulfilledEvent) + err = vrfv2PlusContracts.Coordinator.OracleWithdraw( + common.HexToAddress(defaultWalletAddress), + amountToWithdrawLink, + ) + require.NoError(t, err, "error withdrawing LINK from coordinator to default wallet") + amountToWithdrawNative := fulfilledEventNative.Payment - require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) - for _, w := range consumerStatus.RandomWords { - l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") - require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") - } - }) + l.Info(). + Str("Returning to", defaultWalletAddress). + Str("Amount", amountToWithdrawNative.String()). + Msg("Invoking Oracle Withdraw for Native") + + err = vrfv2PlusContracts.Coordinator.OracleWithdrawNative( + common.HexToAddress(defaultWalletAddress), + amountToWithdrawNative, + ) + require.NoError(t, err, "error withdrawing Native tokens from coordinator to default wallet") + + err = env.EVMClient.WaitForEvents() + require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) + defaultWalletBalanceNativeAfterOracleWithdraw, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(defaultWalletAddress)) + require.NoError(t, err) + + defaultWalletBalanceLinkAfterOracleWithdraw, err := linkToken.BalanceOf(context.Background(), defaultWalletAddress) + require.NoError(t, err) + + //not possible to verify exact amount of Native/LINK returned as defaultWallet is used in other tests in parallel which might affect the balance + require.Equal(t, 1, defaultWalletBalanceNativeAfterOracleWithdraw.Cmp(defaultWalletBalanceNativeBeforeOracleWithdraw), "Native funds were not returned after oracle withdraw native") + require.Equal(t, 1, defaultWalletBalanceLinkAfterOracleWithdraw.Cmp(defaultWalletBalanceLinkBeforeOracleWithdraw), "LINK funds were not returned after oracle withdraw") + }) } func TestVRFv2PlusMigration(t *testing.T) { @@ -270,7 +609,10 @@ 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(env, &vrfv2PlusConfig, linkAddress, mockETHLinkFeedAddress, 2, 1, l) + nativeTokenPrimaryKeyAddress, err := env.ClCluster.NodeAPIs()[0].PrimaryEthAddress() + require.NoError(t, err, "error getting primary eth address") + + vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, vrfv2PlusConfig, linkAddress, mockETHLinkFeedAddress, nativeTokenPrimaryKeyAddress, 2, 1, l) require.NoError(t, err, "error setting up VRF v2_5 env") subID := subIDs[0] @@ -395,10 +737,10 @@ func TestVRFv2PlusMigration(t *testing.T) { expectedLinkTotalBalanceForOldCoordinator := new(big.Int).Sub(oldCoordinatorLinkTotalBalanceBeforeMigration, oldSubscriptionBeforeMigration.Balance) expectedEthTotalBalanceForOldCoordinator := new(big.Int).Sub(oldCoordinatorEthTotalBalanceBeforeMigration, oldSubscriptionBeforeMigration.NativeBalance) - require.Equal(t, expectedLinkTotalBalanceForMigratedCoordinator, migratedCoordinatorLinkTotalBalanceAfterMigration) - require.Equal(t, expectedEthTotalBalanceForMigratedCoordinator, migratedCoordinatorEthTotalBalanceAfterMigration) - require.Equal(t, expectedLinkTotalBalanceForOldCoordinator, oldCoordinatorLinkTotalBalanceAfterMigration) - require.Equal(t, expectedEthTotalBalanceForOldCoordinator, oldCoordinatorEthTotalBalanceAfterMigration) + require.Equal(t, 0, expectedLinkTotalBalanceForMigratedCoordinator.Cmp(migratedCoordinatorLinkTotalBalanceAfterMigration)) + require.Equal(t, 0, expectedEthTotalBalanceForMigratedCoordinator.Cmp(migratedCoordinatorEthTotalBalanceAfterMigration)) + require.Equal(t, 0, expectedLinkTotalBalanceForOldCoordinator.Cmp(oldCoordinatorLinkTotalBalanceAfterMigration)) + require.Equal(t, 0, expectedEthTotalBalanceForOldCoordinator.Cmp(oldCoordinatorEthTotalBalanceAfterMigration)) //Verify rand requests fulfills with Link Token billing _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillmentUpgraded( @@ -407,7 +749,7 @@ func TestVRFv2PlusMigration(t *testing.T) { vrfv2PlusData, subID, false, - &vrfv2PlusConfig, + vrfv2PlusConfig, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -419,7 +761,7 @@ func TestVRFv2PlusMigration(t *testing.T) { vrfv2PlusData, subID, true, - &vrfv2PlusConfig, + vrfv2PlusConfig, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") diff --git a/integration-tests/utils/common.go b/integration-tests/utils/common.go index c8243097a7d..9aacaeed416 100644 --- a/integration-tests/utils/common.go +++ b/integration-tests/utils/common.go @@ -1,6 +1,7 @@ package utils import ( + "math/big" "net" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -23,3 +24,12 @@ func MustIP(s string) *net.IP { } return &ip } + +func BigIntSliceContains(slice []*big.Int, b *big.Int) bool { + for _, a := range slice { + if b.Cmp(a) == 0 { + return true + } + } + return false +}