Skip to content
Draft
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
6 changes: 3 additions & 3 deletions core/scripts/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ require (
github.com/shopspring/decimal v1.4.0
github.com/smartcontractkit/chainlink-automation v0.8.1
github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20251009203201-900123a5c46a
github.com/smartcontractkit/chainlink-common v0.9.6-0.20251016213956-9a6afcd1532a
github.com/smartcontractkit/chainlink-common v0.9.6-0.20251020192613-ab3ae2841edf
github.com/smartcontractkit/chainlink-data-streams v0.1.6
github.com/smartcontractkit/chainlink-deployments-framework v0.56.0
github.com/smartcontractkit/chainlink-evm v0.3.4-0.20251017190323-e749d4a05491
Expand Down Expand Up @@ -485,13 +485,13 @@ require (
github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250717121125-2350c82883e2 // indirect
github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20250717121125-2350c82883e2 // indirect
github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250729142306-508e798f6a5d // indirect
github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20250807135425-a2c09896d609 // indirect
github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251020004840-4638e4262066 // indirect
github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b // indirect
github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 // indirect
github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 // indirect
github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 // indirect
github.com/smartcontractkit/chainlink-protos/svr v1.1.0 // indirect
github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20251008185222-47a7460f5207 // indirect
github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20251020004840-4638e4262066 // indirect
github.com/smartcontractkit/chainlink-solana v1.1.2-0.20251007010318-c9a7b2d44524 // indirect
github.com/smartcontractkit/chainlink-sui v0.0.0-20251012014843-5d44e7731854 // indirect
github.com/smartcontractkit/chainlink-sui/deployment v0.0.0-20251012014843-5d44e7731854 // indirect
Expand Down
12 changes: 6 additions & 6 deletions core/scripts/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1599,8 +1599,8 @@ github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250912190424-f
github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250912190424-fd2e35d7deb5/go.mod h1:Ve1xD71bl193YIZQEoJMmBqLGQJdNs29bwbuObwvbhQ=
github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5 h1:Z4t2ZY+ZyGWxtcXvPr11y4o3CGqhg3frJB5jXkCSvWA=
github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5/go.mod h1:xtZNi6pOKdC3sLvokDvXOhgHzT+cyBqH/gWwvxTxqrg=
github.com/smartcontractkit/chainlink-common v0.9.6-0.20251016213956-9a6afcd1532a h1:78io0EdIrI3/ZOJxHJWXGDguz5sbeoKZKlB0VTgN3O8=
github.com/smartcontractkit/chainlink-common v0.9.6-0.20251016213956-9a6afcd1532a/go.mod h1:4InnO+pggA5q4DzsKOvAKkCp1EEi12wUs4T9YClg2+g=
github.com/smartcontractkit/chainlink-common v0.9.6-0.20251020192613-ab3ae2841edf h1:l/eqgK9cRXVFoxjt9DKkkRJlcfFxPvmxk4tUVqGrAPA=
github.com/smartcontractkit/chainlink-common v0.9.6-0.20251020192613-ab3ae2841edf/go.mod h1:zxiqKMTgvXupUYWBAMUMq+DvnfAH0ZYZB7qbxD9bs8c=
github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.6 h1:INTd6uKc/QO11B0Vx7Ze17xgW3bqYbWuQcBQa9ixicQ=
github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.6/go.mod h1:eKGyfTKzr0/PeR7qKN4l2FcW9p+HzyKUwAfGhm/5YZc=
github.com/smartcontractkit/chainlink-common/pkg/monitoring v0.0.0-20250415235644-8703639403c7 h1:9wh1G+WbXwPVqf0cfSRSgwIcaXTQgvYezylEAfwmrbw=
Expand All @@ -1623,8 +1623,8 @@ github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20250717121125-23
github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20250717121125-2350c82883e2/go.mod h1:jo+cUqNcHwN8IF7SInQNXDZ8qzBsyMpnLdYbDswviFc=
github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250729142306-508e798f6a5d h1:pTYIcsWHTMG5fAcbRUA8Qk5yscXKdSpopQ0DUEOjPik=
github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250729142306-508e798f6a5d/go.mod h1:2JTBNp3FlRdO/nHc4dsc9bfxxMClMO1Qt8sLJgtreBY=
github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20250807135425-a2c09896d609 h1:7U8t4Ytj2rRnkkdAp4eFUTU34lXCCT7WYuKQWaJZfw0=
github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20250807135425-a2c09896d609/go.mod h1:HHGeDUpAsPa0pmOx7wrByCitjQ0mbUxf0R9v+g67uCA=
github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251020004840-4638e4262066 h1:D7fFxHtPZNKKh1eWcTqpasb/aBGxnQ2REssEP49l1lg=
github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251020004840-4638e4262066/go.mod h1:HHGeDUpAsPa0pmOx7wrByCitjQ0mbUxf0R9v+g67uCA=
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20251008161434-22d9bd439bba h1:M+tG22TF6jpfeGifM4UpjUzbfD2JDD3ixIX9MdZ0qH8=
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20251008161434-22d9bd439bba/go.mod h1:jUC52kZzEnWF9tddHh85zolKybmLpbQ1oNA4FjOHt1Q=
github.com/smartcontractkit/chainlink-protos/job-distributor v0.13.1 h1:PWwLGimBt37eDzpbfZ9V/ZkW4oCjcwKjKiAwKlSfPc0=
Expand All @@ -1639,8 +1639,8 @@ github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 h1:B7itmjy+C
github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0/go.mod h1:h6kqaGajbNRrezm56zhx03p0mVmmA2xxj7E/M4ytLUA=
github.com/smartcontractkit/chainlink-protos/svr v1.1.0 h1:79Z9N9dMbMVRGaLoDPAQ+vOwbM+Hnx8tIN2xCPG8H4o=
github.com/smartcontractkit/chainlink-protos/svr v1.1.0/go.mod h1:TcOliTQU6r59DwG4lo3U+mFM9WWyBHGuFkkxQpvSujo=
github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20251008185222-47a7460f5207 h1:bZ+3mm/yy2wd9ydtDRnO6Opy4QAhNZVIw/SujQb1wpU=
github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20251008185222-47a7460f5207/go.mod h1:HIpGvF6nKCdtZ30xhdkKWGM9+4Z4CVqJH8ZBL1FTEiY=
github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20251020004840-4638e4262066 h1:Lrc0+uegqasIFgsGXHy4tzdENT+zH2AbkTV4F7e3otU=
github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20251020004840-4638e4262066/go.mod h1:HIpGvF6nKCdtZ30xhdkKWGM9+4Z4CVqJH8ZBL1FTEiY=
github.com/smartcontractkit/chainlink-solana v1.1.2-0.20251007010318-c9a7b2d44524 h1:QgjF+S64bGDyaNcz11zDg7GC7FwNmYrsHN6jiJPRVkk=
github.com/smartcontractkit/chainlink-solana v1.1.2-0.20251007010318-c9a7b2d44524/go.mod h1:vcms/UPnfg7LZ2txinn59yJR6rXZ31XOk5++03LOeys=
github.com/smartcontractkit/chainlink-sui v0.0.0-20251012014843-5d44e7731854 h1:7KMcSEptDirqBY/jzNhxFvWmDE2s5KQE6uMPQ1inad4=
Expand Down
23 changes: 14 additions & 9 deletions core/services/chainlink/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,7 @@ func NewApplication(ctx context.Context, opts ApplicationOpts) (Application, err
Relayers: relayChainInterops,
MailMon: mailMon,
CapabilitiesRegistry: opts.CapabilitiesRegistry,
RegistrySyncer: creServices.capabilityRegistrySyncer,
DonTimeStore: opts.DonTimeStore,
RetirementReportCache: opts.RetirementReportCache,
GatewayConnectorServiceWrapper: creServices.gatewayConnectorWrapper,
Expand Down Expand Up @@ -889,8 +890,8 @@ type CREServices struct {
// srvs are all the services that are created, including those that are explicitly exposed
srvs []services.ServiceCtx

workflowRegistrySyncer syncerV2.WorkflowRegistrySyncer

workflowRegistrySyncer syncerV2.WorkflowRegistrySyncer
capabilityRegistrySyncer registrysyncerV2.RegistrySyncer
// orgResolver provides realtime workflow owner --> orgID resolution
orgResolver orgresolver.OrgResolver
}
Expand Down Expand Up @@ -956,6 +957,7 @@ func newCREServices(
srvcs = append(srvcs, gatewayConnectorWrapper)
}

var capRegSyncer registrysyncerV2.RegistrySyncer
var orgResolver orgresolver.OrgResolver
if cfg.CRE().Linking().URL() != "" {
var wrChainDetails chainselectors.ChainDetails
Expand Down Expand Up @@ -1097,6 +1099,7 @@ func newCREServices(

registrySyncer.AddListener(wfLauncher)
srvcs = append(srvcs, wfLauncher, registrySyncer)
capRegSyncer = registrySyncer
case 2:
registrySyncer, err := registrysyncerV2.New(
globalLogger,
Expand All @@ -1111,6 +1114,7 @@ func newCREServices(

registrySyncer.AddListener(wfLauncher)
srvcs = append(srvcs, wfLauncher, registrySyncer)
capRegSyncer = registrySyncer
default:
return nil, fmt.Errorf("could not configure capability registry syncer with version: %d", externalRegistryVersion.Major())
}
Expand Down Expand Up @@ -1300,13 +1304,14 @@ func newCREServices(
opts.CapabilitiesRegistry.SetLocalRegistry(&capabilities.TestMetadataRegistry{})
}
return &CREServices{
workflowRateLimiter: workflowRateLimiter,
workflowLimits: workflowLimits,
gatewayConnectorWrapper: gatewayConnectorWrapper,
getPeerID: getPeerID,
srvs: srvcs,
workflowRegistrySyncer: workflowRegistrySyncerV2,
orgResolver: orgResolver,
workflowRateLimiter: workflowRateLimiter,
workflowLimits: workflowLimits,
gatewayConnectorWrapper: gatewayConnectorWrapper,
getPeerID: getPeerID,
srvs: srvcs,
workflowRegistrySyncer: workflowRegistrySyncerV2,
capabilityRegistrySyncer: capRegSyncer,
orgResolver: orgResolver,
}, nil
}

Expand Down
29 changes: 27 additions & 2 deletions core/services/ocr2/delegate.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate"
"github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon"
"github.com/smartcontractkit/chainlink/v2/core/services/pipeline"
"github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer"
"github.com/smartcontractkit/chainlink/v2/core/services/relay"
evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm"
functionsRelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/functions"
Expand Down Expand Up @@ -143,6 +144,7 @@ type Delegate struct {

legacyChains legacyevm.LegacyChainContainer // legacy: use relayers instead
capabilitiesRegistry core.CapabilitiesRegistry
registrySyncer registrysyncer.RegistrySyncer
dontimeStore *dontime.Store
gatewayConnectorServiceWrapper *gatewayconnector.ServiceWrapper
WorkflowRegistrySyncer syncerV2.WorkflowRegistrySyncer
Expand Down Expand Up @@ -253,6 +255,7 @@ type DelegateOpts struct {
Relayers RelayGetter
MailMon *mailbox.Monitor
CapabilitiesRegistry core.CapabilitiesRegistry
RegistrySyncer registrysyncer.RegistrySyncer
DonTimeStore *dontime.Store
RetirementReportCache retirement.RetirementReportCache
GatewayConnectorServiceWrapper *gatewayconnector.ServiceWrapper
Expand Down Expand Up @@ -861,6 +864,27 @@ func (d *Delegate) newDonTimePlugin(
return nil, ErrRelayNotEnabled{Err: err, Relay: spec.Relay, PluginName: "dontime"}
}

var capRegConfigTracker *relay.CapRegConfigProvider
if true { // TODO: Check if {job spec?} specifies that config is stored in Cap Reg
localNode, err := d.capabilitiesRegistry.LocalNode(ctx)
if err != nil {
return nil, errors.New("Failed to get local node from cap reg")
}
// TODO: Will this work to get the DonID for tracking config in Cap Reg?
donID := localNode.WorkflowDON.ID

capName := string(jb.OCR2OracleSpec.PluginType) // TODO: Can we get Cap Name from spec or where?
capRegConfigTracker, err := relay.NewCapRegConfigProvider(ctx, lggr, donID, capName)
if err != nil {
return nil, err
}
d.registrySyncer.AddListener(capRegConfigTracker) // Subscribe to Cap Reg changes
err = d.registrySyncer.Sync(ctx, false)
if err != nil {
return nil, err
}
}

provider, err := relayer.NewPluginProvider(ctx, types.RelayArgs{
ExternalJobID: jb.ExternalJobID,
JobID: jb.ID,
Expand All @@ -870,8 +894,9 @@ func (d *Delegate) newDonTimePlugin(
RelayConfig: spec.RelayConfig.Bytes(),
ProviderType: string(types.DonTimePlugin),
}, types.PluginArgs{
TransmitterID: spec.TransmitterID.String,
PluginConfig: spec.PluginConfig.Bytes(),
TransmitterID: spec.TransmitterID.String,
PluginConfig: spec.PluginConfig.Bytes(),
CapRegConfigTracker: capRegConfigTracker,
})
if err != nil {
return nil, err
Expand Down
12 changes: 6 additions & 6 deletions core/services/registrysyncer/local_registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,12 @@ type NodeInfo struct {

type LocalRegistry struct {
core.UnimplementedCapabilitiesRegistryMetadata

Logger logger.Logger
GetPeerID func() (types.PeerID, error)
IDsToDONs map[DonID]DON
IDsToNodes map[types.PeerID]NodeInfo
IDsToCapabilities map[string]Capability
LastSyncedBlockHeight string
Logger logger.Logger
GetPeerID func() (types.PeerID, error)
IDsToDONs map[DonID]DON
IDsToNodes map[types.PeerID]NodeInfo
IDsToCapabilities map[string]Capability
}

func NewLocalRegistry(
Expand Down
17 changes: 11 additions & 6 deletions core/services/registrysyncer/syncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package registrysyncer
import (
"context"
"encoding/json"
"errors"
"fmt"
"sync"
"time"
Expand Down Expand Up @@ -251,10 +252,13 @@ func (s *registrySyncer) importOnchainRegistry(ctx context.Context) (*LocalRegis

nodes := []kcr.INodeInfoProviderNodeInfo{}

err = s.reader.GetLatestValue(ctx, s.capabilitiesContract.ReadIdentifier("getNodes"), primitives.Unconfirmed, nil, &nodes)
head, err := s.reader.GetLatestValueWithHeadData(ctx, s.capabilitiesContract.ReadIdentifier("getNodes"), primitives.Unconfirmed, nil, &nodes)
if err != nil {
return nil, err
}
if head != nil {
return nil, errors.New("Received nil head")
}

idsToNodes := map[p2ptypes.PeerID]NodeInfo{}
for _, node := range nodes {
Expand Down Expand Up @@ -285,11 +289,12 @@ func (s *registrySyncer) importOnchainRegistry(ctx context.Context) (*LocalRegis
}

return &LocalRegistry{
Logger: s.lggr,
GetPeerID: s.getPeerID,
IDsToDONs: idsToDONs,
IDsToCapabilities: idsToCapabilities,
IDsToNodes: idsToNodes,
Logger: s.lggr,
LastSyncedBlockHeight: head.Height,
GetPeerID: s.getPeerID,
IDsToDONs: idsToDONs,
IDsToCapabilities: idsToCapabilities,
IDsToNodes: idsToNodes,
}, nil
}

Expand Down
133 changes: 133 additions & 0 deletions core/services/relay/cap_reg_config_provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package relay

import (
"bytes"
"context"
"github.com/pkg/errors"
"strconv"

"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer"
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
)

var _ ocrtypes.ContractConfigTracker = &CapRegConfigProvider{}

// CapRegConfigProvider subscribes to the registrySyncer for on-chain changes in the Capability Registry.
// Parses config from on-chain Capability Config.
type CapRegConfigProvider struct {
services.StateMachine
lggr logger.Logger

lastSyncedBlockHeight string
localConfig ocrtypes.ContractConfig
donID registrysyncer.DonID
capability string
initialSync bool
}

func NewCapRegConfigProvider(ctx context.Context, lggr logger.Logger, donID uint32, capability string) (*CapRegConfigProvider, error) {
return newCapRegConfigProvider(ctx, lggr, donID, capability)
}

func newCapRegConfigProvider(ctx context.Context, lggr logger.Logger, donID uint32, capability string) (*CapRegConfigProvider, error) {
return &CapRegConfigProvider{
lggr: logger.Named(lggr, "ConfigPoller"),
donID: registrysyncer.DonID(donID),
capability: capability,
// localConfig will be updated once sync is called on registry syncer
localConfig: ocrtypes.ContractConfig{},
initialSync: false,
}, nil
}

// Subscribes to registry syncer for config changes
var _ registrysyncer.Listener = &CapRegConfigProvider{}

func (cp *CapRegConfigProvider) OnNewRegistry(ctx context.Context, registry *registrysyncer.LocalRegistry) error {
if registry == nil {
return errors.New("registry is nil")
}
cp.initialSync = true

don, ok := registry.IDsToDONs[cp.donID]
if !ok {
cp.lggr.Warnw("DON not found in registry", "donID", cp.donID)
return nil
}

capConfig, ok := don.CapabilityConfigurations[cp.capability]
if !ok {
cp.lggr.Warnw("Capability not found for DON", "donID", cp.donID, "capability", cp.capability)
return nil
}

// This config is on-chain in the Capability Registry
newOnChainConfig := capConfig.Config
cp.lastSyncedBlockHeight = registry.LastSyncedBlockHeight

// TODO: Do we unmarshal newOnChainConfig into ocrtypes.ContractConfig or is that just the OnchainConfig?
// TODO: If so, how do we obtain the rest of the information?
cp.localConfig = ocrtypes.ContractConfig{
ConfigDigest: ocrtypes.ConfigDigest{},
ConfigCount: 0,
Signers: nil,
Transmitters: nil,
F: don.F,
OnchainConfig: nil, // TODO: Is newOnChainConfig just this part?
OffchainConfigVersion: 0,
OffchainConfig: nil,
}

if !bytes.Equal(newOnChainConfig, cp.localConfig.OnchainConfig) {
cp.lggr.Infow("capability config updated", "donID", cp.donID, "capability", cp.capability)
cp.localConfig.OnchainConfig = newOnChainConfig
}
return nil
}

// LatestConfigDetails returns the latest config details from the logs
func (cp *CapRegConfigProvider) LatestConfigDetails(ctx context.Context) (changedInBlock uint64, configDigest ocrtypes.ConfigDigest, err error) {
if !cp.initialSync {
return 0, ocrtypes.ConfigDigest{}, errors.New("Config Provider has not been synced yet")
}
blockHeight, err := cp.LatestBlockHeight(ctx)
if err != nil {
return 0, ocrtypes.ConfigDigest{}, err
}
// TODO: Implement Config Digest...
return blockHeight, ocrtypes.ConfigDigest{}, errors.New("Unimplemented")
}

// LatestConfig returns the latest config from the logs on a certain block
func (cp *CapRegConfigProvider) LatestConfig(ctx context.Context, changedInBlock uint64) (ocrtypes.ContractConfig, error) {
if !cp.initialSync {
return ocrtypes.ContractConfig{}, errors.New("Config Provider has not been synced yet")
}
latestConfigSet := ocrtypes.ContractConfig{
ConfigDigest: cp.localConfig.ConfigDigest,
ConfigCount: cp.localConfig.ConfigCount,
Signers: cp.localConfig.Signers,
Transmitters: cp.localConfig.Transmitters,
F: cp.localConfig.F,
OnchainConfig: cp.localConfig.OnchainConfig,
OffchainConfigVersion: cp.localConfig.OffchainConfigVersion,
OffchainConfig: cp.localConfig.OffchainConfig,
}
cp.lggr.Infow("LatestConfig", "latestConfig", latestConfigSet)
return latestConfigSet, nil
}

// LatestBlockHeight returns the latest block height from the logs
func (cp *CapRegConfigProvider) LatestBlockHeight(_ context.Context) (blockHeight uint64, err error) {
blockHeight, err = strconv.ParseUint(cp.lastSyncedBlockHeight, 10, 64)
if err != nil {
return 0, err
}
return blockHeight, err
}

func (cp *CapRegConfigProvider) Notify() <-chan struct{} {
return nil
}
Loading