diff --git a/build/devenv/common/common.go b/build/devenv/common/common.go index 273a41faa..8cc123dee 100644 --- a/build/devenv/common/common.go +++ b/build/devenv/common/common.go @@ -34,6 +34,7 @@ const ( CustomExecutorQualifier = "custom" + CCTPVerifierResolverQualifier = "CCTPVerifierResolver" CCTPPrimaryReceiverQualifier = "cctp-primary" CCTPSecondaryReceiverQualifier = "cctp-secondary" diff --git a/build/devenv/components/tokenverifier/component.go b/build/devenv/components/tokenverifier/component.go index 7ea299377..69b17a301 100644 --- a/build/devenv/components/tokenverifier/component.go +++ b/build/devenv/components/tokenverifier/component.go @@ -3,7 +3,6 @@ package tokenverifier import ( "context" "fmt" - "strconv" chainsel "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink-ccv/build/devenv/chainreg" @@ -14,7 +13,6 @@ import ( "github.com/smartcontractkit/chainlink-ccv/build/devenv/services" ccvdeployment "github.com/smartcontractkit/chainlink-ccv/deployment" ccvchangesets "github.com/smartcontractkit/chainlink-ccv/deployment/changesets" - "github.com/smartcontractkit/chainlink-ccv/verifier/pkg/token" "github.com/smartcontractkit/chainlink-deployments-framework/deployment" "github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain" ) @@ -88,6 +86,7 @@ func (c *component) RunPhase4( } familyLombardQualifier := make(map[string]string, len(inputs)) + familyCCTPQualifier := make(map[string]string, len(inputs)) for _, in := range inputs { if in == nil { continue @@ -101,6 +100,12 @@ func (c *component) RunPhase4( q = devenvcommon.LombardVerifierResolverQualifier } familyLombardQualifier[fam] = q + + q = in.CCTPQualifier + if q == "" { + q = devenvcommon.CCTPVerifierResolverQualifier + } + familyCCTPQualifier[fam] = q } localEnv := *e @@ -116,12 +121,13 @@ func (c *component) RunPhase4( if family == "" { family = chainsel.FamilyEVM } - familySelectors := selectorsForFamily(selectors, family) + familySelectors := devenvcommon.SelectorsForFamily(selectors, family) if len(familySelectors) == 0 { return nil, nil, fmt.Errorf("tokenverifier: no chain selectors found for family %q (instance %q)", family, tvIn.ContainerName) } lombardQualifier := familyLombardQualifier[family] + cctpQualifier := familyCCTPQualifier[family] cs := ccvchangesets.GenerateTokenVerifierConfig() output, csErr := cs.Apply(localEnv, ccvchangesets.GenerateTokenVerifierConfigInput{ @@ -134,6 +140,7 @@ func (c *component) RunPhase4( }, CCTP: ccvchangesets.CCTPConfigInput{ VerifierID: "CCTPVerifier", + Qualifier: cctpQualifier, AttestationAPI: fakeOut.InternalHTTPURL + "/cctp", }, }) @@ -154,20 +161,17 @@ func (c *component) RunPhase4( remoteByFamily[selFamily] = append(remoteByFamily[selFamily], sel) } for remoteFamily, remoteSelectors := range remoteByFamily { - remoteLombardQualifier := familyLombardQualifier[remoteFamily] - if remoteLombardQualifier == "" { - remoteLombardQualifier = devenvcommon.LombardVerifierResolverQualifier - } remoteOutput, remoteErr := ccvchangesets.GenerateTokenVerifierConfig().Apply(localEnv, ccvchangesets.GenerateTokenVerifierConfigInput{ ServiceIdentifier: tvIn.ContainerName, ChainSelectors: remoteSelectors, Lombard: ccvchangesets.LombardConfigInput{ VerifierID: "LombardVerifier", - Qualifier: remoteLombardQualifier, + Qualifier: familyLombardQualifier[remoteFamily], AttestationAPI: fakeOut.InternalHTTPURL + "/lombard", }, CCTP: ccvchangesets.CCTPConfigInput{ VerifierID: "CCTPVerifier", + Qualifier: familyCCTPQualifier[remoteFamily], AttestationAPI: fakeOut.InternalHTTPURL + "/cctp", }, }) @@ -182,7 +186,7 @@ func (c *component) RunPhase4( return nil, nil, fmt.Errorf("tokenverifier: getting token verifier config: %w", cfgErr) } - tokenVerifierCfg.TokenVerifiers = dropUnreachableVerifiers(tokenVerifierCfg.TokenVerifiers, familySelectors) + tokenVerifierCfg.TokenVerifiers = devenvcommon.DropUnreachableTokenVerifiers(tokenVerifierCfg.TokenVerifiers, familySelectors) inputs[i].GeneratedConfig = tokenVerifierCfg } @@ -208,54 +212,6 @@ func (c *component) RunPhase4( return map[string]any{Key: inputs}, nil, nil } -// dropUnreachableVerifiers removes any verifier-type entry (CCTP or Lombard) whose -// resolved verifier-resolver addresses have no chain in common with localSelectors: -// an instance can never coordinate a verifier type it has no locally-reachable chains for. -func dropUnreachableVerifiers(verifiers []token.VerifierConfig, localSelectors []uint64) []token.VerifierConfig { - local := make(map[string]struct{}, len(localSelectors)) - for _, sel := range localSelectors { - local[strconv.FormatUint(sel, 10)] = struct{}{} - } - - reachable := make([]token.VerifierConfig, 0, len(verifiers)) - for _, vc := range verifiers { - var resolvers map[string]any - switch { - case vc.CCTPConfig != nil: - resolvers = vc.CCTPConfig.VerifierResolvers - case vc.LombardConfig != nil: - resolvers = vc.LombardConfig.VerifierResolvers - } - hasLocalChain := false - for chainSelectorStr := range resolvers { - if _, ok := local[chainSelectorStr]; ok { - hasLocalChain = true - break - } - } - if hasLocalChain { - reachable = append(reachable, vc) - } - } - return reachable -} - -// selectorsForFamily filters selectors down to those belonging to family, by cross-referencing -// each selector's registered chain details. Order is not guaranteed to match the input. -func selectorsForFamily(selectors []uint64, family string) []uint64 { - var filtered []uint64 - for _, sel := range selectors { - selFamily, err := chainsel.GetSelectorFamily(sel) - if err != nil { - continue - } - if selFamily == family { - filtered = append(filtered, sel) - } - } - return filtered -} - func decode(raw any) ([]*services.TokenVerifierInput, error) { inputs, err := devenvruntime.DecodeConfig[[]*services.TokenVerifierInput](raw, Key) if err != nil { diff --git a/build/devenv/environment_monolith.go b/build/devenv/environment_monolith.go index 860dd27c8..81278f48f 100644 --- a/build/devenv/environment_monolith.go +++ b/build/devenv/environment_monolith.go @@ -784,11 +784,43 @@ func NewEnvironment() (in *Cfg, err error) { /////////////////////////////////// progress.Stage(ctx, stageLaunchTokenVerifiers) + familyLombardQualifier := make(map[string]string, len(in.TokenVerifier)) + familyCCTPQualifier := make(map[string]string, len(in.TokenVerifier)) + for _, tv := range in.TokenVerifier { + if in == nil { + continue + } + fam := tv.ChainFamily + if fam == "" { + fam = chainsel.FamilyEVM + } + q := tv.LombardQualifier + if q == "" { + q = devenvcommon.LombardVerifierResolverQualifier + } + familyLombardQualifier[fam] = q + + q = tv.CCTPQualifier + if q == "" { + q = devenvcommon.CCTPVerifierResolverQualifier + } + familyCCTPQualifier[fam] = q + } + + localEnv := *e // Generate token verifier configs using changeset (on-chain state as source of truth) for i, tokenVerifierInput := range in.TokenVerifier { if tokenVerifierInput == nil { continue } + family := tokenVerifierInput.ChainFamily + if family == "" { + family = chainsel.FamilyEVM + } + localSelectors := devenvcommon.SelectorsForFamily(selectors, family) + if len(localSelectors) == 0 { + return nil, fmt.Errorf("no chain selectors found for token verifier family %q (instance %q)", family, tokenVerifierInput.ContainerName) + } if fakeOut == nil { return nil, fmt.Errorf("fake data provider is required for token verifiers to provide attestation API endpoints, but it was not created successfully") @@ -796,22 +828,53 @@ func NewEnvironment() (in *Cfg, err error) { // Use changeset to generate token verifier config from on-chain state cs := ccvchangesets.GenerateTokenVerifierConfig() - output, err := cs.Apply(*e, ccvchangesets.GenerateTokenVerifierConfigInput{ + output, err := cs.Apply(localEnv, ccvchangesets.GenerateTokenVerifierConfigInput{ ServiceIdentifier: "TokenVerifier", - ChainSelectors: selectors, + ChainSelectors: localSelectors, Lombard: ccvchangesets.LombardConfigInput{ VerifierID: "LombardVerifier", - Qualifier: devenvcommon.LombardVerifierResolverQualifier, + Qualifier: familyLombardQualifier[family], AttestationAPI: fakeOut.InternalHTTPURL + "/lombard", }, CCTP: ccvchangesets.CCTPConfigInput{ VerifierID: "CCTPVerifier", + Qualifier: familyCCTPQualifier[family], AttestationAPI: fakeOut.InternalHTTPURL + "/cctp", }, }) if err != nil { return nil, fmt.Errorf("failed to generate token verifier config: %w", err) } + localEnv.DataStore = output.DataStore.Seal() + + remoteByFamily := make(map[string][]uint64) + for _, selector := range selectors { + selectorFamily, familyErr := chainsel.GetSelectorFamily(selector) + if familyErr != nil || selectorFamily == family { + continue + } + remoteByFamily[selectorFamily] = append(remoteByFamily[selectorFamily], selector) + } + for remoteFamily, remoteSelectors := range remoteByFamily { + remoteOutput, remoteErr := ccvchangesets.GenerateTokenVerifierConfig().Apply(localEnv, ccvchangesets.GenerateTokenVerifierConfigInput{ + ServiceIdentifier: "TokenVerifier", + ChainSelectors: remoteSelectors, + Lombard: ccvchangesets.LombardConfigInput{ + VerifierID: "LombardVerifier", + Qualifier: familyLombardQualifier[remoteFamily], + AttestationAPI: fakeOut.InternalHTTPURL + "/lombard", + }, + CCTP: ccvchangesets.CCTPConfigInput{ + VerifierID: "CCTPVerifier", + Qualifier: familyCCTPQualifier[remoteFamily], + AttestationAPI: fakeOut.InternalHTTPURL + "/cctp", + }, + }) + if remoteErr != nil { + return nil, fmt.Errorf("failed to generate cross-family token verifier config for %q (family %q): %w", tokenVerifierInput.ContainerName, remoteFamily, remoteErr) + } + localEnv.DataStore = remoteOutput.DataStore.Seal() + } // Get generated config from output datastore tokenVerifierCfg, err := ccvdeployment.GetTokenVerifierConfig( @@ -820,8 +883,9 @@ func NewEnvironment() (in *Cfg, err error) { if err != nil { return nil, fmt.Errorf("failed to get token verifier config from output: %w", err) } + tokenVerifierCfg.TokenVerifiers = devenvcommon.DropUnreachableTokenVerifiers(tokenVerifierCfg.TokenVerifiers, localSelectors) in.TokenVerifier[i].GeneratedConfig = tokenVerifierCfg - e.DataStore = output.DataStore.Seal() + e.DataStore = localEnv.DataStore } if fakeOut != nil { diff --git a/build/devenv/services/tokenVerifier.go b/build/devenv/services/tokenVerifier.go index 0e85aa742..3435bc512 100644 --- a/build/devenv/services/tokenVerifier.go +++ b/build/devenv/services/tokenVerifier.go @@ -61,6 +61,10 @@ type TokenVerifierInput struct { // generated config should resolve addresses for. LombardQualifier string `toml:"lombard_qualifier"` + // CCTPQualifier identifies which CCTP verifier/resolver deployment this instance's + // generated config should resolve addresses for. + CCTPQualifier string `toml:"cctp_qualifier"` + // GeneratedConfig stores the generated token verifier configuration from the changeset. GeneratedConfig *token.Config `toml:"-"`