Skip to content

offchain tooling api#1031

Merged
harry-secure merged 6 commits intomainfrom
tt/offchain
Apr 22, 2026
Merged

offchain tooling api#1031
harry-secure merged 6 commits intomainfrom
tt/offchain

Conversation

@tt-cll
Copy link
Copy Markdown
Contributor

@tt-cll tt-cll commented Apr 17, 2026

No description provided.

Comment thread evm/go.mod
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little hesitant to bury modules in build/devenv. Should we put this in a new top-level package called platform and treat that directory as a sort of mono-repo?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the EVM impl of offchain tooling and it is at the top level :-). Don't know if there's a better home for that

Where should the EVM impl live vs the interface declarations? We can rename chainlink-ccv/deployment to chainlink-ccv/platform if that's clearer

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fine for now, maybe we can have an evm/deployment which has the interface implementations of the offchain deployment interfaces?

I'm imagining that in the future evm could also hold the evm-specific implementations of the chainaccess interfaces as well.

The chainlink-ccv/platform module can then have the subdirectories devenv for the devenv package and deployment for the offchain deployment API?

@tt-cll tt-cll marked this pull request as ready for review April 17, 2026 20:33
@tt-cll tt-cll requested review from a team and skudasov as code owners April 17, 2026 20:33
Copilot AI review requested due to automatic review settings April 17, 2026 20:33
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a CCV “offchain tooling API” layer: chain-family adapters (starting with EVM) plus deployment operations/changesets for generating offchain service configs and managing Job Distributor (JD) job proposals, and updates the devenv tooling to use these new APIs.

Changes:

  • Add a new deployment module with topology/config models, env-metadata persistence helpers, JD-facing operations (propose/revoke/sync), and changesets (apply verifier/executor configs; generate aggregator/indexer/token-verifier configs).
  • Add an evm module that registers EVM adapter implementations for the new deployment registries.
  • Update build/devenv to consume the CCV deployment package (with a TOML-based shim to interop with legacy CCIP topology types where needed).

Reviewed changes

