Skip to content

Commit

Permalink
Use Seth EVM client in E2E VRF tests (#12964)
Browse files Browse the repository at this point in the history
* WIP: smoke/vrfv2_test.go

* wip 2

* wip 3

* wip 4

* wip 5

* wip 6

* wip 7

* wip 8

* fix

* wip 9

* wip 10

* fix

* fix go mod

* fix

* fix lint

* fix

* Fix

* fix vrfv2plus

* fix 2

* fix

* wip

* bump gas limit for sending funds to EOA

* check receipt when sending funds

* fix go mod

* Fix test context

* use latest Seth that estimates gas for funds sending

* adding Polygon Amoy and Arb Sepolia with default config; small refactoring

* Fix passing wrapped contract backend

* Use MustGetRootKeyAddress()

* Show funding amount in ETH

* Remove legacy vrf code

* Fix lint

* Fix lint 2

* Use AnySyncedKey in wasp guns

* Log key num

* Add RequestRandomnessFromKey and use GetChainClientWithConfigFunction in load tests

* Extract events from tx logs

* Use SethRootKeyIndex

* Fix getting event data

* Fix parsing events

* Fix load tests

* Do not use AnySyncedKey

* Support multiple keys with AvailableSethKeyNum

---------

Co-authored-by: Bartek Tofel <[email protected]>
Co-authored-by: Ilja Pavlovs <[email protected]>
  • Loading branch information
3 people authored May 16, 2024
1 parent aeb9f4d commit 7be3506
Show file tree
Hide file tree
Showing 34 changed files with 2,041 additions and 2,647 deletions.
67 changes: 24 additions & 43 deletions integration-tests/actions/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import (
"github.com/rs/zerolog/log"
"go.uber.org/zap/zapcore"

"github.com/smartcontractkit/seth"

"github.com/smartcontractkit/chainlink-testing-framework/blockchain"
ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client"
"github.com/smartcontractkit/chainlink-testing-framework/k8s/environment"
Expand Down Expand Up @@ -474,36 +476,12 @@ func GenerateWallet() (common.Address, error) {
return crypto.PubkeyToAddress(*publicKeyECDSA), nil
}

// todo - move to CTF
func FundAddress(client blockchain.EVMClient, sendingKey string, fundingToSendEth *big.Float) error {
address := common.HexToAddress(sendingKey)
gasEstimates, err := client.EstimateGas(ethereum.CallMsg{
To: &address,
})
if err != nil {
return err
}
err = client.Fund(sendingKey, fundingToSendEth, gasEstimates)
if err != nil {
return err
}
return nil
}

// todo - move to CTF
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))
Expand All @@ -523,42 +501,50 @@ func DecodeTxInputData(abiString string, data []byte) (map[string]interface{}, e
return inputsMap, nil
}

