Skip to content

Commit

Permalink
OCRSetupInputs multiple contracts (#117)
Browse files Browse the repository at this point in the history
* OCRSetupInputs multiple contracts

* fix

* lint

* PR changes
  • Loading branch information
gheorghestrimtu authored Oct 20, 2021
1 parent 0bb4e93 commit f71416d
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 102 deletions.
3 changes: 2 additions & 1 deletion suite/chaos/chaos_ocr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ var _ = XDescribeTable("OCR chaos tests @chaos-ocr", func(
i := &testcommon.OCRSetupInputs{}
Context("Runs OCR test with a chaos modifier", func() {
testcommon.DeployOCRForEnv(i, envInit)
testcommon.SetupOCRTest(i)
testcommon.FundNodes(i)
testcommon.DeployOCRContracts(i, 1)
testcommon.SendOCRJobs(i)
_, err := i.SuiteSetup.Environment().ApplyChaos(chaosSpec)
Expect(err).ShouldNot(HaveOccurred())
Expand Down
3 changes: 2 additions & 1 deletion suite/contracts/contracts_ocr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ var _ = Describe("OCR Feed @ocr", func() {
) {
i := &testcommon.OCRSetupInputs{}
testcommon.DeployOCRForEnv(i, envInit)
testcommon.SetupOCRTest(i)
testcommon.FundNodes(i)
testcommon.DeployOCRContracts(i, 1)
testcommon.SendOCRJobs(i)
testcommon.CheckRound(i)
By("Printing gas stats", func() {
Expand Down
24 changes: 15 additions & 9 deletions suite/steps/alerts_steps.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
package steps

import (
"fmt"
. "github.com/onsi/gomega"
"github.com/smartcontractkit/integrations-framework/client"
"github.com/smartcontractkit/integrations-framework/contracts"
)

// GetMockserverInitializerDataForOTPE crates mocked weiwatchers data needed for otpe
func GetMockserverInitializerDataForOTPE(offChainAggregatorInstanceAddress string, chainlinkNodes []client.Chainlink) interface{} {
contractInfo := client.ContractInfoJSON{
ContractVersion: 4,
Path: "test",
Status: "live",
ContractAddress: offChainAggregatorInstanceAddress,
}
// GetMockserverInitializerDataForOTPE creates mocked weiwatchers data needed for otpe
func GetMockserverInitializerDataForOTPE(OCRInstances []contracts.OffchainAggregator, chainlinkNodes []client.Chainlink) interface{} {
var contractsInfo []client.ContractInfoJSON

for index, OCRInstance := range OCRInstances {
contractInfo := client.ContractInfoJSON{
ContractVersion: 4,
Path: fmt.Sprintf("contract_%d", index),
Status: "live",
ContractAddress: OCRInstance.Address(),
}

contractsInfo := []client.ContractInfoJSON{contractInfo}
contractsInfo = append(contractsInfo, contractInfo)
}

contractsInitializer := client.HttpInitializer{
Request: client.HttpRequest{Path: "/contracts.json"},
Expand Down
198 changes: 107 additions & 91 deletions suite/testcommon/ocr.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type OCRSetupInputs struct {
NetworkInfo actions.NetworkInfo
ChainlinkNodes []client.Chainlink
DefaultWallet client.BlockchainWallet
OCRInstance contracts.OffchainAggregator
OCRInstances []contracts.OffchainAggregator
Mockserver *client.MockserverClient
}

Expand All @@ -50,83 +50,88 @@ func DeployOCRForEnv(i *OCRSetupInputs, envInit environment.K8sEnvSpecInit) {
})
}

// SetupOCRTest setup for an ocr test
func SetupOCRTest(i *OCRSetupInputs) {
By("Funding nodes and deploying OCR contract", func() {
ethAmount, err := i.NetworkInfo.Deployer.CalculateETHForTXs(i.NetworkInfo.Wallets.Default(), i.NetworkInfo.Network.Config(), 2)
Expect(err).ShouldNot(HaveOccurred())
err = actions.FundChainlinkNodes(
i.ChainlinkNodes,
i.NetworkInfo.Client,
i.DefaultWallet,
ethAmount,
big.NewFloat(2),
)
Expect(err).ShouldNot(HaveOccurred())

// Deploy and config OCR contract
deployer, err := contracts.NewContractDeployer(i.NetworkInfo.Client)
Expect(err).ShouldNot(HaveOccurred())
// DeployOCRContracts deploys and funds a certain number of offchain aggregator contracts
func DeployOCRContracts(i *OCRSetupInputs, nrOfOCRContracts int) {
deployer, err := contracts.NewContractDeployer(i.NetworkInfo.Client)
Expect(err).ShouldNot(HaveOccurred())

i.OCRInstance, err = deployer.DeployOffChainAggregator(i.DefaultWallet, contracts.DefaultOffChainAggregatorOptions())
for nr := 0; nr < nrOfOCRContracts; nr++ {
OCRInstance, err := deployer.DeployOffChainAggregator(i.DefaultWallet, contracts.DefaultOffChainAggregatorOptions())
Expect(err).ShouldNot(HaveOccurred())
err = i.OCRInstance.SetConfig(
err = OCRInstance.SetConfig(
i.DefaultWallet,
i.ChainlinkNodes[1:],
contracts.DefaultOffChainAggregatorConfig(len(i.ChainlinkNodes[1:])),
)
Expect(err).ShouldNot(HaveOccurred())
err = i.OCRInstance.Fund(i.DefaultWallet, nil, big.NewFloat(2))
err = OCRInstance.Fund(i.DefaultWallet, nil, big.NewFloat(2))
Expect(err).ShouldNot(HaveOccurred())
err = i.NetworkInfo.Client.WaitForEvents()
Expect(err).ShouldNot(HaveOccurred())
})
i.OCRInstances = append(i.OCRInstances, OCRInstance)
}
}

// FundNodes funds all chainlink nodes
func FundNodes(i *OCRSetupInputs) {
ethAmount, err := i.NetworkInfo.Deployer.CalculateETHForTXs(i.NetworkInfo.Wallets.Default(), i.NetworkInfo.Network.Config(), 2)
Expect(err).ShouldNot(HaveOccurred())
err = actions.FundChainlinkNodes(
i.ChainlinkNodes,
i.NetworkInfo.Client,
i.DefaultWallet,
ethAmount,
big.NewFloat(2),
)
Expect(err).ShouldNot(HaveOccurred())
}

// SendOCRJobs bootstraps the first node and to the other nodes sends ocr jobs that
// read from different adapters
func SendOCRJobs(i *OCRSetupInputs) {
By("Sending OCR jobs to chainlink nodes", func() {
bootstrapNode := i.ChainlinkNodes[0]
bootstrapP2PIds, err := bootstrapNode.ReadP2PKeys()
Expect(err).ShouldNot(HaveOccurred())
bootstrapP2PId := bootstrapP2PIds.Data[0].Attributes.PeerID
bootstrapSpec := &client.OCRBootstrapJobSpec{
ContractAddress: i.OCRInstance.Address(),
P2PPeerID: bootstrapP2PId,
IsBootstrapPeer: true,
}
_, err = bootstrapNode.CreateJob(bootstrapSpec)
Expect(err).ShouldNot(HaveOccurred())

for index := 1; index < len(i.ChainlinkNodes); index++ {
nodeP2PIds, err := i.ChainlinkNodes[index].ReadP2PKeys()
Expect(err).ShouldNot(HaveOccurred())
nodeP2PId := nodeP2PIds.Data[0].Attributes.PeerID
nodeTransmitterAddress, err := i.ChainlinkNodes[index].PrimaryEthAddress()
for OCRInstanceIndex, OCRInstance := range i.OCRInstances {
bootstrapNode := i.ChainlinkNodes[0]
bootstrapP2PIds, err := bootstrapNode.ReadP2PKeys()
Expect(err).ShouldNot(HaveOccurred())
nodeOCRKeys, err := i.ChainlinkNodes[index].ReadOCRKeys()
Expect(err).ShouldNot(HaveOccurred())
nodeOCRKeyId := nodeOCRKeys.Data[0].ID

bta := client.BridgeTypeAttributes{
Name: fmt.Sprintf("node_%d", index),
URL: fmt.Sprintf("%s/node_%d", i.Mockserver.Config.ClusterURL, index),
bootstrapP2PId := bootstrapP2PIds.Data[0].Attributes.PeerID
bootstrapSpec := &client.OCRBootstrapJobSpec{
ContractAddress: OCRInstance.Address(),
P2PPeerID: bootstrapP2PId,
IsBootstrapPeer: true,
}

err = i.ChainlinkNodes[index].CreateBridge(&bta)
_, err = bootstrapNode.CreateJob(bootstrapSpec)
Expect(err).ShouldNot(HaveOccurred())

ocrSpec := &client.OCRTaskJobSpec{
ContractAddress: i.OCRInstance.Address(),
P2PPeerID: nodeP2PId,
P2PBootstrapPeers: []client.Chainlink{bootstrapNode},
KeyBundleID: nodeOCRKeyId,
TransmitterAddress: nodeTransmitterAddress,
ObservationSource: client.ObservationSourceSpecBridge(bta),
for nodeIndex := 1; nodeIndex < len(i.ChainlinkNodes); nodeIndex++ {
nodeP2PIds, err := i.ChainlinkNodes[nodeIndex].ReadP2PKeys()
Expect(err).ShouldNot(HaveOccurred())
nodeP2PId := nodeP2PIds.Data[0].Attributes.PeerID
nodeTransmitterAddress, err := i.ChainlinkNodes[nodeIndex].PrimaryEthAddress()
Expect(err).ShouldNot(HaveOccurred())
nodeOCRKeys, err := i.ChainlinkNodes[nodeIndex].ReadOCRKeys()
Expect(err).ShouldNot(HaveOccurred())
nodeOCRKeyId := nodeOCRKeys.Data[0].ID

bta := client.BridgeTypeAttributes{
Name: fmt.Sprintf("node_%d_contract_%d", nodeIndex, OCRInstanceIndex),
URL: fmt.Sprintf("%s/node_%d_contract_%d", i.Mockserver.Config.ClusterURL, nodeIndex, OCRInstanceIndex),
}

err = i.ChainlinkNodes[nodeIndex].CreateBridge(&bta)
Expect(err).ShouldNot(HaveOccurred())

ocrSpec := &client.OCRTaskJobSpec{
ContractAddress: OCRInstance.Address(),
P2PPeerID: nodeP2PId,
P2PBootstrapPeers: []client.Chainlink{bootstrapNode},
KeyBundleID: nodeOCRKeyId,
TransmitterAddress: nodeTransmitterAddress,
ObservationSource: client.ObservationSourceSpecBridge(bta),
}
_, err = i.ChainlinkNodes[nodeIndex].CreateJob(ocrSpec)
Expect(err).ShouldNot(HaveOccurred())
}
_, err = i.ChainlinkNodes[index].CreateJob(ocrSpec)
Expect(err).ShouldNot(HaveOccurred())
}
})
}
Expand All @@ -145,9 +150,11 @@ func CheckRound(i *OCRSetupInputs) {
StartNewRound(i, 1)

// Check answer is as expected
answer, err := i.OCRInstance.GetLatestAnswer(context.Background())
Expect(err).ShouldNot(HaveOccurred())
Expect(answer.Int64()).Should(Equal(int64(5)), "Latest answer from OCR is not as expected")
for _, OCRInstance := range i.OCRInstances {
answer, err := OCRInstance.GetLatestAnswer(context.Background())
Expect(err).ShouldNot(HaveOccurred())
Expect(answer.Int64()).Should(Equal(int64(5)), "Latest answer from OCR is not as expected")
}

// Change adapters answer to 10
adapterResults = []int{}
Expand All @@ -160,26 +167,29 @@ func CheckRound(i *OCRSetupInputs) {
StartNewRound(i, 2)

// Check answer is as expected
answer, err = i.OCRInstance.GetLatestAnswer(context.Background())
Expect(err).ShouldNot(HaveOccurred())
Expect(answer.Int64()).Should(Equal(int64(10)), "Latest answer from OCR is not as expected")
for _, OCRInstance := range i.OCRInstances {
answer, err := OCRInstance.GetLatestAnswer(context.Background())
Expect(err).ShouldNot(HaveOccurred())
Expect(answer.Int64()).Should(Equal(int64(10)), "Latest answer from OCR is not as expected")
}
})
}

// StartNewRound requests a new round from the ocr contract and waits for confirmation
func StartNewRound(i *OCRSetupInputs, roundNr int64) {
roundTimeout := time.Minute * 2
for _, OCRInstance := range i.OCRInstances {
err := OCRInstance.RequestNewRound(i.DefaultWallet)
Expect(err).ShouldNot(HaveOccurred())
err = i.SuiteSetup.DefaultNetwork().Client.WaitForEvents()
Expect(err).ShouldNot(HaveOccurred())

err := i.OCRInstance.RequestNewRound(i.DefaultWallet)
Expect(err).ShouldNot(HaveOccurred())
err = i.SuiteSetup.DefaultNetwork().Client.WaitForEvents()
Expect(err).ShouldNot(HaveOccurred())

// Wait for the second round
ocrRound := contracts.NewOffchainAggregatorRoundConfirmer(i.OCRInstance, big.NewInt(roundNr), roundTimeout)
i.SuiteSetup.DefaultNetwork().Client.AddHeaderEventSubscription(i.OCRInstance.Address(), ocrRound)
err = i.SuiteSetup.DefaultNetwork().Client.WaitForEvents()
Expect(err).ShouldNot(HaveOccurred())
// Wait for the second round
ocrRound := contracts.NewOffchainAggregatorRoundConfirmer(OCRInstance, big.NewInt(roundNr), roundTimeout)
i.SuiteSetup.DefaultNetwork().Client.AddHeaderEventSubscription(OCRInstance.Address(), ocrRound)
err = i.SuiteSetup.DefaultNetwork().Client.WaitForEvents()
Expect(err).ShouldNot(HaveOccurred())
}
}

// SetAdapterResults sets the mock responses in mockserver that are read by chainlink nodes
Expand All @@ -189,40 +199,46 @@ func SetAdapterResults(i *OCRSetupInputs, results []int) {

log.Info().Interface("New Adapter results", results).Msg("Setting new values")

for index := 1; index < len(i.ChainlinkNodes); index++ {
pathSelector := client.PathSelector{Path: fmt.Sprintf("/node_%d", index)}
err := i.Mockserver.ClearExpectation(pathSelector)
Expect(err).ShouldNot(HaveOccurred())
}
for OCRInstanceIndex := range i.OCRInstances {
for nodeIndex := 1; nodeIndex < len(i.ChainlinkNodes); nodeIndex++ {
pathSelector := client.PathSelector{Path: fmt.Sprintf("/node_%d_contract_%d", nodeIndex, OCRInstanceIndex)}
err := i.Mockserver.ClearExpectation(pathSelector)
Expect(err).ShouldNot(HaveOccurred())
}

}
var initializers []client.HttpInitializer
for index := 1; index < len(i.ChainlinkNodes); index++ {
adResp := client.AdapterResponse{
Id: "",
Data: client.AdapterResult{Result: results[index-1]},
Error: nil,
}
nodesInitializer := client.HttpInitializer{
Request: client.HttpRequest{Path: fmt.Sprintf("/node_%d", index)},
Response: client.HttpResponse{Body: adResp},

for OCRInstanceIndex := range i.OCRInstances {
for nodeIndex := 1; nodeIndex < len(i.ChainlinkNodes); nodeIndex++ {
adResp := client.AdapterResponse{
Id: "",
Data: client.AdapterResult{Result: results[nodeIndex-1]},
Error: nil,
}
nodesInitializer := client.HttpInitializer{
Request: client.HttpRequest{Path: fmt.Sprintf("/node_%d_contract_%d", nodeIndex, OCRInstanceIndex)},
Response: client.HttpResponse{Body: adResp},
}
initializers = append(initializers, nodesInitializer)
}
initializers = append(initializers, nodesInitializer)
}

err := i.Mockserver.PutExpectations(initializers)
Expect(err).ShouldNot(HaveOccurred())
}

// NewOCRSetupInputForObservability deploys and setups env and clients for testing observability
func NewOCRSetupInputForObservability(i *OCRSetupInputs, nodeCount int, rules map[string]*os.File) {
func NewOCRSetupInputForObservability(i *OCRSetupInputs, nodeCount int, contractCount int, rules map[string]*os.File) {
DeployOCRForEnv(
i,
environment.NewChainlinkClusterForObservabilityTesting(nodeCount),
)
SetupOCRTest(i)
FundNodes(i)
DeployOCRContracts(i, contractCount)

err := i.Mockserver.PutExpectations(steps.GetMockserverInitializerDataForOTPE(
i.OCRInstance.Address(),
i.OCRInstances,
i.ChainlinkNodes,
))
Expect(err).ShouldNot(HaveOccurred())
Expand Down

0 comments on commit f71416d

Please sign in to comment.