Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
502c657
wip: refactor ocr3 config in local env
krehermann Aug 29, 2025
8c2bd51
start refactoring the setup of contracts
krehermann Aug 30, 2025
6bbccf8
ocr3 deploy sequence
krehermann Aug 30, 2025
ff25fae
add deploy ocr wrapper func
krehermann Aug 30, 2025
6dd7e71
datastore hints, comments, cleanup
krehermann Aug 30, 2025
6189553
finish minimal refactor for multiple ocr3 support
krehermann Aug 30, 2025
a3662f4
rm dead code
krehermann Aug 30, 2025
5315925
cleanup; rm donCapabilities slice
krehermann Aug 30, 2025
7b8214c
review comments
krehermann Sep 1, 2025
8b3902d
use 4 nodes for capability DON, so they can run OCR. Fix internal hos…
Tofel Sep 1, 2025
aeaae8d
refactor(smoke/cre): accept v2 registry flag in PoR test
MStreet3 Sep 2, 2025
25e9278
feat(cre): get default contract set from cli flag
MStreet3 Sep 2, 2025
b9172b0
refactor(cre): cli flags clean up
MStreet3 Sep 2, 2025
d8d0250
feat(operations): deploy v2 cap registry
MStreet3 Aug 28, 2025
407ecb4
refactor(capabilities): allow setting v2 config for cap
MStreet3 Aug 28, 2025
2fcdc8f
chore: wire in v2 contracts
MStreet3 Aug 28, 2025
1baa385
refactor(environment): remove lint warnings
MStreet3 Sep 2, 2025
3636fc6
chore: support checking registry version
MStreet3 Sep 2, 2025
08a9d17
refactor(lib/cre): get type and version when fetching contract
MStreet3 Sep 2, 2025
3d35e34
chore: fix missing use of type and version
MStreet3 Sep 2, 2025
23dbfba
refactor: logs some contract versions
MStreet3 Sep 2, 2025
05d947a
feat: deploys wf reg v2 in sequence
MStreet3 Sep 2, 2025
05491d7
refactor: remove keystone from struct names
MStreet3 Sep 2, 2025
69874b5
Merge branch 'develop' into cre-deploy/ocr-op
krehermann Sep 2, 2025
288c2f4
feat: deploys v2 wf registry
MStreet3 Sep 2, 2025
aa8aee3
chore: skip test
MStreet3 Sep 2, 2025
905b5c3
try to fix ci timeout
krehermann Sep 2, 2025
8875275
Merge branch 'develop' into cre-741/v2-contracts-cre
MStreet3 Sep 3, 2025
294cf1d
refactor: removes Get prefixes
MStreet3 Sep 3, 2025
6bcb59d
chore: lint
MStreet3 Sep 3, 2025
077e3e2
fix linters
MStreet3 Sep 3, 2025
95d088c
Merge branch 'develop' into cre-741/v2-contracts-cre
MStreet3 Sep 3, 2025
be3604d
Merge branch 'develop' into cre-741/v2-contracts-cre
MStreet3 Sep 3, 2025
102505c
lint file
MStreet3 Sep 3, 2025
a16a9a5
fix: overrite default config fn
MStreet3 Sep 3, 2025
dba97e7
deps: changeset
MStreet3 Sep 3, 2025
93138c2
fix: allow nil config funcs to be skipped
MStreet3 Sep 3, 2025
8a95c5d
Merge branch 'develop' into cre-deploy/ocr-op
krehermann Sep 3, 2025
8386d8e
put back web-api-target
krehermann Sep 4, 2025
a6e03f9
Merge branch 'develop' into cre-741/v2-contracts-cre
MStreet3 Sep 4, 2025
fa40734
Merge branch 'cre-deploy/ocr-op' into cre-741/v2-contracts-cre
MStreet3 Sep 4, 2025
95a9394
refactor: create v2 deploy sequence
MStreet3 Sep 4, 2025
71272cd
Merge branch 'develop' into fix/cre-741
MStreet3 Sep 4, 2025
646b1fb
clean up
MStreet3 Sep 4, 2025
6a4f8fe
lint
MStreet3 Sep 4, 2025
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
5 changes: 5 additions & 0 deletions .changeset/forty-zebras-grab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

