Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions system-tests/lib/cre/contracts/keystone.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,7 @@ func (d *dons) allDonCapabilities() []keystone_changeset.DonCapabilities {

// embedOCR3Config computes the full OCR3 configuration for a consensus V2 DON
// and embeds it in the capability config proto's Ocr3Configs map.
func (d *dons) embedOCR3Config(capConfig *capabilitiespb.CapabilityConfig, don donConfig, registryChainSelector uint64) error {
oracleConfig, err := DefaultOCR3Config()
if err != nil {
return fmt.Errorf("failed to get default OCR3 config: %w", err)
}
func (d *dons) embedOCR3Config(capConfig *capabilitiespb.CapabilityConfig, don donConfig, registryChainSelector uint64, oracleConfig *ocr3.OracleConfig) error {
oracleConfig.TransmissionSchedule = []int{len(don.Nops[0].Nodes)}

var allNodeIDs []string
Expand Down Expand Up @@ -182,7 +178,7 @@ func (d *dons) embedOCR3Config(capConfig *capabilitiespb.CapabilityConfig, don d
return nil
}

func (d *dons) mustToV2ConfigureInput(chainSelector uint64, contractAddress string) cap_reg_v2_seq.ConfigureCapabilitiesRegistryInput {
func (d *dons) mustToV2ConfigureInput(chainSelector uint64, contractAddress string, capabilityToOCR3Config map[string]*ocr3.OracleConfig) cap_reg_v2_seq.ConfigureCapabilitiesRegistryInput {
nops := make([]capabilities_registry_v2.CapabilitiesRegistryNodeOperatorParams, 0)
nodes := make([]contracts.NodesInput, 0)
capabilities := make([]contracts.RegisterableCapability, 0)
Expand Down Expand Up @@ -264,8 +260,12 @@ func (d *dons) mustToV2ConfigureInput(chainSelector uint64, contractAddress stri
configBytes := []byte("{}")
if cap.Config != nil {
if cap.UseCapRegOCRConfig {
if err := d.embedOCR3Config(cap.Config, don, chainSelector); err != nil {
panic(fmt.Sprintf("failed to embed OCR3 config for consensus V2: %s", err))
ocrConfig := capabilityToOCR3Config[cap.Capability.LabelledName]
if ocrConfig == nil {
panic("no OCR3 config found for capability " + cap.Capability.LabelledName)
}
if err := d.embedOCR3Config(cap.Config, don, chainSelector, ocrConfig); err != nil {
panic(fmt.Sprintf("failed to embed OCR3 config for capability %s: %s", cap.Capability.LabelledName, err))
}
}
if protoBytes, err := proto.Marshal(cap.Config); err == nil {
Expand Down Expand Up @@ -475,7 +475,7 @@ func ConfigureCapabilityRegistry(input cre.ConfigureCapabilityRegistryInput) (Ca
}

// Transform dons data to V2 sequence input format
v2Input := dons.mustToV2ConfigureInput(input.ChainSelector, input.CapabilitiesRegistryAddress.Hex())
v2Input := dons.mustToV2ConfigureInput(input.ChainSelector, input.CapabilitiesRegistryAddress.Hex(), input.CapabilityToOCR3Config)
_, seqErr := operations.ExecuteSequence(
input.CldEnv.OperationsBundle,
cap_reg_v2_seq.ConfigureCapabilitiesRegistry,
Expand Down
211 changes: 158 additions & 53 deletions system-tests/lib/cre/contracts/keystone_test.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,97 @@
package contracts

import (
"context"
"errors"
"fmt"
"math/big"
"strings"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"

chainselectors "github.com/smartcontractkit/chain-selectors"

capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb"
cldf_offchain "github.com/smartcontractkit/chainlink-deployments-framework/offchain"
kcr "github.com/smartcontractkit/chainlink-evm/gethwrappers/keystone/generated/capabilities_registry_1_1_0"
nodev1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node"
"github.com/smartcontractkit/chainlink-protos/job-distributor/v1/shared/ptypes"

keystone_changeset "github.com/smartcontractkit/chainlink/deployment/keystone/changeset"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey"
)

// fakeOffchainClient implements offchain.Client; only ListNodes and
// ListNodeChainConfigs are wired, every other method panics via the embedded
// nil interface.
type fakeOffchainClient struct {
cldf_offchain.Client
nodesByID map[string]*fakeNodeInfo
}

type fakeNodeInfo struct {
id string
name string
csaKey string
workflowKey string
p2pID string
chainConfigs []*nodev1.ChainConfig
}

func newFakeOffchainClient(nodes []*fakeNodeInfo) *fakeOffchainClient {
f := &fakeOffchainClient{nodesByID: make(map[string]*fakeNodeInfo)}
for _, n := range nodes {
f.nodesByID[n.id] = n
}
return f
}

func (f *fakeOffchainClient) ListNodes(_ context.Context, in *nodev1.ListNodesRequest, _ ...grpc.CallOption) (*nodev1.ListNodesResponse, error) {
var wantP2P map[string]bool
if in.Filter != nil {
for _, sel := range in.Filter.Selectors {
if sel.Key == "p2p_id" && sel.Op == ptypes.SelectorOp_IN && sel.Value != nil {
wantP2P = make(map[string]bool)
for _, v := range strings.Split(*sel.Value, ",") {
wantP2P[v] = true
}
}
}
}

out := make([]*nodev1.Node, 0, len(f.nodesByID))
for _, n := range f.nodesByID {
if wantP2P != nil && !wantP2P[n.p2pID] {
continue
}
p2pVal := n.p2pID
wfKey := n.workflowKey
out = append(out, &nodev1.Node{
Id: n.id,
Name: n.name,
PublicKey: n.csaKey,
WorkflowKey: &wfKey,
IsEnabled: true,
Labels: []*ptypes.Label{{Key: "p2p_id", Value: &p2pVal}},
})
}
return &nodev1.ListNodesResponse{Nodes: out}, nil
}

func (f *fakeOffchainClient) ListNodeChainConfigs(_ context.Context, in *nodev1.ListNodeChainConfigsRequest, _ ...grpc.CallOption) (*nodev1.ListNodeChainConfigsResponse, error) {
if in.Filter == nil || len(in.Filter.NodeIds) == 0 {
return nil, errors.New("filter with node IDs required")
}
n, ok := f.nodesByID[in.Filter.NodeIds[0]]
if !ok {
return nil, fmt.Errorf("node not found: %s", in.Filter.NodeIds[0])
}
return &nodev1.ListNodeChainConfigsResponse{ChainConfigs: n.chainConfigs}, nil
}

func TestDonsOrderedByID(t *testing.T) {
// Test donsOrderedByID sorts by id ascending
d := dons{
Expand All @@ -34,16 +113,77 @@ func TestDonsOrderedByID(t *testing.T) {
}

func TestToV2ConfigureInput(t *testing.T) {
// Create test peer IDs
peerID1 := p2pkey.MustNewV2XXXTestingOnly(big.NewInt(1)).PeerID().String()
peerID2 := p2pkey.MustNewV2XXXTestingOnly(big.NewInt(2)).PeerID().String()
chainSel := chainselectors.ETHEREUM_TESTNET_SEPOLIA.Selector
chainID, err := chainselectors.GetChainIDFromSelector(chainSel)
require.NoError(t, err)

key1 := p2pkey.MustNewV2XXXTestingOnly(big.NewInt(1))
key2 := p2pkey.MustNewV2XXXTestingOnly(big.NewInt(2))
peerID1 := key1.PeerID().String()
peerID2 := key2.PeerID().String()

fakeNodes := []*fakeNodeInfo{
{
id: "node_01",
name: "test-node-1",
csaKey: "403b72f0b1b3b5f5a91bcfedb7f28599767502a04b5b7e067fcf3782e23eeb9c",
workflowKey: "5193f72fc7b4323a86088fb0acb4e4494ae351920b3944bd726a59e8dbcdd45f",
p2pID: peerID1,
chainConfigs: []*nodev1.ChainConfig{{
Chain: &nodev1.Chain{
Type: nodev1.ChainType_CHAIN_TYPE_EVM,
Id: chainID,
},
Ocr2Config: &nodev1.OCR2Config{
OcrKeyBundle: &nodev1.OCR2Config_OCRKeyBundle{
OffchainPublicKey: "03dacd15fc96c965c648e3623180de002b71a97cf6eeca9affb91f461dcd6ce1",
OnchainSigningAddress: "b35409a8d4f9a18da55c5b2bb08a3f5f68d44442",
ConfigPublicKey: "5193f72fc7b4323a86088fb0acb4e4494ae351920b3944bd726a59e8dbcdd45f",
BundleId: "665a101d79d310cb0a5ebf695b06e8fc8082b5cbe62d7d362d80d47447a31fea",
},
P2PKeyBundle: &nodev1.OCR2Config_P2PKeyBundle{
PeerId: peerID1,
},
IsBootstrap: false,
},
AccountAddress: "0x2877F08d9c5Cc9F401F730Fa418fAE563A9a2FF3",
}},
},
{
id: "node_02",
name: "test-node-2",
csaKey: "28b91143ec9111796a7d63e14c1cf6bb01b4ed59667ab54f5bc72ebe49c881be",
workflowKey: "2c45fec2320f6bcd36444529a86d9f8b4439499a5d8272dec9bcbbebb5e1bf01",
p2pID: peerID2,
chainConfigs: []*nodev1.ChainConfig{{
Chain: &nodev1.Chain{
Type: nodev1.ChainType_CHAIN_TYPE_EVM,
Id: chainID,
},
Ocr2Config: &nodev1.OCR2Config{
OcrKeyBundle: &nodev1.OCR2Config_OCRKeyBundle{
OffchainPublicKey: "255096a3b7ade10e29c648e0b407fc486180464f713446b1da04f013df6179c8",
OnchainSigningAddress: "8258f4c4761cc445333017608044a204fd0c006a",
ConfigPublicKey: "2c45fec2320f6bcd36444529a86d9f8b4439499a5d8272dec9bcbbebb5e1bf01",
BundleId: "7a9b75510b8d09932b98142419bef52436ff725dd9395469473b487ef87fdfb0",
},
P2PKeyBundle: &nodev1.OCR2Config_P2PKeyBundle{
PeerId: peerID2,
},
IsBootstrap: false,
},
AccountAddress: "0x415aa1E9a1bcB3929ed92bFa1F9735Dc0D45AD31",
}},
},
}

offchainClient := newFakeOffchainClient(fakeNodes)

// Create test dons with sample data
d := &dons{
c: make(map[string]donConfig),
c: make(map[string]donConfig),
offChain: offchainClient,
}

// Add a DON with capabilities and nodes
d.c["test-don"] = donConfig{
id: 1,
DonCapabilities: keystone_changeset.DonCapabilities{
Expand All @@ -68,58 +208,23 @@ func TestToV2ConfigureInput(t *testing.T) {
},
}

// Call the method under test
result := d.mustToV2ConfigureInput(123, "0x1234567890abcdef")
result := d.mustToV2ConfigureInput(chainSel, "0x1234567890abcdef", nil)

// Verify the transformation
if result.RegistryChainSel != 123 {
t.Errorf("expected RegistryChainSel 123, got %d", result.RegistryChainSel)
}
require.Equal(t, chainSel, result.RegistryChainSel)

if result.ContractAddress != "0x1234567890abcdef" { //nolint:staticcheck // we won't migrate tests
t.Errorf("expected ContractAddress 0x1234567890abcdef, got %s", result.ContractAddress) //nolint:staticcheck // we won't migrate tests
}
require.Len(t, result.Nops, 1)
require.Equal(t, "test-nop", result.Nops[0].Name)

if len(result.Nops) != 1 {
t.Fatalf("expected 1 NOP, got %d", len(result.Nops))
}
require.Len(t, result.Nodes, 2)

if result.Nops[0].Name != "test-nop" {
t.Errorf("expected NOP name 'test-nop', got %s", result.Nops[0].Name)
}

if len(result.Nodes) != 2 {
t.Fatalf("expected 2 nodes, got %d", len(result.Nodes))
}
require.Len(t, result.Capabilities, 1)
require.Equal(t, "test-capability@1.0.0", result.Capabilities[0].CapabilityID)

if len(result.Capabilities) != 1 {
t.Fatalf("expected 1 capability, got %d", len(result.Capabilities))
}

expectedCapID := "test-capability@1.0.0"
if result.Capabilities[0].CapabilityID != expectedCapID {
t.Errorf("expected capability ID '%s', got %s", expectedCapID, result.Capabilities[0].CapabilityID)
}

if len(result.DONs) != 1 {
t.Fatalf("expected 1 DON, got %d", len(result.DONs))
}

if result.DONs[0].Name != "test-don" {
t.Errorf("expected DON name 'test-don', got %s", result.DONs[0].Name)
}

if result.DONs[0].F != 1 {
t.Errorf("expected DON F value 1, got %d", result.DONs[0].F)
}

if len(result.DONs[0].Nodes) != 2 {
t.Errorf("expected DON to have 2 nodes, got %d", len(result.DONs[0].Nodes))
}

if len(result.DONs[0].CapabilityConfigurations) != 1 {
t.Errorf("expected DON to have 1 capability configuration, got %d", len(result.DONs[0].CapabilityConfigurations))
}
require.Len(t, result.DONs, 1)
require.Equal(t, "test-don", result.DONs[0].Name)
require.Equal(t, uint8(1), result.DONs[0].F)
require.Len(t, result.DONs[0].Nodes, 2)
require.Len(t, result.DONs[0].CapabilityConfigurations, 1)
}

// TestGenerateAdminAddresses contains all the test cases for the function.
Expand Down
17 changes: 7 additions & 10 deletions system-tests/lib/cre/contracts/ocr3.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func DeployOCR3Contract(logger zerolog.Logger, qualifier string, selector uint64
}

// values supplied by Alexandr Yepishev as the expected values for OCR3 config
func DefaultOCR3Config() (*keystone_changeset.OracleConfig, error) {
func DefaultOCR3Config() *ocr3.OracleConfig {
// values supplied by Alexandr Yepishev as the expected values for OCR3 config
oracleConfig := &keystone_changeset.OracleConfig{
DeltaProgressMillis: 5000,
Expand All @@ -75,10 +75,10 @@ func DefaultOCR3Config() (*keystone_changeset.OracleConfig, error) {
UniqueReports: true,
}

return oracleConfig, nil
return oracleConfig
}

func DefaultOCR3_1Config(numWorkers int) (*ocr3_1.V3_1OracleConfig, error) {
func DefaultOCR3_1Config(numWorkers int) *ocr3_1.V3_1OracleConfig {
return &ocr3_1.V3_1OracleConfig{
DeltaProgressMillis: 5000, // DKG 10-15 seconds; Vault 5 sec // check bandwidth from nops
DeltaRoundMillis: 200,
Expand All @@ -103,14 +103,11 @@ func DefaultOCR3_1Config(numWorkers int) (*ocr3_1.V3_1OracleConfig, error) {
PrevConfigDigest: "",
PrevSeqNr: 0,
PrevHistoryDigest: "",
}, nil
}
}

func DefaultChainCapabilityOCR3Config() (*keystone_changeset.OracleConfig, error) {
cfg, err := DefaultOCR3Config()
if err != nil {
return nil, fmt.Errorf("failed to generate default OCR3 config: %w", err)
}
func DefaultChainCapabilityOCR3Config() *ocr3.OracleConfig {
cfg := DefaultOCR3Config()

cfg.DeltaRoundMillis = 1000
const kib = 1024
Expand All @@ -124,5 +121,5 @@ func DefaultChainCapabilityOCR3Config() (*keystone_changeset.OracleConfig, error
MaxReportCount: 1000,
MaxBatchSize: 200,
}
return cfg, nil
return cfg
}
4 changes: 4 additions & 0 deletions system-tests/lib/cre/environment/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/s3provider"

"github.com/smartcontractkit/chainlink-testing-framework/lib/utils/ptr"
"github.com/smartcontractkit/chainlink/deployment/cre/ocr3"
keystone_changeset "github.com/smartcontractkit/chainlink/deployment/keystone/changeset"
"github.com/smartcontractkit/chainlink/system-tests/lib/cre"
crecontracts "github.com/smartcontractkit/chainlink/system-tests/lib/cre/contracts"
Expand Down Expand Up @@ -188,6 +189,7 @@ func SetupTestEnvironment(

fmt.Print(libformat.PurpleText("%s", input.StageGen.Wrap("Applying Features before environment startup")))
var donsCapabilities = make(map[uint64][]keystone_changeset.DONCapabilityWithConfig)
var capabilityToOCR3Config = make(map[string]*ocr3.OracleConfig)
for _, feature := range input.Features.List() {
for _, donMetadata := range topology.DonsMetadataWithFlag(feature.Flag()) {
testLogger.Info().Msgf("Executing PreEnvStartup for feature %s for don '%s'", feature.Flag(), donMetadata.Name)
Expand All @@ -206,6 +208,7 @@ func SetupTestEnvironment(
donsCapabilities[donMetadata.ID] = []keystone_changeset.DONCapabilityWithConfig{}
}
donsCapabilities[donMetadata.ID] = append(donsCapabilities[donMetadata.ID], output.DONCapabilityWithConfig...)
maps.Copy(capabilityToOCR3Config, output.CapabilityToOCR3Config)
}
testLogger.Info().Msgf("PreEnvStartup for feature %s executed successfully", feature.Flag())
}
Expand Down Expand Up @@ -379,6 +382,7 @@ func SetupTestEnvironment(
NodeSets: input.NodeSets,
WithV2Registries: input.WithV2Registries,
DONCapabilityWithConfigs: make(map[uint64][]keystone_changeset.DONCapabilityWithConfig),
CapabilityToOCR3Config: capabilityToOCR3Config,
}

for _, capability := range input.Capabilities {
Expand Down
5 changes: 1 addition & 4 deletions system-tests/lib/cre/features/consensus/v1/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,7 @@ func (c *Consensus) PostEnvStartup(
return errors.Wrap(err, "failed while waiting for Log Poller to become healthy")
}

ocr3Config, ocr3confErr := contracts.DefaultOCR3Config()
if ocr3confErr != nil {
return fmt.Errorf("failed to get default OCR3 config: %w", ocr3confErr)
}
ocr3Config := contracts.DefaultOCR3Config()

chain, ok := creEnv.CldfEnvironment.BlockChains.EVMChains()[creEnv.RegistryChainSelector]
if !ok {
Expand Down
Loading
Loading