Copilot reviewed 42 out of 44 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
evm/verifier_config.go EVM adapter resolving verifier-related contract addresses from datastore.
evm/token_verifier_config.go EVM adapter resolving token-verifier-related addresses from datastore.
evm/register.go EVM init self-registration (chain type → family, address normalization, adapter registrations).
evm/indexer_config.go EVM adapter resolving verifier resolver addresses for indexer config generation.
evm/go.mod New nested Go module for EVM-specific deployment adapters.
evm/executor_config.go EVM adapter building executor chain configuration from datastore.
evm/aggregator_config.go EVM adapter scanning deployed committee state + resolving verifier address for aggregator config generation.
deployment/topology.go New topology model + TOML load/write + validation helpers.
deployment/token_verifier.go Token verifier generated config schema (JSON).
deployment/shared/types.go Shared types for jobs/NOPs/scopes + job metadata helpers.
deployment/shared/nodes.go JD node lookup utilities and guarded node fetching.
deployment/shared/jd_client.go JD client interface abstraction used by operations.
deployment/shared/chain_validation.go Helpers to validate NOP chain support and format user-facing errors.
deployment/shared/chain_type_registry.go Registry for JD chain-type → chain-selectors family + address normalizers.
deployment/sequences/manage_job_proposals.go Sequence to propose changed jobs and optionally revoke/cleanup orphaned jobs.
deployment/operations/sync_job_proposals/sync_job_proposals.go Operation to sync proposal statuses/specs from JD and detect drift/orphans.
deployment/operations/revoke_jobs/revoke_jobs.go Operation to revoke jobs via JD with node-ownership validation.
deployment/operations/propose_jobs/propose_jobs.go Operation to propose jobs via JD and return proposal metadata.
deployment/operations/fetch_signing_keys/fetch_signing_keys.go Operation to batch fetch OCR signing addresses from JD chain configs.
deployment/operations/fetch_node_chain_support/fetch_node_chain_support.go Operation to fetch supported chain selectors per NOP from JD chain configs.
deployment/indexer.go Indexer generated config schema (JSON).
deployment/go.mod New nested Go module for deployment tooling and dependencies.
deployment/env_metadata_util.go Persist/load CCV offchain configs + NOP jobs into datastore env metadata.
deployment/changesets/sync_job_proposals.go Changeset wrapper around SyncJobProposals operation.
deployment/changesets/generate_token_verifier_config.go Changeset to generate + store token verifier offchain config from onchain state.
deployment/changesets/generate_indexer_config.go Changeset to generate + store indexer config by collecting resolver addresses.
deployment/changesets/generate_aggregator_config.go Changeset to generate + store aggregator committee config from onchain state.
deployment/changesets/apply_verifier_config.go Changeset to build verifier job specs, propose via JD, and manage revocations/cleanup.
deployment/changesets/apply_executor_config.go Changeset to build executor job specs, propose via JD, and manage revocations/cleanup.
deployment/aggregator.go Aggregator generated config schema (JSON).
deployment/adapters/verifier_config.go Verifier adapter interface + registry keyed by chain family.
deployment/adapters/token_verifier_config.go Token-verifier adapter interface + registry keyed by chain family.
deployment/adapters/indexer_config.go Indexer adapter interface + registry + missing-address error type.
deployment/adapters/executor_config.go Executor adapter interface + registry + helper to collect deployed chains.
deployment/adapters/aggregator_config.go Aggregator adapter interface + registry for committee discovery and resolver lookup.
build/devenv/topology_compat.go TOML encode/decode shim to convert CCV topology → legacy CCIP topology types.
build/devenv/offchainloader/loader.go Switch offchain config loading to CCV deployment metadata types.
build/devenv/jobs/jd.go Switch devenv job proposal syncing/verification to CCV changesets + shared types.
build/devenv/implcommon.go Update devenv chain deploy/configure helpers to accept CCV topology (convert when calling CCIP code).
build/devenv/go.mod Add local replaces + requires for new deployment and evm modules.
build/devenv/expand_ha_test.go Update tests to use CCV topology types instead of legacy CCIP offchain types.
build/devenv/environment.go Wire devenv environment generation to CCV changesets/adapters and import EVM adapters for registration.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread deployment/shared/types.go
Comment thread deployment/operations/propose_jobs/propose_jobs.go
Comment thread deployment/topology.go
Comment on lines +206 to +208
if err := c.NOPTopology.Validate(); err != nil {
return fmt.Errorf("nop_topology validation failed: %w", err)
}
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EnvironmentTopology.Validate dereferences c.NOPTopology without checking for nil. If the topology file omits nop_topology (or it fails to unmarshal), this will panic instead of returning a validation error. Add an explicit nil check for c.NOPTopology (and similarly handle a nil receiver in (*NOPTopology).Validate) and return a descriptive error like nop_topology is required.

Copilot uses AI. Check for mistakes.
carte7000
carte7000 previously approved these changes Apr 17, 2026
Copy link
Copy Markdown
Collaborator

@makramkd makramkd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pros: chain-agnostic interfaces, following existing patterns. Cons: config struct duplication, EnvironmentTopology seems committee-verifier specific, I feel like it either needs a better home or there needs to be some synergy b/w lane definitions, chain support, and committee verifier configurations, as all have been referred to as "topology" at some point in time and confusion is nigh upon us.