#internal deploys V2 registries in local CRE
5 changes: 3 additions & 2 deletions core/scripts/cre/environment/environment/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ func startCmd() *cobra.Command {
withV2Registries := withContractsVersion == "v2"
envDependencies := cre.NewEnvironmentDependencies(
flags.NewDefaultCapabilityFlagsProvider(),
cre.NewContractVersionsProvider(envconfig.GetDefaultContractSet(withV2Registries)),
cre.NewContractVersionsProvider(envconfig.DefaultContractSet(withV2Registries)),
cre.NewCLIFlagsProvider(withV2Registries),
)

Expand Down Expand Up @@ -675,7 +675,8 @@ func StartCLIEnvironment(
universalSetupInput := creenv.SetupInput{
CapabilitiesAwareNodeSets: in.NodeSets,
BlockchainsInput: in.Blockchains,
ContractVersions: env.GetContractVersions(),
ContractVersions: env.ContractVersions(),
WithV2Registries: env.WithV2Registries(),
JdInput: *in.JD,
InfraInput: *in.Infra,
S3ProviderInput: in.S3ProviderInput,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type DeployCapabilitiesRegistryOutput struct {

// DeployCapabilitiesRegistry is an operation that deploys the V2 Capabilities Registry contract.
// This atomic operation performs the single side effect of deploying and registering the contract.
var DeployCapabilitiesRegistry = operations.NewOperation[DeployCapabilitiesRegistryInput, DeployCapabilitiesRegistryOutput, DeployCapabilitiesRegistryDeps](
var DeployCapabilitiesRegistry = operations.NewOperation(
"deploy-capabilities-registry-v2-op",
semver.MustParse("1.0.0"),
"Deploy CapabilitiesRegistry V2 Contract",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@ import (
"github.com/smartcontractkit/chainlink-deployments-framework/datastore"
"github.com/smartcontractkit/chainlink-deployments-framework/deployment"
"github.com/smartcontractkit/chainlink-deployments-framework/operations"

cap_reg_v2 "github.com/smartcontractkit/chainlink/deployment/cre/capabilities_registry/v2/changeset/operations/contracts"
wf_reg_v2 "github.com/smartcontractkit/chainlink/deployment/cre/workflow_registry/v2/changeset/operations/contracts"
)

type EVMChainID uint64
type Selector uint64
type (
EVMChainID uint64
Selector uint64
)

// inputs and outputs have to be serializable, and must not contain sensitive data
type DeployContractsSequenceDeps struct {
Expand Down Expand Up @@ -43,7 +48,7 @@ func updateAddresses(addr datastore.MutableAddressRefStore, as datastore.Address
}

// DeployRegistryContractsSequence is a sequence that deploys the the required registry contracts (Capabilities Registry, Workflow Registry).
var DeployRegistryContractsSequence = operations.NewSequence[DeployRegistryContractsSequenceInput, DeployContractSequenceOutput, DeployContractsSequenceDeps](
var DeployRegistryContractsSequence = operations.NewSequence(
// do not add optional contracts here (ocr, forwarder...), as this sequence is used to deploy the registry contracts that other sequences depend on
"deploy-registry-contracts-seq",
semver.MustParse("1.0.0"),
Expand Down Expand Up @@ -74,10 +79,116 @@ var DeployRegistryContractsSequence = operations.NewSequence[DeployRegistryContr
AddressBook: ab,
Datastore: as.Seal(),
}, nil
},
)

// DeployV2RegistryContractsSequence is a sequence that deploys the the required registry contracts (Capabilities Registry, Workflow Registry).
var DeployV2RegistryContractsSequence = operations.NewSequence(
// do not add optional contracts here (ocr, forwarder...), as this sequence is used to deploy the registry contracts that other sequences depend on
"deploy-v2-registry-contracts-seq",
semver.MustParse("1.0.0"),
"Deploy V2 registry Contracts (Capabilities Registry, Workflow Registry)",
func(b operations.Bundle, deps DeployContractsSequenceDeps, input DeployRegistryContractsSequenceInput) (output DeployContractSequenceOutput, err error) {
ab := deployment.NewMemoryAddressBook()
as := datastore.NewMemoryDataStore()

// Capabilities Registry contract
capabilitiesRegistryDeployReport, err := operations.ExecuteOperation(b, cap_reg_v2.DeployCapabilitiesRegistry, cap_reg_v2.DeployCapabilitiesRegistryDeps(deps), cap_reg_v2.DeployCapabilitiesRegistryInput{ChainSelector: input.RegistryChainSelector})
if err != nil {
return DeployContractSequenceOutput{}, err
}

v1Output, err := toV1Output(capabilitiesRegistryDeployReport.Output)
if err != nil {
return DeployContractSequenceOutput{}, err
}

if err = updateAddresses(as.Addresses(), v1Output.Addresses, ab, v1Output.AddressBook); err != nil {
return DeployContractSequenceOutput{}, err
}

// Workflow Registry contract
workflowRegistryDeployReport, err := operations.ExecuteOperation(b, wf_reg_v2.DeployWorkflowRegistryOp, wf_reg_v2.DeployWorkflowRegistryOpDeps(deps), wf_reg_v2.DeployWorkflowRegistryOpInput{ChainSelector: input.RegistryChainSelector})
if err != nil {
return DeployContractSequenceOutput{}, err
}

v1Output, err = toV1Output(workflowRegistryDeployReport.Output)
if err != nil {
return DeployContractSequenceOutput{}, err
}

err = updateAddresses(as.Addresses(), v1Output.Addresses, ab, v1Output.AddressBook)
if err != nil {
return DeployContractSequenceOutput{}, err
}
return DeployContractSequenceOutput{
AddressBook: ab,
Datastore: as.Seal(),
}, nil
},
)

func CapabilityContractIdentifier(chainID uint64) string {
return fmt.Sprintf("capability_evm_%d", chainID)
}

type DeprecatedOutput struct {
Addresses datastore.AddressRefStore
AddressBook deployment.AddressBook
}

// toV1Output transforms a v2 output to a common output format that uses the deprecated
// address book.
func toV1Output(in any) (DeprecatedOutput, error) {
ab := deployment.NewMemoryAddressBook()
ds := datastore.NewMemoryDataStore()
labels := deployment.NewLabelSet()
var r datastore.AddressRef

switch v := in.(type) {
case cap_reg_v2.DeployCapabilitiesRegistryOutput:
r = datastore.AddressRef{
ChainSelector: v.ChainSelector,
Address: v.Address,
Type: datastore.ContractType(v.Type),
Version: semver.MustParse(v.Version),
Qualifier: v.Qualifier,
Labels: datastore.NewLabelSet(v.Labels...),
}
for _, l := range v.Labels {
labels.Add(l)
}
case wf_reg_v2.DeployWorkflowRegistryOpOutput:
r = datastore.AddressRef{
ChainSelector: v.ChainSelector,
Address: v.Address,
Type: datastore.ContractType(v.Type),
Version: semver.MustParse(v.Version),
Qualifier: v.Qualifier,
Labels: datastore.NewLabelSet(v.Labels...),
}
for _, l := range v.Labels {
labels.Add(l)
}
default:
return DeprecatedOutput{}, fmt.Errorf("unsupported input type for transform: %T", in)
}

if err := ds.Addresses().Add(r); err != nil {
return DeprecatedOutput{}, fmt.Errorf("failed to add address ref: %w", err)
}

if err := ab.Save(r.ChainSelector, r.Address, deployment.TypeAndVersion{
Type: deployment.ContractType(r.Type),
Version: *r.Version,
Labels: labels,
}); err != nil {
return DeprecatedOutput{}, fmt.Errorf("failed to save address to address book: %w", err)
}

return DeprecatedOutput{
Addresses: ds.Addresses(),
AddressBook: ab,
}, nil
}
51 changes: 42 additions & 9 deletions system-tests/lib/cre/capabilities/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@ import (
"github.com/smartcontractkit/chainlink/system-tests/lib/cre"
)

type registryConfigFns struct {
V1 cre.CapabilityRegistryConfigFn
V2 cre.CapabilityRegistryConfigFn
}

type Capability struct {
flag cre.CapabilityFlag
jobSpecFn cre.JobSpecFn
nodeConfigFn cre.NodeConfigTransformerFn
gatewayJobHandlerConfigFn cre.GatewayHandlerConfigFn
capabilityRegistryV1ConfigFn cre.CapabilityRegistryConfigFn
validateFn func(*Capability) error
flag cre.CapabilityFlag
jobSpecFn cre.JobSpecFn
nodeConfigFn cre.NodeConfigTransformerFn
gatewayJobHandlerConfigFn cre.GatewayHandlerConfigFn
registryConfigFns *registryConfigFns
validateFn func(*Capability) error
}

func (c *Capability) Flag() cre.CapabilityFlag {
Expand All @@ -32,7 +37,17 @@ func (c *Capability) GatewayJobHandlerConfigFn() cre.GatewayHandlerConfigFn {
}

func (c *Capability) CapabilityRegistryV1ConfigFn() cre.CapabilityRegistryConfigFn {
return c.capabilityRegistryV1ConfigFn
if c.registryConfigFns != nil {
return c.registryConfigFns.V1
}
return nil
}

func (c *Capability) CapabilityRegistryV2ConfigFn() cre.CapabilityRegistryConfigFn {
if c.registryConfigFns != nil {
return c.registryConfigFns.V2
}
return nil
}

type Option func(*Capability)
Expand All @@ -55,9 +70,27 @@ func WithGatewayJobHandlerConfigFn(gatewayJobHandlerConfigFn cre.GatewayHandlerC
}
}

func WithCapabilityRegistryV1ConfigFn(capabilityRegistryV1ConfigFn cre.CapabilityRegistryConfigFn) Option {
func WithCapabilityRegistryV1ConfigFn(fn cre.CapabilityRegistryConfigFn) Option {
return func(c *Capability) {
c.capabilityRegistryV1ConfigFn = capabilityRegistryV1ConfigFn
if c.registryConfigFns == nil {
c.registryConfigFns = &registryConfigFns{
V1: fn,
}
return
}
c.registryConfigFns.V1 = fn
}
}

func WithCapabilityRegistryV2ConfigFn(fn cre.CapabilityRegistryConfigFn) Option {
return func(c *Capability) {
if c.registryConfigFns == nil {
c.registryConfigFns = &registryConfigFns{
V2: fn,
}
return
}
c.registryConfigFns.V2 = fn
}
}

Expand Down
14 changes: 8 additions & 6 deletions system-tests/lib/cre/capabilities/evm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ import (
"github.com/smartcontractkit/chainlink/system-tests/lib/cre/don/jobs/ocr/chainlevel"
)

const flag = cre.EVMCapability
const configTemplate = `'{"chainId":{{.ChainID}},"network":"{{.NetworkFamily}}","logTriggerPollInterval":{{.LogTriggerPollInterval}}, "creForwarderAddress":"{{.CreForwarderAddress}}","receiverGasMinimum":{{.ReceiverGasMinimum}},"nodeAddress":"{{.NodeAddress}}"}'`
const registrationRefresh = 20 * time.Second
const registrationExpiry = 60 * time.Second
const (
flag = cre.EVMCapability
configTemplate = `'{"chainId":{{.ChainID}},"network":"{{.NetworkFamily}}","logTriggerPollInterval":{{.LogTriggerPollInterval}}, "creForwarderAddress":"{{.CreForwarderAddress}}","receiverGasMinimum":{{.ReceiverGasMinimum}},"nodeAddress":"{{.NodeAddress}}"}'`
registrationRefresh = 20 * time.Second
registrationExpiry = 60 * time.Second
)

func New(registryChainID uint64) (*capabilities.Capability, error) {
registryChainSelector, err := chainselectors.SelectorFromChainId(registryChainID)
Expand Down Expand Up @@ -105,7 +107,7 @@ func buildRuntimeValues(chainID uint64, networkFamily, creForwarderAddress, node

func jobSpecWithRegistryChainSelector(registryChainSelector uint64) cre.JobSpecFn {
return func(input *cre.JobSpecInput) (cre.DonsToJobSpecs, error) {
var generateJobSpec = func(logger zerolog.Logger, chainID uint64, nodeAddress string, mergedConfig map[string]any) (string, error) {
generateJobSpec := func(logger zerolog.Logger, chainID uint64, nodeAddress string, mergedConfig map[string]any) (string, error) {
cs, ok := chainselectors.EvmChainIdToChainSelector()[chainID]
if !ok {
return "", fmt.Errorf("chain selector not found for chainID: %d", chainID)
Expand Down Expand Up @@ -150,7 +152,7 @@ func jobSpecWithRegistryChainSelector(registryChainSelector uint64) cre.JobSpecF
return configStr, nil
}

var dataStoreOCR3ContractKeyProvider = func(contractName string, _ uint64) datastore.AddressRefKey {
dataStoreOCR3ContractKeyProvider := func(contractName string, _ uint64) datastore.AddressRefKey {
return datastore.NewAddressRefKey(
// we have deployed OCR3 contract for each EVM chain on the registry chain to avoid a situation when more than 1 OCR contract (of any type) has the same address
// because that violates a DB constraint for offchain reporting jobs
Expand Down
2 changes: 1 addition & 1 deletion system-tests/lib/cre/capabilities/gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ func generateConfig(input cre.GenerateConfigsInput, configOverrides cre.NodeInde
return nil, errors.Wrap(homeErr, "failed to get home chain ID")
}

workflowRegistryAddress, workErr := crecontracts.FindAddressesForChain(input.AddressBook, input.HomeChainSelector, keystone_changeset.WorkflowRegistry.String())
workflowRegistryAddress, _, workErr := crecontracts.FindAddressesForChain(input.AddressBook, input.HomeChainSelector, keystone_changeset.WorkflowRegistry.String())
if workErr != nil {
return nil, errors.Wrap(workErr, "failed to find WorkflowRegistry address")
}
Expand Down
15 changes: 7 additions & 8 deletions system-tests/lib/cre/contracts/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,27 +464,26 @@ func DefaultOCR3Config(topology *cre.Topology) (*keystone_changeset.OracleConfig
return oracleConfig, nil
}

// TODO: CRE-742 use datastore
func FindAddressesForChain(addressBook cldf.AddressBook, chainSelector uint64, contractName string) (common.Address, error) {
func FindAddressesForChain(addressBook cldf.AddressBook, chainSelector uint64, contractName string) (common.Address, cldf.TypeAndVersion, error) {
addresses, err := addressBook.AddressesForChain(chainSelector)
if err != nil {
return common.Address{}, errors.Wrap(err, "failed to get addresses for chain")
return common.Address{}, cldf.TypeAndVersion{}, errors.Wrap(err, "failed to get addresses for chain")
}

for addrStr, tv := range addresses {
if !strings.Contains(tv.String(), contractName) {
continue
}

return common.HexToAddress(addrStr), nil
return common.HexToAddress(addrStr), tv, nil
}

return common.Address{}, fmt.Errorf("failed to find %s address in the address book for chain %d", contractName, chainSelector)
return common.Address{}, cldf.TypeAndVersion{}, fmt.Errorf("failed to find %s address in the address book for chain %d", contractName, chainSelector)
}

// TODO: CRE-742 use datastore
func MustFindAddressesForChain(addressBook cldf.AddressBook, chainSelector uint64, contractName string) common.Address {
addr, err := FindAddressesForChain(addressBook, chainSelector, contractName)
addr, _, err := FindAddressesForChain(addressBook, chainSelector, contractName)
if err != nil {
panic(fmt.Errorf("failed to find %s address in the address book for chain %d", contractName, chainSelector))
}
Expand Down Expand Up @@ -643,7 +642,7 @@ func DeployDataFeedsCacheContract(testLogger zerolog.Logger, chainSelector uint6
}
testLogger.Info().Msgf("Data Feeds Cache contract deployed to %d", chainSelector)

dataFeedsCacheAddress, dataFeedsCacheErr := FindAddressesForChain(
dataFeedsCacheAddress, _, dataFeedsCacheErr := FindAddressesForChain(
fullCldEnvOutput.Environment.ExistingAddresses, //nolint:staticcheck // won't migrate now
chainSelector,
df_changeset.DataFeedsCache.String(),
Expand All @@ -670,7 +669,7 @@ func DeployReadBalancesContract(testLogger zerolog.Logger, chainSelector uint64,
}
testLogger.Info().Msgf("Read Balances contract deployed to %d", chainSelector)

readBalancesAddress, readContractErr := FindAddressesForChain(
readBalancesAddress, _, readContractErr := FindAddressesForChain(
fullCldEnvOutput.Environment.ExistingAddresses, //nolint:staticcheck // won't migrate now
chainSelector,
keystone_changeset.BalanceReader.String(),
Expand Down
11 changes: 8 additions & 3 deletions system-tests/lib/cre/don/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,16 @@ func Generate(input cre.GenerateConfigsInput, nodeConfigFns []cre.NodeConfigTran
}

// find contract addresses
capabilitiesRegistryAddress, capErr := crecontracts.FindAddressesForChain(input.AddressBook, input.HomeChainSelector, keystone_changeset.CapabilitiesRegistry.String())
capabilitiesRegistryAddress, capRegTypeVersion, capErr := crecontracts.FindAddressesForChain(input.AddressBook, input.HomeChainSelector, keystone_changeset.CapabilitiesRegistry.String())
if capErr != nil {
return nil, errors.Wrap(capErr, "failed to find CapabilitiesRegistry address")
}

capRegistry := AddressTypeVersion{
Address: capabilitiesRegistryAddress,
TypeAndVersion: capRegTypeVersion,
}

// find bootstrap node for the Don
var donBootstrapNodeHost string
var donBootstrapNodePeerID string
Expand Down Expand Up @@ -106,7 +111,7 @@ func Generate(input cre.GenerateConfigsInput, nodeConfigFns []cre.NodeConfigTran
}

// generate configuration for the bootstrap node
configOverrides[nodeIndex] = BootstrapEVM(donBootstrapNodePeerID, homeChainID, capabilitiesRegistryAddress, evmChains)
configOverrides[nodeIndex] = BootstrapEVM(donBootstrapNodePeerID, homeChainID, capRegistry, evmChains)
if flags.HasFlag(input.Flags, cre.WorkflowDON) {
configOverrides[nodeIndex] += BoostrapDon2DonPeering(input.CapabilitiesPeeringData)
}
Expand All @@ -133,7 +138,7 @@ func Generate(input cre.GenerateConfigsInput, nodeConfigFns []cre.NodeConfigTran

// connect worker nodes to all the chains, add chain ID for registry (home chain)
var workerErr error
configOverrides[nodeIndex], workerErr = WorkerEVM(donBootstrapNodePeerID, donBootstrapNodeHost, input.OCRPeeringData, input.CapabilitiesPeeringData, capabilitiesRegistryAddress, homeChainID, evmChains)
configOverrides[nodeIndex], workerErr = WorkerEVM(donBootstrapNodePeerID, donBootstrapNodeHost, input.OCRPeeringData, input.CapabilitiesPeeringData, capRegistry, homeChainID, evmChains)
if workerErr != nil {
return nil, errors.Wrap(workerErr, "failed to generate worker [EVM.Workflow] config")
}
Expand Down
Loading
Loading