@@ -14,6 +14,7 @@ import (
1414 "github.com/ethereum/go-ethereum/common"
1515 "github.com/pkg/errors"
1616 "github.com/rs/zerolog"
17+ chainselectors "github.com/smartcontractkit/chain-selectors"
1718 "google.golang.org/protobuf/proto"
1819
1920 "github.com/smartcontractkit/chainlink-common/keystore/corekeys/p2pkey"
@@ -30,6 +31,7 @@ import (
3031 cap_reg_v2_seq "github.com/smartcontractkit/chainlink/deployment/cre/capabilities_registry/v2/changeset/sequences"
3132 cre_contracts "github.com/smartcontractkit/chainlink/deployment/cre/contracts"
3233 "github.com/smartcontractkit/chainlink/deployment/cre/ocr3"
34+ "github.com/smartcontractkit/chainlink/deployment/cre/ocr3/ocr3_1"
3335 keystone_changeset "github.com/smartcontractkit/chainlink/deployment/keystone/changeset"
3436 ks_contracts_op "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/operations/contracts"
3537 libc "github.com/smartcontractkit/chainlink/system-tests/lib/conversions"
@@ -178,6 +180,93 @@ func (d *dons) embedOCR3Config(capConfig *capabilitiespb.CapabilityConfig, don d
178180 return nil
179181}
180182
183+ type embedOCR3_1Params struct {
184+ capRegAddress string
185+ chainID uint64
186+ donID uint32
187+ capabilityID string
188+ }
189+
190+ func (d * dons ) embedOCR3_1Config (capConfig * capabilitiespb.CapabilityConfig , don donConfig , registryChainSelector uint64 , configs map [string ]* cre.OCR3_1ConfigEntry , params embedOCR3_1Params ) error {
191+ var allNodeIDs []string
192+ for _ , nop := range don .Nops {
193+ allNodeIDs = append (allNodeIDs , nop .Nodes ... )
194+ }
195+
196+ nodes , err := deployment .NodeInfo (allNodeIDs , d .offChain )
197+ if err != nil {
198+ return fmt .Errorf ("failed to get node info: %w" , err )
199+ }
200+
201+ if capConfig .Ocr3Configs == nil {
202+ capConfig .Ocr3Configs = make (map [string ]* capabilitiespb.OCR3Config )
203+ }
204+
205+ sortedKeys := make ([]string , 0 , len (configs ))
206+ for k := range configs {
207+ sortedKeys = append (sortedKeys , k )
208+ }
209+ sort .Strings (sortedKeys )
210+
211+ generateConfig := func (ocrConfigKey string , entry * cre.OCR3_1ConfigEntry ) error {
212+ entry .Config .TransmissionSchedule = []int {len (don .Nops [0 ].Nodes )}
213+
214+ ocrConfig , err := ocr3_1 .GenerateOCR3_1ConfigFromNodes (* entry .Config , nodes , registryChainSelector , d .env .OCRSecrets , entry .ReportingPluginConfig )
215+ if err != nil {
216+ return fmt .Errorf ("failed to generate OCR3_1 config for key %s: %w" , ocrConfigKey , err )
217+ }
218+
219+ transmitterBytes := make ([][]byte , len (ocrConfig .Transmitters ))
220+ for i , t := range ocrConfig .Transmitters {
221+ transmitterBytes [i ] = t .Bytes ()
222+ }
223+
224+ capConfig .Ocr3Configs [ocrConfigKey ] = & capabilitiespb.OCR3Config {
225+ Signers : ocrConfig .Signers ,
226+ Transmitters : transmitterBytes ,
227+ F : uint32 (ocrConfig .F ),
228+ OnchainConfig : ocrConfig .OnchainConfig ,
229+ OffchainConfigVersion : ocrConfig .OffchainConfigVersion ,
230+ OffchainConfig : ocrConfig .OffchainConfig ,
231+ ConfigCount : 1 ,
232+ }
233+ return nil
234+ }
235+
236+ // Pass 1: generate configs with static ReportingPluginConfig
237+ for _ , key := range sortedKeys {
238+ entry := configs [key ]
239+ if entry .ReportingPluginConfig != nil {
240+ if err := generateConfig (key , entry ); err != nil {
241+ return err
242+ }
243+ }
244+ }
245+
246+ // Pass 2: generate configs using ReportingPluginConfigFactory (may depend on pass 1 results)
247+ for _ , key := range sortedKeys {
248+ entry := configs [key ]
249+ if entry .ReportingPluginConfig != nil {
250+ continue
251+ }
252+ if entry .ReportingPluginConfigFactory == nil {
253+ return fmt .Errorf ("OCR3_1 config entry for key %q has neither ReportingPluginConfig nor ReportingPluginConfigFactory" , key )
254+ }
255+
256+ rpc , err := entry .ReportingPluginConfigFactory (params .capRegAddress , params .chainID , params .donID , params .capabilityID , capConfig .Ocr3Configs )
257+ if err != nil {
258+ return fmt .Errorf ("ReportingPluginConfigFactory failed for key %q: %w" , key , err )
259+ }
260+ entry .ReportingPluginConfig = rpc
261+
262+ if err := generateConfig (key , entry ); err != nil {
263+ return err
264+ }
265+ }
266+
267+ return nil
268+ }
269+
181270func (d * dons ) mustToV2ConfigureInput (chainSelector uint64 , contractAddress string , capabilityToOCR3Config map [string ]* ocr3.OracleConfig ) cap_reg_v2_seq.ConfigureCapabilitiesRegistryInput {
182271 nops := make ([]capabilities_registry_v2.CapabilitiesRegistryNodeOperatorParams , 0 )
183272 nodes := make ([]contracts.NodesInput , 0 )
@@ -451,6 +540,26 @@ func ConfigureCapabilityRegistry(input cre.ConfigureCapabilityRegistryInput) (Ca
451540 if ! cap .UseCapRegOCRConfig || cap .Config == nil {
452541 continue
453542 }
543+
544+ // Check for OCR3_1 config first (multi-instance capabilities like vault)
545+ if ocr31Config := input .CapabilityToOCR3_1Config [cap .Capability .LabelledName ]; ocr31Config != nil {
546+ chainID , cErr := chainselectors .ChainIdFromSelector (input .ChainSelector )
547+ if cErr != nil {
548+ return nil , fmt .Errorf ("failed to get chain ID from selector %d: %w" , input .ChainSelector , cErr )
549+ }
550+ capID := fmt .Sprintf ("%s@%s" , cap .Capability .LabelledName , cap .Capability .Version )
551+ params := embedOCR3_1Params {
552+ capRegAddress : input .CapabilitiesRegistryAddress .Hex (),
553+ chainID : chainID ,
554+ donID : don .id ,
555+ capabilityID : capID ,
556+ }
557+ if err := dons .embedOCR3_1Config (don .Capabilities [i ].Config , don , input .ChainSelector , ocr31Config .Configs , params ); err != nil {
558+ return nil , fmt .Errorf ("failed to embed OCR3_1 config for capability %s: %w" , cap .Capability .LabelledName , err )
559+ }
560+ continue
561+ }
562+
454563 ocrConfig := input .CapabilityToOCR3Config [cap .Capability .LabelledName ]
455564 if ocrConfig == nil {
456565 return nil , fmt .Errorf ("no OCR3 config found for capability %s" , cap .Capability .LabelledName )
0 commit comments