Comment on lines +35 to +38
type AggregatorConfigRegistry struct {
mu sync.Mutex
adapters map[string]AggregatorConfigAdapter
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A developer ergonomics question: have we thought about potentially combining the registries into one, that ends up registering a struct of all these different interface types, in order to have a single entrypoint?

type Adapters struct {
    AggregatorConfigAdapter AggregatorConfigAdapter
    ExecutorConfigAdapter ExecutorConfigAdapter
    // the rest of them ... 
}

type AdapterRegistry struct {
    mu sync.Mutex
    adapters map[string]Adapters
}

func (r *AdapterRegistry) Register(family string, adapters Adapters) {
    // register func same as below.
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I remember us talking about this. We can switch these to a single register to start the pattern. This was mostly a lift and shift from what already existed

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🏋️

Comment thread deployment/topology.go
IndexerAddress []string `toml:"indexer_address"`
PyroscopeURL string `toml:"pyroscope_url"`
Monitoring MonitoringConfig `toml:"monitoring"`
NOPTopology *NOPTopology `toml:"nop_topology"`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This being a pointer suggests it could be nil (and we'd have to do nil checks in a lot of places). Is this the case or is it actually required?

Comment thread deployment/topology.go
Comment on lines +28 to +31
// NOPTopology defines the node operator structure and committee membership.
type NOPTopology struct {
NOPs []NOPConfig `toml:"nops"`
Committees map[string]CommitteeConfig `toml:"committees"`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This NOPTopology type seems weird to me because its committee-verifier specific is it not? Or is the entire EnvironmentTopology structure committee-verifier specific?

Comment thread deployment/topology.go
Comment on lines +123 to +129
IndexerQueryLimit uint64 `toml:"indexer_query_limit"`
BackoffDuration time.Duration `toml:"backoff_duration"`
LookbackWindow time.Duration `toml:"lookback_window"`
ReaderCacheExpiry time.Duration `toml:"reader_cache_expiry"`
MaxRetryDuration time.Duration `toml:"max_retry_duration"`
WorkerCount int `toml:"worker_count"`
NtpServer string `toml:"ntp_server"`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the previously duplicated executor configs? Or were those somewhere else?

Comment thread deployment/shared/types.go Outdated
Comment on lines +93 to +102
type BeholderInput struct {
InsecureConnection bool
CACertFile string
OtelExporterGRPCEndpoint string
OtelExporterHTTPEndpoint string
LogStreamingEnabled bool
MetricReaderInterval int64
TraceSampleRatio float64
TraceBatchTimeout int64
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be duplicated in multiple places, can we import it from somewhere where its canonically defined?

Comment thread deployment/aggregator.go
Comment on lines +3 to +20
type SourceSelector = string

type DestinationSelector = string

type Signer struct {
Address string `json:"address"`
}

type QuorumConfig struct {
SourceVerifierAddress string `json:"sourceVerifierAddress"`
Signers []Signer `json:"signers"`
Threshold uint8 `json:"threshold"`
}

type Committee struct {
QuorumConfigs map[SourceSelector]*QuorumConfig `json:"quorumConfigs"`
DestinationVerifiers map[DestinationSelector]string `json:"destinationVerifiers"`
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated configs?

Comment thread deployment/indexer.go
Comment on lines +3 to +10
type IndexerVerifierConfig struct {
Name string `json:"name"`
IssuerAddresses []string `json:"issuerAddresses"`
}

type IndexerGeneratedConfig struct {
Verifiers []IndexerVerifierConfig `json:"verifiers"`
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto here, duplicated? Whats the plan in a follow up?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to clean this up in general.

Comment on lines +5 to +11
type TokenVerifierGeneratedConfig struct {
PyroscopeURL string `json:"pyroscope_url"`
OnRampAddresses map[string]string `json:"on_ramp_addresses"`
RMNRemoteAddresses map[string]string `json:"rmn_remote_addresses"`
TokenVerifiers []TokenVerifierEntry `json:"token_verifiers"`
Monitoring TokenVerifierMonitoringConfig `json:"monitoring"`
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto here, duplicated

@github-actions
Copy link
Copy Markdown

Code coverage report:

Package main tt/offchain diff
github.com/smartcontractkit/chainlink-ccv/aggregator 48.46% 48.46% +0.00%
github.com/smartcontractkit/chainlink-ccv/bootstrap 42.60% 42.60% +0.00%
github.com/smartcontractkit/chainlink-ccv/cli 65.13% 65.13% +0.00%
github.com/smartcontractkit/chainlink-ccv/cmd 0.00% 0.00% +0.00%
github.com/smartcontractkit/chainlink-ccv/common 51.13% 50.74% -0.39%
github.com/smartcontractkit/chainlink-ccv/executor 45.74% 45.74% +0.00%
github.com/smartcontractkit/chainlink-ccv/indexer 37.52% 37.52% +0.00%
github.com/smartcontractkit/chainlink-ccv/integration 47.68% 47.68% +0.00%
github.com/smartcontractkit/chainlink-ccv/pkg 100.00% 100.00% +0.00%
github.com/smartcontractkit/chainlink-ccv/pricer 0.00% 0.00% +0.00%
github.com/smartcontractkit/chainlink-ccv/protocol 65.19% 65.19% +0.00%
github.com/smartcontractkit/chainlink-ccv/verifier 32.55% 32.56% +0.01%

@tt-cll tt-cll enabled auto-merge April 21, 2026 13:28
@harry-secure harry-secure disabled auto-merge April 22, 2026 02:00
@harry-secure harry-secure enabled auto-merge April 22, 2026 02:01
@harry-secure harry-secure disabled auto-merge April 22, 2026 02:06
@harry-secure harry-secure merged commit 8e0ee62 into main Apr 22, 2026
33 of 36 checks passed
@harry-secure harry-secure deleted the tt/offchain branch April 22, 2026 02:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants