Skip to content
Open
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
9 changes: 9 additions & 0 deletions core/config/capabilities_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type CapabilitiesWorkflowRegistry interface {
RelayID() types.RelayID
SyncStrategy() string
WorkflowStorage() WorkflowStorage
AlternativeSources() []AlternativeWorkflowSource
}

type WorkflowStorage interface {
Expand All @@ -41,6 +42,14 @@ type WorkflowStorage interface {
TLSEnabled() bool
}

// AlternativeWorkflowSource represents a single alternative workflow metadata source
// that can be configured to load workflows from sources other than the on-chain registry.
type AlternativeWorkflowSource interface {
GetURL() string
GetTLSEnabled() bool
GetName() string
}

type GatewayConnector interface {
ChainIDForNodeKey() string
NodeAddress() string
Expand Down
9 changes: 9 additions & 0 deletions core/config/docs/core.toml
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,15 @@ TLSEnabled = true # Default
# ArtifactStorageHost is the host name that, when present within the workflow metadata binary or config URL, designates that a signed URL should be retrieved from the workflow storage service.
ArtifactStorageHost = 'artifact.cre.chain.link' # Example

[[Capabilities.WorkflowRegistry.AlternativeSources]]
Copy link
Contributor

Choose a reason for hiding this comment

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

Is Additional a better name here? (Alternative to me implies "replacement of", whereas we want to read from both)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hmm. we have to keep TOML backwards compatible, so it will take a few node revisions to deprecate the old TOML config section in favor of a more flexible section name like [[Capabilities.WorkflowRegistry.Source]] - i wanted to handle any such migration later on once we see usage.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm with Cedric on this. How about "Offchain Sources"?

# URL is the GRPC endpoint for the alternative workflow metadata source.
# This allows workflows to be loaded from sources other than the on-chain registry contract.
URL = 'localhost:50051' # Example
# TLSEnabled enables TLS for the GRPC connection. Defaults to true.
TLSEnabled = true # Default
# Name is a human-readable identifier for logging purposes.
Name = 'my-workflow-source' # Example

[Workflows]
[Workflows.Limits]
# Global is the maximum number of workflows that can be registered globally.
Expand Down
105 changes: 96 additions & 9 deletions core/config/toml/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2197,16 +2197,60 @@ func (s *WorkflowStorage) ValidateConfig() error {
return nil
}

// AlternativeWorkflowSource represents a single alternative workflow metadata source
// configured via TOML. This allows workflows to be loaded from sources other than
// the on-chain registry contract (e.g., a GRPC service).
type AlternativeWorkflowSource struct {
URL *string `toml:"URL"`
TLSEnabled *bool `toml:"TLSEnabled"`
Name *string `toml:"Name"` // Human-readable name for logging
}

func (a *AlternativeWorkflowSource) setFrom(f *AlternativeWorkflowSource) {
if f.URL != nil {
a.URL = f.URL
}
if f.TLSEnabled != nil {
a.TLSEnabled = f.TLSEnabled
}
if f.Name != nil {
a.Name = f.Name
}
}

// GetURL implements config.AlternativeWorkflowSource.
func (a AlternativeWorkflowSource) GetURL() string {
if a.URL == nil {
return ""
}
return *a.URL
}

func (a AlternativeWorkflowSource) GetTLSEnabled() bool {
if a.TLSEnabled == nil {
return true // Default to enabled
}
return *a.TLSEnabled
}

func (a AlternativeWorkflowSource) GetName() string {
if a.Name == nil {
return "GRPCWorkflowSource"
}
return *a.Name
}

type WorkflowRegistry struct {
Address *string
NetworkID *string
ChainID *string
ContractVersion *string
MaxBinarySize *utils.FileSize
MaxEncryptedSecretsSize *utils.FileSize
MaxConfigSize *utils.FileSize
SyncStrategy *string
WorkflowStorage WorkflowStorage
Address *string
NetworkID *string
ChainID *string
ContractVersion *string
MaxBinarySize *utils.FileSize
MaxEncryptedSecretsSize *utils.FileSize
MaxConfigSize *utils.FileSize
SyncStrategy *string
WorkflowStorage WorkflowStorage
AlternativeSourcesConfig []AlternativeWorkflowSource `toml:"AlternativeSources"`
Copy link
Contributor

Choose a reason for hiding this comment

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

Ideally we would deprecate the old fields (Address, NetworkID, ContractVersion, ChainID)
And introduce a []SourcesConfig that supports both contract + grpc sources
Then in setFrom you can read from the deprecated fields and add a contract source to the sources

Everywhere else in the application uses sources going forward

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will schedule for a follow up ticket, good idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

It will be hard to keep all sources together because config format is very different. How about a split into OnchainSources and OffchainSources? Potentially add XYZSources in the future.

}

func (r *WorkflowRegistry) setFrom(f *WorkflowRegistry) {
Expand Down Expand Up @@ -2243,6 +2287,49 @@ func (r *WorkflowRegistry) setFrom(f *WorkflowRegistry) {
}

r.WorkflowStorage.setFrom(&f.WorkflowStorage)

if len(f.AlternativeSourcesConfig) > 0 {
r.AlternativeSourcesConfig = make([]AlternativeWorkflowSource, len(f.AlternativeSourcesConfig))
for i := range f.AlternativeSourcesConfig {
r.AlternativeSourcesConfig[i].setFrom(&f.AlternativeSourcesConfig[i])
}
}
}

// MaxAlternativeSources is the maximum number of alternative workflow sources
const MaxAlternativeSources = 5

func (r *WorkflowRegistry) ValidateConfig() error {
if err := r.WorkflowStorage.ValidateConfig(); err != nil {
return err
}

if len(r.AlternativeSourcesConfig) > MaxAlternativeSources {
return configutils.ErrInvalid{
Name: "AlternativeSources",
Value: len(r.AlternativeSourcesConfig),
Msg: fmt.Sprintf("maximum %d alternative sources supported", MaxAlternativeSources),
}
}

// Validate each source has a URL
for i, src := range r.AlternativeSourcesConfig {
if src.URL == nil || *src.URL == "" {
return configutils.ErrMissing{Name: fmt.Sprintf("AlternativeSources[%d].URL", i)}
}
}

return nil
}

// AlternativeSources returns the list of alternative workflow sources.
// Implements config.CapabilitiesWorkflowRegistry.
func (r WorkflowRegistry) AlternativeSources() []config.AlternativeWorkflowSource {
result := make([]config.AlternativeWorkflowSource, len(r.AlternativeSourcesConfig))
for i := range r.AlternativeSourcesConfig {
result[i] = r.AlternativeSourcesConfig[i]
}
return result
}

type Dispatcher struct {
Expand Down
4 changes: 4 additions & 0 deletions core/platform/monitoring.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ const (
EngineVersion = "engineVersion"
CapabilitiesRegistryVersion = "capabilitiesRegistryVersion"
DonVersion = "donVersion"

// WorkflowSource identifies where the workflow was deployed from
// e.g., "contract", "grpc:my-source", "file"
KeyWorkflowSource = "workflowSource"
)

func LabelKeysSorted() iter.Seq[string] {
Expand Down
Loading
Loading