Skip to content

Conversation

@makramkd
Copy link
Collaborator

@makramkd makramkd commented Jan 23, 2026

Summary

This PR refactors the SourceReader creation logic to be chain-agnostic using a factory pattern, enabling support for non-EVM chains like Canton.

Changes

  • Move BlockchainInfo out of protocol and into integration/pkg/blockchain
    • Reasoning: this isn't really a protocol level structure, its more about over specifying which chains the protocol operates on.
  • Accessor interface: Introduced Accessor interface in pkg/chainaccess. The idea behind this is to serve as a one-stop shop for all the blockchain-specific reader(s) that we have defined across the codebase. For now it only creates the chainaccess.SourceReader object, but should be easily extensible in the future to support new types, like executor.DestinationReader.
  • Accessor Factory Pattern: Introduced AccessorFactory interface and Registry types to decouple accessor instantiation from the main application logic.
  • EVM Factory: Moved EVM-specific accessor creation into integration/pkg/accessors/evm.
  • Canton Factory: Added Canton-specific accessor creation into integration/pkg/accessors/canton.
  • Configuration Updates: Updated the verifier Config struct to include CantonConfigs, allowing Canton-specific settings (Party ID, Template ID) to be loaded from TOML.

Next Steps

  • Switch NewVerificationCoordinator to take map[protocol.ChainSelector]chainaccess.SourceReader instead of map[protocol.ChainSelector]legacyevm.Chain, assuming this approach will also be used in the Chainlink node to construct the source readers.

Comment on lines 117 to 118
reg.Register(chainsel.FamilyEVM, sourcereader.NewEVMFactory(lggr, helper, config.OnRampAddresses, config.RMNRemoteAddresses))
reg.Register(chainsel.FamilyCanton, canton.NewFactory(lggr, helper, config.CantonConfigs))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice, this becomes the only place where non-evms hook their implementation into the service.

It could be a little better with a driver pattern where the config/selector are one big JSON string.

That would let you skip calling reg.Register, but you'd have to pass the config in like reg.GetSourceReader(ctx, srConfig[selector])

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I debated internally the driver pattern vs. this explicit registration but I found the explicit to be better due to the dep injection. In general I think I'm preferring an explicit vs. implicit approach, the big JSON string reminds me too much of ChainReader 😛

Copy link
Collaborator

Choose a reason for hiding this comment

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

The benefit is when you need to setup the registry for tests. With this approach you'll need this block of code in several places. I think you still have the same properties regarding dep injection, it's also still explicit because you still need _ integrations/canton to trigger the driver to register itself.

Hopefully accessor configs don't become a full on meta programming exercise, but I'm sort of imagining a directory full of config files. From there tests / apps can select the right directory and initialize their accessors dynamically (or explicitly if they want to define the config inline).

reader, err := reg.GetSourceReader(ctx, selector)
if err != nil {
lggr.Errorw("Failed to create EVM source reader", "selector", selector, "error", err)
lggr.Errorw("Failed to create source reader", "chainSelector", selector, "error", err)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
lggr.Errorw("Failed to create source reader", "chainSelector", selector, "error", err)
lggr.Errorw("Failed to create source reader", "chainSelector", selector, "error", err)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I actually added these emojis, found it easier to follow along in the logs, but can remove them if thats preferred / consistency.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I wonder if emoji's are going to be the new "I think you forgot to remove a printf"

Copy link
Contributor

Choose a reason for hiding this comment

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

I actually added these emojis, found it easier to follow along in the logs, but can remove them if thats preferred / consistency.

My personal preferences is that I like having them as they make debugging much easier. One thing that was mentioned before is that not all NOPs allow emojis so it'll show as unicode which is even worse. Probably we can ask NOPs to allow it though.

@makramkd makramkd changed the title integration: source reader instantiation integration: source reader instantiation via accessors Jan 23, 2026
@makramkd makramkd marked this pull request as ready for review January 23, 2026 18:46
@makramkd makramkd requested review from a team and skudasov as code owners January 23, 2026 18:46

cmd.StartPyroscope(lggr, config.PyroscopeURL, "verifier")
blockchainHelper, chainClients := cmd.LoadBlockchainInfo(ctx, lggr, blockchainInfos)
blockchainHelper := cmd.LoadBlockchainInfo(ctx, lggr, blockchainInfos)
Copy link
Contributor

Choose a reason for hiding this comment

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

I know I named the original struct `BlockChainHelpere but I don't like that name 😂

func RegisterEVM(ctx context.Context, registry *accessors.Registry, lggr logger.Logger, helper *blockchain.Helper, onRampAddresses, rmnRemoteAddresses map[string]string) {
// Create the chain clients then the head trackers
chainClients := make(map[protocol.ChainSelector]client.Client)
for _, selector := range helper.GetAllChainSelectors() {
Copy link
Contributor

Choose a reason for hiding this comment

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

shouldn't' this check for EVM family selectors only?

return nil, fmt.Errorf("RMN Remote address is not set for chain %d", chainSelector)
}

// Create chain client
Copy link
Contributor

Choose a reason for hiding this comment

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

wrong comment?

return nil, fmt.Errorf("chain client is not set for chain %d", chainSelector)
}

// Create head tracker wrapper
Copy link
Contributor

Choose a reason for hiding this comment

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

wrong comment?

mateusz-sekara
mateusz-sekara previously approved these changes Jan 26, 2026
@github-actions
Copy link

Code coverage report:

Package main mk/NONEVM-3492 diff
github.com/smartcontractkit/chainlink-ccv/aggregator 48.39% 48.36% -0.03%
github.com/smartcontractkit/chainlink-ccv/cmd 0.00% 0.00% +0.00%
github.com/smartcontractkit/chainlink-ccv/committee 0.00% 100.00% +100.00%
github.com/smartcontractkit/chainlink-ccv/common 0.00% 0.00% +0.00%
github.com/smartcontractkit/chainlink-ccv/executor 0.00% 50.48% +50.48%
github.com/smartcontractkit/chainlink-ccv/indexer 0.00% 38.48% +38.48%
github.com/smartcontractkit/chainlink-ccv/integration 0.00% 35.71% +35.71%
github.com/smartcontractkit/chainlink-ccv/pkg 0.00% 100.00% +100.00%
github.com/smartcontractkit/chainlink-ccv/pricer 0.00% 39.76% +39.76%
github.com/smartcontractkit/chainlink-ccv/protocol 0.00% 63.68% +63.68%
github.com/smartcontractkit/chainlink-ccv/verifier 0.00% 33.23% +33.23%

WARNING: go tool cover failed for coverage_target.out
cover: open /home/runner/work/chainlink-ccv/chainlink-ccv/cmd/verifier/head_tracker.go: no such file or directory
WARNING: go tool cover failed for coverage.out
cover: open /home/runner/work/chainlink-ccv/chainlink-ccv/verifier/pending_writing_tracker.go: no such file or directory

@makramkd makramkd added this pull request to the merge queue Jan 26, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jan 26, 2026
@makramkd makramkd added this pull request to the merge queue Jan 26, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jan 26, 2026
@makramkd makramkd added this pull request to the merge queue Jan 26, 2026
Merged via the queue into main with commit 2dc13ff Jan 26, 2026
19 checks passed
@makramkd makramkd deleted the mk/NONEVM-3492 branch January 26, 2026 12:49
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.

4 participants