Skip to content

Commit

Permalink
VRF-329: add BHS CTF test (#11890)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
iljapavlovs authored Feb 7, 2024
1 parent 1df59ca commit 5c7c7ce
Show file tree
Hide file tree
Showing 24 changed files with 1,526 additions and 783 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
78 changes: 77 additions & 1 deletion integration-tests/actions/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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"
)
Expand Down Expand Up @@ -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
}
}
}
137 changes: 137 additions & 0 deletions integration-tests/actions/vrf/common/actions.go
Original file line number Diff line number Diff line change
@@ -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
}
27 changes: 27 additions & 0 deletions integration-tests/actions/vrf/common/errors.go
Original file line number Diff line number Diff line change
@@ -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"
)
69 changes: 69 additions & 0 deletions integration-tests/actions/vrf/common/models.go
Original file line number Diff line number Diff line change
@@ -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
}
10 changes: 10 additions & 0 deletions integration-tests/actions/vrf/vrfv2/errors.go
Original file line number Diff line number Diff line change
@@ -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"
)
Loading

0 comments on commit 5c7c7ce

Please sign in to comment.