// todo - move to EVMClient
// todo - move to CTF
func WaitForBlockNumberToBe(
waitForBlockNumberToBe uint64,
client blockchain.EVMClient,
client *seth.Client,
wg *sync.WaitGroup,
timeout time.Duration,
t testing.TB,
l zerolog.Logger,
) (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
ticker := time.NewTicker(time.Second * 5)
var latestBlockNumber uint64
for {
select {
case <-testContext.Done():
ticker.Stop()
wg.Done()
return blockNumber,
return latestBlockNumber,
fmt.Errorf("timeout waiting for Block Number to be: %d. Last recorded block number was: %d",
waitForBlockNumberToBe, blockNumber)
waitForBlockNumberToBe, latestBlockNumber)
case <-ticker.C:
go func() {
currentBlockNumber, err := client.LatestBlockNumber(testcontext.Get(t))
currentBlockNumber, err := client.Client.BlockNumber(testcontext.Get(t))
if err != nil {
errorChannel <- err
}
l.Info().
Uint64("Latest Block Number", currentBlockNumber).
Uint64("Desired Block Number", waitForBlockNumberToBe).
Msg("Waiting for Block Number to be")
blockNumberChannel <- currentBlockNumber
}()
case blockNumber = <-blockNumberChannel:
if blockNumber == waitForBlockNumberToBe {
case latestBlockNumber = <-blockNumberChannel:
if latestBlockNumber >= waitForBlockNumberToBe {
ticker.Stop()
wg.Done()
return blockNumber, nil
l.Info().
Uint64("Latest Block Number", latestBlockNumber).
Uint64("Desired Block Number", waitForBlockNumberToBe).
Msg("Desired Block Number reached!")
return latestBlockNumber, nil
}
case err := <-errorChannel:
ticker.Stop()
Expand All @@ -571,12 +557,12 @@ func WaitForBlockNumberToBe(
// todo - move to EVMClient
func RewindSimulatedChainToBlockNumber(
ctx context.Context,
evmClient blockchain.EVMClient,
client *seth.Client,
rpcURL string,
rewindChainToBlockNumber uint64,
l zerolog.Logger,
) (uint64, error) {
latestBlockNumberBeforeReorg, err := evmClient.LatestBlockNumber(ctx)
latestBlockNumberBeforeReorg, err := client.Client.BlockNumber(ctx)
if err != nil {
return 0, fmt.Errorf("error getting latest block number: %w", err)
}
Expand All @@ -593,12 +579,7 @@ func RewindSimulatedChainToBlockNumber(
return 0, fmt.Errorf("error making reorg: %w", err)
}

err = evmClient.WaitForEvents()
if err != nil {
return 0, fmt.Errorf("error waiting for events: %w", err)
}

latestBlockNumberAfterReorg, err := evmClient.LatestBlockNumber(ctx)
latestBlockNumberAfterReorg, err := client.Client.BlockNumber(ctx)
if err != nil {
return 0, fmt.Errorf("error getting latest block number: %w", err)
}
Expand Down
58 changes: 13 additions & 45 deletions integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,18 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/seth"

ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types"

"github.com/smartcontractkit/chainlink-testing-framework/blockchain"
"github.com/smartcontractkit/chainlink-testing-framework/logging"
"github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext"

actions_seth "github.com/smartcontractkit/chainlink/integration-tests/actions/seth"
chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype"

"github.com/smartcontractkit/chainlink/integration-tests/actions"
"github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants"
"github.com/smartcontractkit/chainlink/integration-tests/client"
"github.com/smartcontractkit/chainlink/integration-tests/contracts"
Expand Down Expand Up @@ -164,45 +166,32 @@ func SetAndGetOCR2VRFPluginConfig(
return ocr2VRFPluginConfig
}

func FundVRFCoordinatorV3Subscription(t *testing.T, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV3, chainClient blockchain.EVMClient, subscriptionID, linkFundingAmount *big.Int) {
func FundVRFCoordinatorV3Subscription(t *testing.T, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV3, subscriptionID, linkFundingAmount *big.Int) {
encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint256"}]`, subscriptionID)
require.NoError(t, err, "Error Abi encoding subscriptionID")
_, err = linkToken.TransferAndCall(coordinator.Address(), big.NewInt(0).Mul(linkFundingAmount, big.NewInt(1e18)), encodedSubId)
require.NoError(t, err, "Error sending Link token")
err = chainClient.WaitForEvents()
require.NoError(t, err, "Error waiting for TXs to complete")
}

func DeployOCR2VRFContracts(t *testing.T, contractDeployer contracts.ContractDeployer, chainClient blockchain.EVMClient, linkToken contracts.LinkToken, beaconPeriodBlocksCount *big.Int, keyID string) (contracts.DKG, contracts.VRFCoordinatorV3, contracts.VRFBeacon, contracts.VRFBeaconConsumer) {
dkg, err := contractDeployer.DeployDKG()
func DeployOCR2VRFContracts(t *testing.T, chainClient *seth.Client, linkToken contracts.LinkToken, beaconPeriodBlocksCount *big.Int, keyID string) (contracts.DKG, contracts.VRFCoordinatorV3, contracts.VRFBeacon, contracts.VRFBeaconConsumer) {
dkg, err := contracts.DeployDKG(chainClient)
require.NoError(t, err, "Error deploying DKG Contract")

err = chainClient.WaitForEvents()
require.NoError(t, err, "Error waiting for TXs to complete")

coordinator, err := contractDeployer.DeployOCR2VRFCoordinator(beaconPeriodBlocksCount, linkToken.Address())
coordinator, err := contracts.DeployOCR2VRFCoordinator(chainClient, beaconPeriodBlocksCount, linkToken.Address())
require.NoError(t, err, "Error deploying OCR2VRFCoordinator Contract")

err = chainClient.WaitForEvents()
require.NoError(t, err, "Error waiting for TXs to complete")

vrfBeacon, err := contractDeployer.DeployVRFBeacon(coordinator.Address(), linkToken.Address(), dkg.Address(), keyID)
vrfBeacon, err := contracts.DeployVRFBeacon(chainClient, coordinator.Address(), linkToken.Address(), dkg.Address(), keyID)
require.NoError(t, err, "Error deploying VRFBeacon Contract")
err = chainClient.WaitForEvents()
require.NoError(t, err, "Error waiting for TXs to complete")

consumer, err := contractDeployer.DeployVRFBeaconConsumer(coordinator.Address(), beaconPeriodBlocksCount)
consumer, err := contracts.DeployVRFBeaconConsumer(chainClient, coordinator.Address(), beaconPeriodBlocksCount)
require.NoError(t, err, "Error deploying VRFBeaconConsumer Contract")

err = chainClient.WaitForEvents()
require.NoError(t, err, "Error waiting for TXs to complete")
return dkg, coordinator, vrfBeacon, consumer
}

func RequestAndRedeemRandomness(
t *testing.T,
consumer contracts.VRFBeaconConsumer,
chainClient blockchain.EVMClient,
vrfBeacon contracts.VRFBeacon,
numberOfRandomWordsToRequest uint16,
subscriptionID,
Expand All @@ -218,9 +207,6 @@ func RequestAndRedeemRandomness(
require.NoError(t, err, "Error requesting randomness from Consumer Contract")
l.Info().Interface("TX Hash", receipt.TxHash).Msg("Randomness requested from Consumer contract")

err = chainClient.WaitForEvents()
require.NoError(t, err, "Error waiting for TXs to complete")

requestID := getRequestId(t, consumer, receipt, confirmationDelay)

newTransmissionEvent, err := vrfBeacon.WaitForNewTransmissionEvent(randomnessTransmissionEventTimeout)
Expand All @@ -229,16 +215,13 @@ func RequestAndRedeemRandomness(

err = consumer.RedeemRandomness(subscriptionID, requestID)
require.NoError(t, err, "Error redeeming randomness from Consumer Contract")
err = chainClient.WaitForEvents()
require.NoError(t, err, "Error waiting for TXs to complete")

return requestID
}

func RequestRandomnessFulfillmentAndWaitForFulfilment(
t *testing.T,
consumer contracts.VRFBeaconConsumer,
chainClient blockchain.EVMClient,
vrfBeacon contracts.VRFBeacon,
numberOfRandomWordsToRequest uint16,
subscriptionID *big.Int,
Expand All @@ -257,18 +240,12 @@ func RequestRandomnessFulfillmentAndWaitForFulfilment(
require.NoError(t, err, "Error requesting Randomness Fulfillment")
l.Info().Interface("TX Hash", receipt.TxHash).Msg("Randomness Fulfillment requested from Consumer contract")

err = chainClient.WaitForEvents()
require.NoError(t, err, "Error waiting for TXs to complete")

requestID := getRequestId(t, consumer, receipt, confirmationDelay)

newTransmissionEvent, err := vrfBeacon.WaitForNewTransmissionEvent(randomnessTransmissionEventTimeout)
require.NoError(t, err, "Error waiting for NewTransmission event from VRF Beacon Contract")
l.Info().Interface("NewTransmission event", newTransmissionEvent).Msg("Randomness Fulfillment transmitted by DON")

err = chainClient.WaitForEvents()
require.NoError(t, err, "Error waiting for TXs to complete")

return requestID
}

Expand All @@ -290,20 +267,19 @@ func SetupOCR2VRFUniverse(
t *testing.T,
linkToken contracts.LinkToken,
mockETHLinkFeed contracts.MockETHLINKFeed,
contractDeployer contracts.ContractDeployer,
chainClient blockchain.EVMClient,
chainClient *seth.Client,
nodeAddresses []common.Address,
chainlinkNodes []*client.ChainlinkK8sClient,
testNetwork blockchain.EVMNetwork,
) (contracts.DKG, contracts.VRFCoordinatorV3, contracts.VRFBeacon, contracts.VRFBeaconConsumer, *big.Int) {
l := logging.GetTestLogger(t)

// Deploy DKG contract
// Deploy VRFCoordinator(beaconPeriodBlocks, linkAddress, linkEthfeedAddress)
// Deploy VRFBeacon
// Deploy Consumer Contract
dkgContract, coordinatorContract, vrfBeaconContract, consumerContract := DeployOCR2VRFContracts(
t,
contractDeployer,
chainClient,
linkToken,
ocr2vrf_constants.BeaconPeriodBlocksCount,
Expand All @@ -318,30 +294,23 @@ func SetupOCR2VRFUniverse(
require.NoError(t, err, "Error setting Producer for VRFCoordinator contract")
err = coordinatorContract.SetConfig(2.5e6, 160 /* 5 EVM words */)
require.NoError(t, err, "Error setting config for VRFCoordinator contract")
err = chainClient.WaitForEvents()
require.NoError(t, err, "Error waiting for TXs to complete")

// Subscription:
//1. Create Subscription
err = coordinatorContract.CreateSubscription()
require.NoError(t, err, "Error creating subscription in VRFCoordinator contract")
err = chainClient.WaitForEvents()
require.NoError(t, err, "Error waiting for TXs to complete")
subID, err := coordinatorContract.FindSubscriptionID()
require.NoError(t, err)

//2. Add Consumer to subscription
err = coordinatorContract.AddConsumer(subID, consumerContract.Address())
require.NoError(t, err, "Error adding a consumer to a subscription in VRFCoordinator contract")
err = chainClient.WaitForEvents()
require.NoError(t, err, "Error waiting for TXs to complete")

//3. fund subscription with LINK token
FundVRFCoordinatorV3Subscription(
t,
linkToken,
coordinatorContract,
chainClient,
subID,
ocr2vrf_constants.LinkFundingAmount,
)
Expand All @@ -352,10 +321,9 @@ func SetupOCR2VRFUniverse(
require.NoError(t, err, "Error setting Payees in VRFBeacon Contract")

// fund OCR Nodes (so that they can transmit)
err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, ocr2vrf_constants.EthFundingAmount)
nodes := contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(chainlinkNodes)
err = actions_seth.FundChainlinkNodesFromRootAddress(l, chainClient, nodes, ocr2vrf_constants.EthFundingAmount)
require.NoError(t, err, "Error funding Nodes")
err = chainClient.WaitForEvents()
require.NoError(t, err, "Error waiting for TXs to complete")

bootstrapNode := chainlinkNodes[0]
nonBootstrapNodes := chainlinkNodes[1:]
Expand Down
23 changes: 21 additions & 2 deletions integration-tests/actions/seth/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ import (
"go.uber.org/zap/zapcore"

"github.com/smartcontractkit/chainlink-testing-framework/blockchain"
ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config"
"github.com/smartcontractkit/chainlink-testing-framework/k8s/environment"
"github.com/smartcontractkit/chainlink-testing-framework/logging"
"github.com/smartcontractkit/chainlink-testing-framework/testreporters"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_factory"

ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config"
"github.com/smartcontractkit/chainlink-testing-framework/utils/conversions"
"github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext"
"github.com/smartcontractkit/chainlink/integration-tests/client"
Expand Down Expand Up @@ -293,7 +293,26 @@ func SendFunds(logger zerolog.Logger, client *seth.Client, payload FundsToSendPa
Bool("Dynamic fees", client.Cfg.Network.EIP1559DynamicFees).
Msg("Sent funds")

return client.WaitMined(ctx, logger, client.Client, signedTx)
receipt, receiptErr := client.WaitMined(ctx, logger, client.Client, signedTx)
if receiptErr != nil {
return nil, errors.Wrap(receiptErr, "failed to wait for transaction to be mined")
}

if receipt.Status == 1 {
return receipt, nil
}

tx, _, err := client.Client.TransactionByHash(ctx, signedTx.Hash())
if err != nil {
return nil, errors.Wrap(err, "failed to get transaction by hash ")
}

_, err = client.Decode(tx, receiptErr)
if err != nil {
return nil, err
}

return receipt, nil
}

// DeployForwarderContracts first deploys Operator Factory and then uses it to deploy given number of
Expand Down
Loading

0 comments on commit 7be3506

Please sign in to comment.