diff --git a/.changeset/tall-mice-wink.md b/.changeset/tall-mice-wink.md new file mode 100644 index 00000000000..b5e00e64f92 --- /dev/null +++ b/.changeset/tall-mice-wink.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +#added DKG integration with Vault plugin diff --git a/core/scripts/keystone/src/02_provision_ocr3_capability.go b/core/scripts/keystone/src/02_provision_ocr3_capability.go index 2aeeae8d599..e7f7ed26b98 100644 --- a/core/scripts/keystone/src/02_provision_ocr3_capability.go +++ b/core/scripts/keystone/src/02_provision_ocr3_capability.go @@ -101,7 +101,7 @@ func generateOCR3Config(nodeKeys []NodeKeys, configFile string) ksdeploy.OCR3Onc topLevelCfg := mustReadOCR3Config(configFile) cfg := topLevelCfg.OracleConfig secrets := focr.XXXGenerateTestOCRSecrets() - c, err := ksdeploy.GenerateOCR3Config(cfg, nodeKeysToKsDeployNodeKeys(nodeKeys[1:]), secrets) // skip the bootstrap node + c, err := ksdeploy.GenerateOCR3Config(cfg, nodeKeysToKsDeployNodeKeys(nodeKeys[1:]), secrets, nil) // skip the bootstrap node helpers.PanicErr(err) return c } diff --git a/core/scripts/keystone/src/generate_local_ocr3_config.go b/core/scripts/keystone/src/generate_local_ocr3_config.go index c6d62edf5d0..07c6721da38 100644 --- a/core/scripts/keystone/src/generate_local_ocr3_config.go +++ b/core/scripts/keystone/src/generate_local_ocr3_config.go @@ -100,7 +100,7 @@ func (g *generateLocalOCR3Config) Run(args []string) { panic(err) } - ocrConfig, err := changeset.GenerateOCR3Config(cfg, pubKeys, focr.XXXGenerateTestOCRSecrets()) + ocrConfig, err := changeset.GenerateOCR3Config(cfg, pubKeys, focr.XXXGenerateTestOCRSecrets(), nil) if err != nil { panic(err) } diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 9b18bc479b4..cc73ef2f92c 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -821,7 +821,7 @@ func (d *Delegate) newServicesVaultPlugin( rpf, err := vaultocrplugin.NewReportingPluginFactory( lggr, requestStore, - nil, // PRIV-153: pass in `vault.NewVaultORM(d.ds) as db` + vaultocrplugin.NewVaultORM(d.ds), &dkgRecipientKey, pk, secKeyShare, diff --git a/core/services/ocr2/plugins/vault/plugin.go b/core/services/ocr2/plugins/vault/plugin.go index e7aa765654f..2bccccd0267 100644 --- a/core/services/ocr2/plugins/vault/plugin.go +++ b/core/services/ocr2/plugins/vault/plugin.go @@ -178,6 +178,9 @@ func (r *ReportingPluginFactory) NewReportingPlugin(ctx context.Context, config if err != nil { return nil, ocr3_1types.ReportingPluginInfo{}, fmt.Errorf("could not read result package from db: %w", err) } + if pack == nil { + return nil, ocr3_1types.ReportingPluginInfo{}, fmt.Errorf("no result package found in db for instance ID %s", *configProto.DKGInstanceID) + } rP := dkgocr.NewResultPackage() err = rP.UnmarshalBinary(pack.ReportWithResultPackage) if err != nil { diff --git a/deployment/cre/ocr3/config.go b/deployment/cre/ocr3/config.go index 0b3363d8c2f..8c1ef1d8e61 100644 --- a/deployment/cre/ocr3/config.go +++ b/deployment/cre/ocr3/config.go @@ -202,7 +202,7 @@ func (c *OCR2OracleConfig) UnmarshalJSON(data []byte) error { return nil } -func GenerateOCR3Config(cfg OracleConfig, nca []NodeKeys, secrets focr.OCRSecrets) (OCR2OracleConfig, error) { +func GenerateOCR3Config(cfg OracleConfig, nca []NodeKeys, secrets focr.OCRSecrets, reportingPluginConfigOverride []byte) (OCR2OracleConfig, error) { // the transmission schedule is very specific; arguably it should be not be a parameter if len(cfg.TransmissionSchedule) != 1 || cfg.TransmissionSchedule[0] != len(nca) { return OCR2OracleConfig{}, fmt.Errorf("transmission schedule must have exactly one entry, matching the len of the number of nodes want [%d], got %v. Total TransmissionSchedules = %d", len(nca), cfg.TransmissionSchedule, len(cfg.TransmissionSchedule)) @@ -292,22 +292,26 @@ func GenerateOCR3Config(cfg OracleConfig, nca []NodeKeys, secrets focr.OCRSecret // let's keep reqTimeout as nil if it's 0, so we can use the default value within `chainlink-common`. // See: https://github.com/smartcontractkit/chainlink-common/blob/main/pkg/capabilities/consensus/ocr3/factory.go#L73 - var reqTimeout *durationpb.Duration - if cfg.RequestTimeout > 0 { - reqTimeout = durationpb.New(cfg.RequestTimeout) - } - cfgBytes, err := proto.Marshal(&capocr3types.ReportingPluginConfig{ - MaxQueryLengthBytes: cfg.MaxQueryLengthBytes, - MaxObservationLengthBytes: cfg.MaxObservationLengthBytes, - MaxReportLengthBytes: cfg.MaxReportLengthBytes, - MaxOutcomeLengthBytes: cfg.MaxOutcomeLengthBytes, - MaxReportCount: cfg.MaxReportCount, - MaxBatchSize: cfg.MaxBatchSize, - OutcomePruningThreshold: cfg.OutcomePruningThreshold, - RequestTimeout: reqTimeout, - }) - if err != nil { - return OCR2OracleConfig{}, fmt.Errorf("failed to marshal ReportingPluginConfig: %w", err) + cfgBytes := reportingPluginConfigOverride + if cfgBytes == nil { + var reqTimeout *durationpb.Duration + if cfg.RequestTimeout > 0 { + reqTimeout = durationpb.New(cfg.RequestTimeout) + } + var err2 error + cfgBytes, err2 = proto.Marshal(&capocr3types.ReportingPluginConfig{ + MaxQueryLengthBytes: cfg.MaxQueryLengthBytes, + MaxObservationLengthBytes: cfg.MaxObservationLengthBytes, + MaxReportLengthBytes: cfg.MaxReportLengthBytes, + MaxOutcomeLengthBytes: cfg.MaxOutcomeLengthBytes, + MaxReportCount: cfg.MaxReportCount, + MaxBatchSize: cfg.MaxBatchSize, + OutcomePruningThreshold: cfg.OutcomePruningThreshold, + RequestTimeout: reqTimeout, + }) + if err2 != nil { + return OCR2OracleConfig{}, fmt.Errorf("failed to marshal ReportingPluginConfig: %w", err2) + } } signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig, err := ocr3confighelper.ContractSetConfigArgsDeterministic( @@ -366,6 +370,8 @@ type ConfigureOCR3Request struct { DryRun bool OcrSecrets focr.OCRSecrets + ReportingPluginConfigOverride []byte + UseMCMS bool } @@ -374,7 +380,7 @@ func (r ConfigureOCR3Request) generateOCR3Config() (OCR2OracleConfig, error) { if r.Cfg == nil { return OCR2OracleConfig{}, errors.New("OCR3 config is required") } - return GenerateOCR3Config(*r.Cfg, nks, r.OcrSecrets) + return GenerateOCR3Config(*r.Cfg, nks, r.OcrSecrets, r.ReportingPluginConfigOverride) } type ConfigureOCR3Response struct { @@ -441,6 +447,8 @@ type ConfigureOCR3Config struct { OCR3Config *OracleConfig DryRun bool + ReportingPluginConfigOverride []byte + UseMCMS bool } @@ -467,13 +475,14 @@ func ConfigureOCR3ContractFromJD(env *cldf.Environment, cfg ConfigureOCR3Config) return nil, err } r, err := ConfigureOCR3contract(ConfigureOCR3Request{ - Cfg: cfg.OCR3Config, - Chain: registryChain, - Contract: contract, - Nodes: nodes, - DryRun: cfg.DryRun, - UseMCMS: cfg.UseMCMS, - OcrSecrets: env.OCRSecrets, + Cfg: cfg.OCR3Config, + Chain: registryChain, + Contract: contract, + Nodes: nodes, + DryRun: cfg.DryRun, + UseMCMS: cfg.UseMCMS, + OcrSecrets: env.OCRSecrets, + ReportingPluginConfigOverride: cfg.ReportingPluginConfigOverride, }) if err != nil { return nil, err diff --git a/deployment/cre/ocr3/v2/changeset/operations/contracts/configure_ocr3.go b/deployment/cre/ocr3/v2/changeset/operations/contracts/configure_ocr3.go index 90e8ad97ed5..e3d90c823d9 100644 --- a/deployment/cre/ocr3/v2/changeset/operations/contracts/configure_ocr3.go +++ b/deployment/cre/ocr3/v2/changeset/operations/contracts/configure_ocr3.go @@ -35,6 +35,8 @@ type ConfigureOCR3Input struct { Config *ocr3.OracleConfig DryRun bool + ReportingPluginConfigOverride []byte + MCMSConfig *ocr3.MCMSConfig } @@ -66,12 +68,13 @@ var ConfigureOCR3 = operations.NewOperation[ConfigureOCR3Input, ConfigureOCR3OpO } resp, err := ocr3.ConfigureOCR3ContractFromJD(deps.Env, ocr3.ConfigureOCR3Config{ - ChainSel: input.ChainSelector, - NodeIDs: input.DON.NodeIDs, - OCR3Config: input.Config, - Contract: contract.Contract, - DryRun: input.DryRun, - UseMCMS: input.UseMCMS(), + ChainSel: input.ChainSelector, + NodeIDs: input.DON.NodeIDs, + OCR3Config: input.Config, + Contract: contract.Contract, + DryRun: input.DryRun, + UseMCMS: input.UseMCMS(), + ReportingPluginConfigOverride: input.ReportingPluginConfigOverride, }) if err != nil { return ConfigureOCR3OpOutput{}, fmt.Errorf("failed to configure OCR3Capability: %w", err) diff --git a/system-tests/lib/cre/contracts/contracts.go b/system-tests/lib/cre/contracts/contracts.go index 4e49e96c436..f2e555b605a 100644 --- a/system-tests/lib/cre/contracts/contracts.go +++ b/system-tests/lib/cre/contracts/contracts.go @@ -20,7 +20,9 @@ import ( "github.com/smartcontractkit/chainlink-evm/gethwrappers/data-feeds/generated/data_feeds_cache" kcr "github.com/smartcontractkit/chainlink-evm/gethwrappers/keystone/generated/capabilities_registry_1_1_0" + ocr3_capability "github.com/smartcontractkit/chainlink-evm/gethwrappers/keystone/generated/ocr3_capability_1_0_0" + vaultprotos "github.com/smartcontractkit/chainlink-common/pkg/capabilities/actions/vault" "github.com/smartcontractkit/chainlink-deployments-framework/datastore" cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" @@ -524,24 +526,6 @@ func ConfigureKeystone(input cre.ConfigureKeystoneInput) error { return fmt.Errorf("failed to get vault DON: %w", err) } - _, err = operations.ExecuteOperation( - input.CldEnv.OperationsBundle, - ks_contracts_op.ConfigureOCR3Op, - ks_contracts_op.ConfigureOCR3OpDeps{ - Env: input.CldEnv, - }, - ks_contracts_op.ConfigureOCR3OpInput{ - ContractAddress: input.VaultOCR3Address, - ChainSelector: input.ChainSelector, - DON: vaultDON.keystoneDonConfig(), - Config: vaultDON.resolveOcr3Config(input.VaultOCR3Config), - DryRun: false, - }, - ) - if err != nil { - return errors.Wrap(err, "failed to configure Vault OCR3 contract") - } - _, err = operations.ExecuteOperation( input.CldEnv.OperationsBundle, ks_contracts_op.ConfigureDKGOp, @@ -560,6 +544,42 @@ func ConfigureKeystone(input cre.ConfigureKeystoneInput) error { if err != nil { return errors.Wrap(err, "failed to configure DKG OCR3 contract") } + + client := input.CldEnv.BlockChains.EVMChains()[input.ChainSelector].Client + dkgContract, err := ocr3_capability.NewOCR3Capability(*input.DKGOCR3Address, client) + if err != nil { + return errors.Wrap(err, "failed to create OCR3 capability contract") + } + details, err := dkgContract.LatestConfigDetails(nil) + if err != nil { + return errors.Wrap(err, "failed to get latest config details from OCR3 capability contract") + } + instanceID := string(dkgocrtypes.MakeInstanceID(dkgContract.Address(), details.ConfigDigest)) + cfg := vaultprotos.ReportingPluginConfig{ + DKGInstanceID: &instanceID, + } + cfgb, err := proto.Marshal(&cfg) + if err != nil { + return errors.Wrap(err, "failed to marshal vault reporting plugin config") + } + _, err = operations.ExecuteOperation( + input.CldEnv.OperationsBundle, + ks_contracts_op.ConfigureOCR3Op, + ks_contracts_op.ConfigureOCR3OpDeps{ + Env: input.CldEnv, + }, + ks_contracts_op.ConfigureOCR3OpInput{ + ContractAddress: input.VaultOCR3Address, + ChainSelector: input.ChainSelector, + DON: vaultDON.keystoneDonConfig(), + Config: vaultDON.resolveOcr3Config(input.VaultOCR3Config), + DryRun: false, + ReportingPluginConfigOverride: cfgb, + }, + ) + if err != nil { + return errors.Wrap(err, "failed to configure Vault OCR3 contract") + } } for chainSelector, evmOCR3Address := range input.EVMOCR3Addresses { diff --git a/system-tests/tests/smoke/cre/v2_vault_don_test.go b/system-tests/tests/smoke/cre/v2_vault_don_test.go index 908b97cc413..d4314f2841c 100644 --- a/system-tests/tests/smoke/cre/v2_vault_don_test.go +++ b/system-tests/tests/smoke/cre/v2_vault_don_test.go @@ -35,26 +35,32 @@ func ExecuteVaultTest(t *testing.T, testEnv *TestEnvironment) { var testLogger = framework.L testLogger.Info().Msgf("Ensuring DKG result packages are present...") - var vaultFound bool - for _, nodeSet := range testEnv.Config.NodeSets { - for _, cap := range nodeSet.Capabilities { - if cap == cre.VaultCapability { - vaultFound = true - break + require.Eventually(t, func() bool { + for _, nodeSet := range testEnv.Config.NodeSets { + var vaultFound bool + for _, cap := range nodeSet.Capabilities { + if cap == cre.VaultCapability { + vaultFound = true + break + } } - } - if vaultFound { - for i := range nodeSet.Nodes { - if i != nodeSet.BootstrapNodeIndex { - packageCount, err := vault.GetResultPackageCount(t.Context(), i, nodeSet.DbInput.Port) - require.NoError(t, err, "failed to get result package count") - require.Equal(t, int64(1), packageCount, "expected one result package in the database") + if vaultFound { + for i := range nodeSet.Nodes { + if i != nodeSet.BootstrapNodeIndex { + packageCount, err := vault.GetResultPackageCount(t.Context(), i, nodeSet.DbInput.Port) + if err != nil || packageCount != 1 { + return false + } + } } + return true } - break } - } - require.True(t, vaultFound, "no node set with vault capability found in topology") + return false + }, time.Second*300, time.Second*5) + + // Wait a bit to ensure the Vault plugin is ready. + time.Sleep(30 * time.Second) testLogger.Info().Msg("Getting gateway configuration...") require.NotEmpty(t, testEnv.FullCldEnvOutput.DonTopology.GatewayConnectorOutput.Configurations, "expected at least one gateway configuration")