From 8ebd9c2dccdbb671af9a024fb32d40ceae3cd43b Mon Sep 17 00:00:00 2001 From: De Clercq Wentzel <10665586+wentzeld@users.noreply.github.com> Date: Sat, 28 Feb 2026 10:50:57 -0800 Subject: [PATCH 1/3] feat: add --limits flag to cre workflow simulate --- cmd/root.go | 22 +++++++----- cmd/workflow/simulate/capabilities.go | 29 ++++++++++++--- cmd/workflow/simulate/simulate.go | 51 +++++++++++++++++++++++++-- cmd/workflow/workflow.go | 2 ++ 4 files changed, 88 insertions(+), 16 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 6cd5636c..b49eb6b9 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -399,9 +399,11 @@ func isLoadSettings(cmd *cobra.Command) bool { "cre completion zsh": {}, "cre help": {}, "cre update": {}, - "cre workflow": {}, - "cre workflow custom-build": {}, - "cre account": {}, + "cre workflow": {}, + "cre workflow custom-build": {}, + "cre workflow limits": {}, + "cre workflow limits export": {}, + "cre account": {}, "cre secrets": {}, "cre templates": {}, "cre templates list": {}, @@ -427,9 +429,11 @@ func isLoadCredentials(cmd *cobra.Command) bool { "cre help": {}, "cre generate-bindings": {}, "cre update": {}, - "cre workflow": {}, - "cre account": {}, - "cre secrets": {}, + "cre workflow": {}, + "cre workflow limits": {}, + "cre workflow limits export": {}, + "cre account": {}, + "cre secrets": {}, "cre templates": {}, "cre templates list": {}, "cre templates add": {}, @@ -496,8 +500,10 @@ func shouldShowSpinner(cmd *cobra.Command) bool { "cre login": {}, // Has its own interactive flow "cre logout": {}, "cre update": {}, - "cre workflow": {}, // Just shows help - "cre account": {}, // Just shows help + "cre workflow": {}, // Just shows help + "cre workflow limits": {}, // Just shows help + "cre workflow limits export": {}, // Static data, no project needed + "cre account": {}, // Just shows help "cre secrets": {}, // Just shows help "cre templates": {}, // Just shows help "cre templates list": {}, diff --git a/cmd/workflow/simulate/capabilities.go b/cmd/workflow/simulate/capabilities.go index 69f7273c..57cc2b5b 100644 --- a/cmd/workflow/simulate/capabilities.go +++ b/cmd/workflow/simulate/capabilities.go @@ -39,6 +39,7 @@ func NewManualTriggerCapabilities( registry *capabilities.Registry, cfg ManualTriggerCapabilitiesConfig, dryRunChainWrite bool, + limits *SimulationLimits, ) (*ManualTriggers, error) { // Cron manualCronTrigger := fakes.NewManualCronTriggerService(lggr) @@ -72,7 +73,13 @@ func NewManualTriggerCapabilities( dryRunChainWrite, ) - evmServer := evmserver.NewClientServer(evm) + // Wrap with limits enforcement if limits are enabled + var evmCap evmserver.ClientCapability = evm + if limits != nil { + evmCap = NewLimitedEVMChain(evm, limits) + } + + evmServer := evmserver.NewClientServer(evmCap) if err := registry.Add(ctx, evmServer); err != nil { return nil, err } @@ -129,7 +136,7 @@ func (m *ManualTriggers) Close() error { } // NewFakeCapabilities builds faked capabilities, then registers them with the capability registry. -func NewFakeActionCapabilities(ctx context.Context, lggr logger.Logger, registry *capabilities.Registry, secretsPath string) ([]services.Service, error) { +func NewFakeActionCapabilities(ctx context.Context, lggr logger.Logger, registry *capabilities.Registry, secretsPath string, limits *SimulationLimits) ([]services.Service, error) { caps := make([]services.Service, 0) // Consensus @@ -142,7 +149,11 @@ func NewFakeActionCapabilities(ctx context.Context, lggr logger.Logger, registry signers = append(signers, signer) } fakeConsensusNoDAG := fakes.NewFakeConsensusNoDAG(signers, lggr) - fakeConsensusServer := consensusserver.NewConsensusServer(fakeConsensusNoDAG) + var consensusCap consensusserver.ConsensusCapability = fakeConsensusNoDAG + if limits != nil { + consensusCap = NewLimitedConsensusNoDAG(fakeConsensusNoDAG, limits) + } + fakeConsensusServer := consensusserver.NewConsensusServer(consensusCap) if err := registry.Add(ctx, fakeConsensusServer); err != nil { return nil, err } @@ -150,7 +161,11 @@ func NewFakeActionCapabilities(ctx context.Context, lggr logger.Logger, registry // HTTP Action httpAction := fakes.NewDirectHTTPAction(lggr) - httpActionServer := httpserver.NewClientServer(httpAction) + var httpCap httpserver.ClientCapability = httpAction + if limits != nil { + httpCap = NewLimitedHTTPAction(httpAction, limits) + } + httpActionServer := httpserver.NewClientServer(httpCap) if err := registry.Add(ctx, httpActionServer); err != nil { return nil, err } @@ -158,7 +173,11 @@ func NewFakeActionCapabilities(ctx context.Context, lggr logger.Logger, registry // Conf HTTP Action confHTTPAction := fakes.NewDirectConfidentialHTTPAction(lggr, secretsPath) - confHTTPActionServer := confhttpserver.NewClientServer(confHTTPAction) + var confHTTPCap confhttpserver.ClientCapability = confHTTPAction + if limits != nil { + confHTTPCap = NewLimitedConfidentialHTTPAction(confHTTPAction, limits) + } + confHTTPActionServer := confhttpserver.NewClientServer(confHTTPCap) if err := registry.Add(ctx, confHTTPActionServer); err != nil { return nil, err } diff --git a/cmd/workflow/simulate/simulate.go b/cmd/workflow/simulate/simulate.go index 6e953dc2..f7f17e26 100644 --- a/cmd/workflow/simulate/simulate.go +++ b/cmd/workflow/simulate/simulate.go @@ -1,6 +1,8 @@ package simulate import ( + "bytes" + "compress/gzip" "context" "crypto/ecdsa" "encoding/json" @@ -61,6 +63,8 @@ type Inputs struct { EVMEventIndex int `validate:"-"` // Experimental chains support (for chains not in official chain-selectors) ExperimentalForwarders map[uint64]common.Address `validate:"-"` // forwarders keyed by chain ID + // Limits enforcement + LimitsPath string `validate:"-"` // "default" or path to custom limits JSON } func New(runtimeContext *runtime.Context) *cobra.Command { @@ -93,6 +97,7 @@ func New(runtimeContext *runtime.Context) *cobra.Command { simulateCmd.Flags().String("http-payload", "", "HTTP trigger payload as JSON string or path to JSON file (with or without @ prefix)") simulateCmd.Flags().String("evm-tx-hash", "", "EVM trigger transaction hash (0x...)") simulateCmd.Flags().Int("evm-event-index", -1, "EVM trigger log index (0-based)") + simulateCmd.Flags().String("limits", "default", "Production limits to enforce during simulation. Use 'default' for prod defaults, path to custom limits.json, or 'none' to disable") return simulateCmd } @@ -226,6 +231,7 @@ func (h *handler) ResolveInputs(v *viper.Viper, creSettings *settings.Settings) EVMTxHash: v.GetString("evm-tx-hash"), EVMEventIndex: v.GetInt("evm-event-index"), ExperimentalForwarders: experimentalForwarders, + LimitsPath: v.GetString("limits"), }, nil } @@ -285,6 +291,39 @@ func (h *handler) Execute(inputs Inputs) error { h.log.Debug().Msg("Workflow compiled") ui.Success("Workflow compiled") + // Resolve simulation limits + simLimits, err := ResolveLimits(inputs.LimitsPath) + if err != nil { + return fmt.Errorf("failed to resolve simulation limits: %w", err) + } + + // WASM binary size pre-flight check + if simLimits != nil { + binaryLimit := simLimits.WASMBinarySize() + if binaryLimit > 0 && len(wasmFileBinary) > binaryLimit { + return fmt.Errorf("WASM binary size %d bytes exceeds limit of %d bytes", len(wasmFileBinary), binaryLimit) + } + + compressedLimit := simLimits.WASMCompressedBinarySize() + if compressedLimit > 0 { + var buf bytes.Buffer + gz := gzip.NewWriter(&buf) + if _, err := gz.Write(wasmFileBinary); err != nil { + return fmt.Errorf("failed to compress WASM binary for size check: %w", err) + } + if err := gz.Close(); err != nil { + return fmt.Errorf("failed to finalize WASM compression: %w", err) + } + compressedSize := buf.Len() + if compressedSize > compressedLimit { + return fmt.Errorf("WASM compressed binary size %d bytes exceeds limit of %d bytes", compressedSize, compressedLimit) + } + } + + ui.Success("Simulation limits enabled") + ui.Dim(simLimits.LimitsSummary()) + } + // Read the config file var config []byte if inputs.ConfigPath != "" { @@ -315,7 +354,7 @@ func (h *handler) Execute(inputs Inputs) error { // if logger instance is set to DEBUG, that means verbosity flag is set by the user verbosity := h.log.GetLevel() == zerolog.DebugLevel - err = run(ctx, wasmFileBinary, config, secrets, inputs, verbosity) + err = run(ctx, wasmFileBinary, config, secrets, inputs, verbosity, simLimits) if err != nil { return err } @@ -349,6 +388,7 @@ func run( binary, config, secrets []byte, inputs Inputs, verbosity bool, + simLimits *SimulationLimits, ) error { logCfg := logger.Config{Level: getLevel(verbosity, zapcore.InfoLevel)} simLogger := NewSimulationLogger(verbosity) @@ -419,14 +459,14 @@ func run( triggerLggr := lggr.Named("TriggerCapabilities") var err error - triggerCaps, err = NewManualTriggerCapabilities(ctx, triggerLggr, registry, manualTriggerCapConfig, !inputs.Broadcast) + triggerCaps, err = NewManualTriggerCapabilities(ctx, triggerLggr, registry, manualTriggerCapConfig, !inputs.Broadcast, simLimits) if err != nil { ui.Error(fmt.Sprintf("Failed to create trigger capabilities: %v", err)) os.Exit(1) } computeLggr := lggr.Named("ActionsCapabilities") - computeCaps, err := NewFakeActionCapabilities(ctx, computeLggr, registry, inputs.SecretsPath) + computeCaps, err := NewFakeActionCapabilities(ctx, computeLggr, registry, inputs.SecretsPath, simLimits) if err != nil { ui.Error(fmt.Sprintf("Failed to create compute capabilities: %v", err)) os.Exit(1) @@ -578,6 +618,11 @@ func run( commonsettings.Bool(true), // Allow all chains in simulation map[string]bool{}, ) + // Apply simulation limits to engine-level settings when --limits is set + if simLimits != nil { + applyEngineLimits(cfg, simLimits) + // Re-apply allow-all chains since applyEngineLimits does not touch ChainAllowed + } }, }) diff --git a/cmd/workflow/workflow.go b/cmd/workflow/workflow.go index bc4298c2..3046fc71 100644 --- a/cmd/workflow/workflow.go +++ b/cmd/workflow/workflow.go @@ -7,6 +7,7 @@ import ( "github.com/smartcontractkit/cre-cli/cmd/workflow/convert" "github.com/smartcontractkit/cre-cli/cmd/workflow/delete" "github.com/smartcontractkit/cre-cli/cmd/workflow/deploy" + "github.com/smartcontractkit/cre-cli/cmd/workflow/limits" "github.com/smartcontractkit/cre-cli/cmd/workflow/pause" "github.com/smartcontractkit/cre-cli/cmd/workflow/simulate" "github.com/smartcontractkit/cre-cli/cmd/workflow/test" @@ -27,6 +28,7 @@ func New(runtimeContext *runtime.Context) *cobra.Command { workflowCmd.AddCommand(test.New(runtimeContext)) workflowCmd.AddCommand(deploy.New(runtimeContext)) workflowCmd.AddCommand(simulate.New(runtimeContext)) + workflowCmd.AddCommand(limits.New(runtimeContext)) return workflowCmd } From edcbc457af69730d46de12e6ba6170735ed20339 Mon Sep 17 00:00:00 2001 From: De Clercq Wentzel <10665586+wentzeld@users.noreply.github.com> Date: Sat, 28 Feb 2026 14:37:03 -0800 Subject: [PATCH 2/3] feat: add --limits flag to cre workflow simulate --- cmd/workflow/limits/export.go | 43 +++ cmd/workflow/simulate/limited_capabilities.go | 278 ++++++++++++++++++ cmd/workflow/simulate/limits.go | 177 +++++++++++ cmd/workflow/simulate/limits.json | 69 +++++ docs/cre_workflow.md | 1 + docs/cre_workflow_limits.md | 28 ++ docs/cre_workflow_limits_export.md | 38 +++ docs/cre_workflow_simulate.md | 1 + 8 files changed, 635 insertions(+) create mode 100644 cmd/workflow/limits/export.go create mode 100644 cmd/workflow/simulate/limited_capabilities.go create mode 100644 cmd/workflow/simulate/limits.go create mode 100644 cmd/workflow/simulate/limits.json create mode 100644 docs/cre_workflow_limits.md create mode 100644 docs/cre_workflow_limits_export.md diff --git a/cmd/workflow/limits/export.go b/cmd/workflow/limits/export.go new file mode 100644 index 00000000..ce0b6e1b --- /dev/null +++ b/cmd/workflow/limits/export.go @@ -0,0 +1,43 @@ +package limits + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/smartcontractkit/cre-cli/cmd/workflow/simulate" + "github.com/smartcontractkit/cre-cli/internal/runtime" +) + +func New(runtimeContext *runtime.Context) *cobra.Command { + limitsCmd := &cobra.Command{ + Use: "limits", + Short: "Manage simulation limits", + Long: `The limits command provides tools for managing workflow simulation limits.`, + } + + limitsCmd.AddCommand(newExportCmd()) + + return limitsCmd +} + +func newExportCmd() *cobra.Command { + return &cobra.Command{ + Use: "export", + Short: "Export default simulation limits as JSON", + Long: `Exports the default production simulation limits as JSON. + +The output can be redirected to a file and customized for use with +the --limits flag of the simulate command. + +Example: + cre workflow limits export > my-limits.json + cre workflow simulate ./my-workflow --limits ./my-limits.json`, + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + data := simulate.ExportDefaultLimitsJSON() + fmt.Println(string(data)) + return nil + }, + } +} diff --git a/cmd/workflow/simulate/limited_capabilities.go b/cmd/workflow/simulate/limited_capabilities.go new file mode 100644 index 00000000..4d9110fa --- /dev/null +++ b/cmd/workflow/simulate/limited_capabilities.go @@ -0,0 +1,278 @@ +package simulate + +import ( + "context" + "fmt" + "time" + + "google.golang.org/protobuf/proto" + + commonCap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + caperrors "github.com/smartcontractkit/chainlink-common/pkg/capabilities/errors" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/actions/confidentialhttp" + confhttpserver "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/actions/confidentialhttp/server" + customhttp "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/actions/http" + httpserver "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/actions/http/server" + evmcappb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/evm" + evmserver "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/evm/server" + consensusserver "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/consensus/server" + sdkpb "github.com/smartcontractkit/chainlink-protos/cre/go/sdk" + valuespb "github.com/smartcontractkit/chainlink-protos/cre/go/values/pb" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" +) + +// --- LimitedHTTPAction --- + +// LimitedHTTPAction wraps an httpserver.ClientCapability and enforces request/response +// size limits and connection timeout from SimulationLimits. +type LimitedHTTPAction struct { + inner httpserver.ClientCapability + limits *SimulationLimits +} + +var _ httpserver.ClientCapability = (*LimitedHTTPAction)(nil) + +func NewLimitedHTTPAction(inner httpserver.ClientCapability, limits *SimulationLimits) *LimitedHTTPAction { + return &LimitedHTTPAction{inner: inner, limits: limits} +} + +func (l *LimitedHTTPAction) SendRequest(ctx context.Context, metadata commonCap.RequestMetadata, input *customhttp.Request) (*commonCap.ResponseAndMetadata[*customhttp.Response], caperrors.Error) { + // Check request body size + reqLimit := l.limits.HTTPRequestSizeLimit() + if reqLimit > 0 && len(input.GetBody()) > reqLimit { + return nil, caperrors.NewPublicUserError( + fmt.Errorf("simulation limit exceeded: HTTP request body size %d bytes exceeds limit of %d bytes", len(input.GetBody()), reqLimit), + caperrors.ResourceExhausted, + ) + } + + // Enforce connection timeout + connTimeout := l.limits.Workflows.HTTPAction.ConnectionTimeout.DefaultValue + if connTimeout > 0 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, time.Duration(connTimeout)) + defer cancel() + } + + // Delegate to inner + resp, capErr := l.inner.SendRequest(ctx, metadata, input) + if capErr != nil { + return resp, capErr + } + + // Check response body size + respLimit := l.limits.HTTPResponseSizeLimit() + if resp != nil && resp.Response != nil && respLimit > 0 && len(resp.Response.GetBody()) > respLimit { + return nil, caperrors.NewPublicUserError( + fmt.Errorf("simulation limit exceeded: HTTP response body size %d bytes exceeds limit of %d bytes", len(resp.Response.GetBody()), respLimit), + caperrors.ResourceExhausted, + ) + } + + return resp, nil +} + +func (l *LimitedHTTPAction) Start(ctx context.Context) error { return l.inner.Start(ctx) } +func (l *LimitedHTTPAction) Close() error { return l.inner.Close() } +func (l *LimitedHTTPAction) HealthReport() map[string]error { return l.inner.HealthReport() } +func (l *LimitedHTTPAction) Name() string { return l.inner.Name() } +func (l *LimitedHTTPAction) Description() string { return l.inner.Description() } +func (l *LimitedHTTPAction) Ready() error { return l.inner.Ready() } +func (l *LimitedHTTPAction) Initialise(ctx context.Context, deps core.StandardCapabilitiesDependencies) error { + return l.inner.Initialise(ctx, deps) +} + +// --- LimitedConfidentialHTTPAction --- + +// LimitedConfidentialHTTPAction wraps a confhttpserver.ClientCapability and enforces +// request/response size limits and connection timeout from SimulationLimits. +type LimitedConfidentialHTTPAction struct { + inner confhttpserver.ClientCapability + limits *SimulationLimits +} + +var _ confhttpserver.ClientCapability = (*LimitedConfidentialHTTPAction)(nil) + +func NewLimitedConfidentialHTTPAction(inner confhttpserver.ClientCapability, limits *SimulationLimits) *LimitedConfidentialHTTPAction { + return &LimitedConfidentialHTTPAction{inner: inner, limits: limits} +} + +func (l *LimitedConfidentialHTTPAction) SendRequest(ctx context.Context, metadata commonCap.RequestMetadata, input *confidentialhttp.ConfidentialHTTPRequest) (*commonCap.ResponseAndMetadata[*confidentialhttp.HTTPResponse], caperrors.Error) { + // Check request size (body string or body bytes) + reqLimit := l.limits.ConfHTTPRequestSizeLimit() + if reqLimit > 0 && input.GetRequest() != nil { + reqSize := len(input.GetRequest().GetBodyString()) + len(input.GetRequest().GetBodyBytes()) + if reqSize > reqLimit { + return nil, caperrors.NewPublicUserError( + fmt.Errorf("simulation limit exceeded: confidential HTTP request body size %d bytes exceeds limit of %d bytes", reqSize, reqLimit), + caperrors.ResourceExhausted, + ) + } + } + + // Enforce connection timeout + connTimeout := l.limits.Workflows.ConfidentialHTTP.ConnectionTimeout.DefaultValue + if connTimeout > 0 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, time.Duration(connTimeout)) + defer cancel() + } + + // Delegate to inner + resp, capErr := l.inner.SendRequest(ctx, metadata, input) + if capErr != nil { + return resp, capErr + } + + // Check response body size + respLimit := l.limits.ConfHTTPResponseSizeLimit() + if resp != nil && resp.Response != nil && respLimit > 0 && len(resp.Response.GetBody()) > respLimit { + return nil, caperrors.NewPublicUserError( + fmt.Errorf("simulation limit exceeded: confidential HTTP response body size %d bytes exceeds limit of %d bytes", len(resp.Response.GetBody()), respLimit), + caperrors.ResourceExhausted, + ) + } + + return resp, nil +} + +func (l *LimitedConfidentialHTTPAction) Start(ctx context.Context) error { return l.inner.Start(ctx) } +func (l *LimitedConfidentialHTTPAction) Close() error { return l.inner.Close() } +func (l *LimitedConfidentialHTTPAction) HealthReport() map[string]error { return l.inner.HealthReport() } +func (l *LimitedConfidentialHTTPAction) Name() string { return l.inner.Name() } +func (l *LimitedConfidentialHTTPAction) Description() string { return l.inner.Description() } +func (l *LimitedConfidentialHTTPAction) Ready() error { return l.inner.Ready() } +func (l *LimitedConfidentialHTTPAction) Initialise(ctx context.Context, deps core.StandardCapabilitiesDependencies) error { + return l.inner.Initialise(ctx, deps) +} + +// --- LimitedConsensusNoDAG --- + +// LimitedConsensusNoDAG wraps a consensusserver.ConsensusCapability and enforces +// observation size limits from SimulationLimits. +type LimitedConsensusNoDAG struct { + inner consensusserver.ConsensusCapability + limits *SimulationLimits +} + +var _ consensusserver.ConsensusCapability = (*LimitedConsensusNoDAG)(nil) + +func NewLimitedConsensusNoDAG(inner consensusserver.ConsensusCapability, limits *SimulationLimits) *LimitedConsensusNoDAG { + return &LimitedConsensusNoDAG{inner: inner, limits: limits} +} + +func (l *LimitedConsensusNoDAG) Simple(ctx context.Context, metadata commonCap.RequestMetadata, input *sdkpb.SimpleConsensusInputs) (*commonCap.ResponseAndMetadata[*valuespb.Value], caperrors.Error) { + // Check observation size + obsLimit := l.limits.ConsensusObservationSizeLimit() + if obsLimit > 0 { + inputSize := proto.Size(input) + if inputSize > obsLimit { + return nil, caperrors.NewPublicUserError( + fmt.Errorf("simulation limit exceeded: consensus observation size %d bytes exceeds limit of %d bytes", inputSize, obsLimit), + caperrors.ResourceExhausted, + ) + } + } + + return l.inner.Simple(ctx, metadata, input) +} + +func (l *LimitedConsensusNoDAG) Report(ctx context.Context, metadata commonCap.RequestMetadata, input *sdkpb.ReportRequest) (*commonCap.ResponseAndMetadata[*sdkpb.ReportResponse], caperrors.Error) { + // Report size is engine-enforced, delegate as-is + return l.inner.Report(ctx, metadata, input) +} + +func (l *LimitedConsensusNoDAG) Start(ctx context.Context) error { return l.inner.Start(ctx) } +func (l *LimitedConsensusNoDAG) Close() error { return l.inner.Close() } +func (l *LimitedConsensusNoDAG) HealthReport() map[string]error { return l.inner.HealthReport() } +func (l *LimitedConsensusNoDAG) Name() string { return l.inner.Name() } +func (l *LimitedConsensusNoDAG) Description() string { return l.inner.Description() } +func (l *LimitedConsensusNoDAG) Ready() error { return l.inner.Ready() } +func (l *LimitedConsensusNoDAG) Initialise(ctx context.Context, deps core.StandardCapabilitiesDependencies) error { + return l.inner.Initialise(ctx, deps) +} + +// --- LimitedEVMChain --- + +// LimitedEVMChain wraps an evmserver.ClientCapability and enforces chain write +// report size and gas limits from SimulationLimits. +type LimitedEVMChain struct { + inner evmserver.ClientCapability + limits *SimulationLimits +} + +var _ evmserver.ClientCapability = (*LimitedEVMChain)(nil) + +func NewLimitedEVMChain(inner evmserver.ClientCapability, limits *SimulationLimits) *LimitedEVMChain { + return &LimitedEVMChain{inner: inner, limits: limits} +} + +func (l *LimitedEVMChain) WriteReport(ctx context.Context, metadata commonCap.RequestMetadata, input *evmcappb.WriteReportRequest) (*commonCap.ResponseAndMetadata[*evmcappb.WriteReportReply], caperrors.Error) { + // Check report size + reportLimit := l.limits.ChainWriteReportSizeLimit() + if reportLimit > 0 && input.Report != nil && len(input.Report.RawReport) > reportLimit { + return nil, caperrors.NewPublicUserError( + fmt.Errorf("simulation limit exceeded: chain write report size %d bytes exceeds limit of %d bytes", len(input.Report.RawReport), reportLimit), + caperrors.ResourceExhausted, + ) + } + + // Check gas limit + gasLimit := l.limits.ChainWriteEVMGasLimit() + if gasLimit > 0 && input.GasConfig != nil && input.GasConfig.GasLimit > gasLimit { + return nil, caperrors.NewPublicUserError( + fmt.Errorf("simulation limit exceeded: EVM gas limit %d exceeds maximum of %d", input.GasConfig.GasLimit, gasLimit), + caperrors.ResourceExhausted, + ) + } + + return l.inner.WriteReport(ctx, metadata, input) +} + +// All other methods delegate to the inner capability. +func (l *LimitedEVMChain) CallContract(ctx context.Context, metadata commonCap.RequestMetadata, input *evmcappb.CallContractRequest) (*commonCap.ResponseAndMetadata[*evmcappb.CallContractReply], caperrors.Error) { + return l.inner.CallContract(ctx, metadata, input) +} + +func (l *LimitedEVMChain) FilterLogs(ctx context.Context, metadata commonCap.RequestMetadata, input *evmcappb.FilterLogsRequest) (*commonCap.ResponseAndMetadata[*evmcappb.FilterLogsReply], caperrors.Error) { + return l.inner.FilterLogs(ctx, metadata, input) +} + +func (l *LimitedEVMChain) BalanceAt(ctx context.Context, metadata commonCap.RequestMetadata, input *evmcappb.BalanceAtRequest) (*commonCap.ResponseAndMetadata[*evmcappb.BalanceAtReply], caperrors.Error) { + return l.inner.BalanceAt(ctx, metadata, input) +} + +func (l *LimitedEVMChain) EstimateGas(ctx context.Context, metadata commonCap.RequestMetadata, input *evmcappb.EstimateGasRequest) (*commonCap.ResponseAndMetadata[*evmcappb.EstimateGasReply], caperrors.Error) { + return l.inner.EstimateGas(ctx, metadata, input) +} + +func (l *LimitedEVMChain) GetTransactionByHash(ctx context.Context, metadata commonCap.RequestMetadata, input *evmcappb.GetTransactionByHashRequest) (*commonCap.ResponseAndMetadata[*evmcappb.GetTransactionByHashReply], caperrors.Error) { + return l.inner.GetTransactionByHash(ctx, metadata, input) +} + +func (l *LimitedEVMChain) GetTransactionReceipt(ctx context.Context, metadata commonCap.RequestMetadata, input *evmcappb.GetTransactionReceiptRequest) (*commonCap.ResponseAndMetadata[*evmcappb.GetTransactionReceiptReply], caperrors.Error) { + return l.inner.GetTransactionReceipt(ctx, metadata, input) +} + +func (l *LimitedEVMChain) HeaderByNumber(ctx context.Context, metadata commonCap.RequestMetadata, input *evmcappb.HeaderByNumberRequest) (*commonCap.ResponseAndMetadata[*evmcappb.HeaderByNumberReply], caperrors.Error) { + return l.inner.HeaderByNumber(ctx, metadata, input) +} + +func (l *LimitedEVMChain) RegisterLogTrigger(ctx context.Context, triggerID string, metadata commonCap.RequestMetadata, input *evmcappb.FilterLogTriggerRequest) (<-chan commonCap.TriggerAndId[*evmcappb.Log], caperrors.Error) { + return l.inner.RegisterLogTrigger(ctx, triggerID, metadata, input) +} + +func (l *LimitedEVMChain) UnregisterLogTrigger(ctx context.Context, triggerID string, metadata commonCap.RequestMetadata, input *evmcappb.FilterLogTriggerRequest) caperrors.Error { + return l.inner.UnregisterLogTrigger(ctx, triggerID, metadata, input) +} + +func (l *LimitedEVMChain) ChainSelector() uint64 { return l.inner.ChainSelector() } +func (l *LimitedEVMChain) Start(ctx context.Context) error { return l.inner.Start(ctx) } +func (l *LimitedEVMChain) Close() error { return l.inner.Close() } +func (l *LimitedEVMChain) HealthReport() map[string]error { return l.inner.HealthReport() } +func (l *LimitedEVMChain) Name() string { return l.inner.Name() } +func (l *LimitedEVMChain) Description() string { return l.inner.Description() } +func (l *LimitedEVMChain) Ready() error { return l.inner.Ready() } +func (l *LimitedEVMChain) Initialise(ctx context.Context, deps core.StandardCapabilitiesDependencies) error { + return l.inner.Initialise(ctx, deps) +} diff --git a/cmd/workflow/simulate/limits.go b/cmd/workflow/simulate/limits.go new file mode 100644 index 00000000..2c273bf4 --- /dev/null +++ b/cmd/workflow/simulate/limits.go @@ -0,0 +1,177 @@ +package simulate + +import ( + _ "embed" + "encoding/json" + "fmt" + "os" + + "github.com/smartcontractkit/chainlink-common/pkg/settings/cresettings" +) + +//go:embed limits.json +var defaultLimitsJSON []byte + +// SimulationLimits holds the workflow-level limits applied during simulation. +type SimulationLimits struct { + Workflows cresettings.Workflows +} + +// DefaultLimits returns simulation limits populated from the embedded defaults. +func DefaultLimits() (*SimulationLimits, error) { + return parseLimitsJSON(defaultLimitsJSON) +} + +// LoadLimits reads a limits JSON file from disk and returns parsed SimulationLimits. +func LoadLimits(path string) (*SimulationLimits, error) { + data, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("failed to read limits file %s: %w", path, err) + } + return parseLimitsJSON(data) +} + +func parseLimitsJSON(data []byte) (*SimulationLimits, error) { + // Start from the pre-built Default which has all Parse functions configured. + // Setting[T].Parse is a function closure (json:"-") that cannot be serialized, + // so we must unmarshal into a copy that already has Parse funcs set. + w := cresettings.Default.PerWorkflow + if err := json.Unmarshal(data, &w); err != nil { + return nil, fmt.Errorf("failed to parse limits JSON: %w", err) + } + return &SimulationLimits{Workflows: w}, nil +} + +// applyEngineLimits copies limit values from the SimulationLimits into the +// engine's workflow settings config. ChainAllowed is intentionally left as +// allow-all for simulation. +func applyEngineLimits(cfg *cresettings.Workflows, limits *SimulationLimits) { + src := &limits.Workflows + + // Execution limits + cfg.ExecutionTimeout = src.ExecutionTimeout + cfg.ExecutionResponseLimit = src.ExecutionResponseLimit + cfg.ExecutionConcurrencyLimit = src.ExecutionConcurrencyLimit + + // Capability limits + cfg.CapabilityConcurrencyLimit = src.CapabilityConcurrencyLimit + cfg.CapabilityCallTimeout = src.CapabilityCallTimeout + cfg.SecretsConcurrencyLimit = src.SecretsConcurrencyLimit + + // Trigger limits + cfg.TriggerRegistrationsTimeout = src.TriggerRegistrationsTimeout + cfg.TriggerEventQueueLimit = src.TriggerEventQueueLimit + cfg.TriggerEventQueueTimeout = src.TriggerEventQueueTimeout + cfg.TriggerSubscriptionTimeout = src.TriggerSubscriptionTimeout + cfg.TriggerSubscriptionLimit = src.TriggerSubscriptionLimit + + // WASM limits + cfg.WASMMemoryLimit = src.WASMMemoryLimit + cfg.WASMBinarySizeLimit = src.WASMBinarySizeLimit + cfg.WASMCompressedBinarySizeLimit = src.WASMCompressedBinarySizeLimit + cfg.WASMConfigSizeLimit = src.WASMConfigSizeLimit + cfg.WASMSecretsSizeLimit = src.WASMSecretsSizeLimit + + // Log limits + cfg.LogLineLimit = src.LogLineLimit + cfg.LogEventLimit = src.LogEventLimit + + // Call count limits + cfg.ChainRead = src.ChainRead + cfg.ChainWrite.TargetsLimit = src.ChainWrite.TargetsLimit + cfg.Consensus.CallLimit = src.Consensus.CallLimit + cfg.HTTPAction.CallLimit = src.HTTPAction.CallLimit + cfg.ConfidentialHTTP.CallLimit = src.ConfidentialHTTP.CallLimit + cfg.Secrets = src.Secrets + + // Trigger-specific limits + cfg.CRONTrigger = src.CRONTrigger + cfg.HTTPTrigger = src.HTTPTrigger + cfg.LogTrigger = src.LogTrigger + + // NOTE: ChainAllowed is NOT overridden — simulation keeps allow-all +} + +// HTTPRequestSizeLimit returns the HTTP action request size limit in bytes. +func (l *SimulationLimits) HTTPRequestSizeLimit() int { + return int(l.Workflows.HTTPAction.RequestSizeLimit.DefaultValue) +} + +// HTTPResponseSizeLimit returns the HTTP action response size limit in bytes. +func (l *SimulationLimits) HTTPResponseSizeLimit() int { + return int(l.Workflows.HTTPAction.ResponseSizeLimit.DefaultValue) +} + +// ConfHTTPRequestSizeLimit returns the confidential HTTP request size limit in bytes. +func (l *SimulationLimits) ConfHTTPRequestSizeLimit() int { + return int(l.Workflows.ConfidentialHTTP.RequestSizeLimit.DefaultValue) +} + +// ConfHTTPResponseSizeLimit returns the confidential HTTP response size limit in bytes. +func (l *SimulationLimits) ConfHTTPResponseSizeLimit() int { + return int(l.Workflows.ConfidentialHTTP.ResponseSizeLimit.DefaultValue) +} + +// ConsensusObservationSizeLimit returns the consensus observation size limit in bytes. +func (l *SimulationLimits) ConsensusObservationSizeLimit() int { + return int(l.Workflows.Consensus.ObservationSizeLimit.DefaultValue) +} + +// ChainWriteReportSizeLimit returns the chain write report size limit in bytes. +func (l *SimulationLimits) ChainWriteReportSizeLimit() int { + return int(l.Workflows.ChainWrite.ReportSizeLimit.DefaultValue) +} + +// ChainWriteEVMGasLimit returns the default EVM gas limit. +func (l *SimulationLimits) ChainWriteEVMGasLimit() uint64 { + return l.Workflows.ChainWrite.EVM.GasLimit.Default.DefaultValue +} + +// WASMBinarySize returns the WASM binary size limit in bytes. +func (l *SimulationLimits) WASMBinarySize() int { + return int(l.Workflows.WASMBinarySizeLimit.DefaultValue) +} + +// WASMCompressedBinarySize returns the WASM compressed binary size limit in bytes. +func (l *SimulationLimits) WASMCompressedBinarySize() int { + return int(l.Workflows.WASMCompressedBinarySizeLimit.DefaultValue) +} + +// LimitsSummary returns a human-readable summary of key limits. +func (l *SimulationLimits) LimitsSummary() string { + w := &l.Workflows + return fmt.Sprintf( + "HTTP: req=%s resp=%s timeout=%s | ConfHTTP: req=%s resp=%s timeout=%s | Consensus obs=%s | ChainWrite report=%s gas=%d | WASM binary=%s compressed=%s", + w.HTTPAction.RequestSizeLimit.DefaultValue, + w.HTTPAction.ResponseSizeLimit.DefaultValue, + w.HTTPAction.ConnectionTimeout.DefaultValue, + w.ConfidentialHTTP.RequestSizeLimit.DefaultValue, + w.ConfidentialHTTP.ResponseSizeLimit.DefaultValue, + w.ConfidentialHTTP.ConnectionTimeout.DefaultValue, + w.Consensus.ObservationSizeLimit.DefaultValue, + w.ChainWrite.ReportSizeLimit.DefaultValue, + w.ChainWrite.EVM.GasLimit.Default.DefaultValue, + w.WASMBinarySizeLimit.DefaultValue, + w.WASMCompressedBinarySizeLimit.DefaultValue, + ) +} + +// ExportDefaultLimitsJSON returns the embedded default limits JSON. +func ExportDefaultLimitsJSON() []byte { + return defaultLimitsJSON +} + +// ResolveLimits resolves a --limits flag value to SimulationLimits. +// Returns nil if limitsFlag is "none" (no limits enforcement). +func ResolveLimits(limitsFlag string) (*SimulationLimits, error) { + if limitsFlag == "" || limitsFlag == "none" { + return nil, nil + } + + if limitsFlag == "default" { + return DefaultLimits() + } + + return LoadLimits(limitsFlag) +} + diff --git a/cmd/workflow/simulate/limits.json b/cmd/workflow/simulate/limits.json new file mode 100644 index 00000000..ced46eeb --- /dev/null +++ b/cmd/workflow/simulate/limits.json @@ -0,0 +1,69 @@ +{ + "TriggerRegistrationsTimeout": "10s", + "TriggerSubscriptionTimeout": "15s", + "TriggerSubscriptionLimit": "10", + "TriggerEventQueueLimit": "50", + "TriggerEventQueueTimeout": "10m0s", + "CapabilityConcurrencyLimit": "30", + "CapabilityCallTimeout": "3m0s", + "SecretsConcurrencyLimit": "5", + "ExecutionConcurrencyLimit": "5", + "ExecutionTimeout": "5m0s", + "ExecutionResponseLimit": "100kb", + "ExecutionTimestampsEnabled": "false", + "WASMMemoryLimit": "100mb", + "WASMBinarySizeLimit": "100mb", + "WASMCompressedBinarySizeLimit": "20mb", + "WASMConfigSizeLimit": "1mb", + "WASMSecretsSizeLimit": "1mb", + "LogLineLimit": "1kb", + "LogEventLimit": "1000", + "CRONTrigger": { + "FastestScheduleInterval": "30s" + }, + "HTTPTrigger": { + "RateLimit": "every30s:3" + }, + "LogTrigger": { + "EventRateLimit": "every6s:10", + "EventSizeLimit": "5kb", + "FilterAddressLimit": "5", + "FilterTopicsPerSlotLimit": "10" + }, + "ChainWrite": { + "TargetsLimit": "10", + "ReportSizeLimit": "5kb", + "EVM": { + "TransactionGasLimit": "5000000", + "GasLimit": { + "Default": "5000000", + "Values": {} + } + } + }, + "ChainRead": { + "CallLimit": "15", + "LogQueryBlockLimit": "100", + "PayloadSizeLimit": "5kb" + }, + "Consensus": { + "ObservationSizeLimit": "100kb", + "CallLimit": "20" + }, + "HTTPAction": { + "CallLimit": "5", + "CacheAgeLimit": "10m0s", + "ConnectionTimeout": "10s", + "RequestSizeLimit": "10kb", + "ResponseSizeLimit": "100kb" + }, + "ConfidentialHTTP": { + "CallLimit": "5", + "ConnectionTimeout": "10s", + "RequestSizeLimit": "10kb", + "ResponseSizeLimit": "100kb" + }, + "Secrets": { + "CallLimit": "5" + } +} diff --git a/docs/cre_workflow.md b/docs/cre_workflow.md index 0bcc74cb..db2424d1 100644 --- a/docs/cre_workflow.md +++ b/docs/cre_workflow.md @@ -32,6 +32,7 @@ cre workflow [optional flags] * [cre workflow custom-build](cre_workflow_custom-build.md) - Converts an existing workflow to a custom (self-compiled) build * [cre workflow delete](cre_workflow_delete.md) - Deletes all versions of a workflow from the Workflow Registry * [cre workflow deploy](cre_workflow_deploy.md) - Deploys a workflow to the Workflow Registry contract +* [cre workflow limits](cre_workflow_limits.md) - Manage simulation limits * [cre workflow pause](cre_workflow_pause.md) - Pauses workflow on the Workflow Registry contract * [cre workflow simulate](cre_workflow_simulate.md) - Simulates a workflow diff --git a/docs/cre_workflow_limits.md b/docs/cre_workflow_limits.md new file mode 100644 index 00000000..4367f1b6 --- /dev/null +++ b/docs/cre_workflow_limits.md @@ -0,0 +1,28 @@ +## cre workflow limits + +Manage simulation limits + +### Synopsis + +The limits command provides tools for managing workflow simulation limits. + +### Options + +``` + -h, --help help for limits +``` + +### Options inherited from parent commands + +``` + -e, --env string Path to .env file which contains sensitive info (default ".env") + -R, --project-root string Path to the project root + -T, --target string Use target settings from YAML config + -v, --verbose Run command in VERBOSE mode +``` + +### SEE ALSO + +* [cre workflow](cre_workflow.md) - Manages workflows +* [cre workflow limits export](cre_workflow_limits_export.md) - Export default simulation limits as JSON + diff --git a/docs/cre_workflow_limits_export.md b/docs/cre_workflow_limits_export.md new file mode 100644 index 00000000..a1028b06 --- /dev/null +++ b/docs/cre_workflow_limits_export.md @@ -0,0 +1,38 @@ +## cre workflow limits export + +Export default simulation limits as JSON + +### Synopsis + +Exports the default production simulation limits as JSON. + +The output can be redirected to a file and customized for use with +the --limits flag of the simulate command. + +Example: + cre workflow limits export > my-limits.json + cre workflow simulate ./my-workflow --limits ./my-limits.json + +``` +cre workflow limits export [optional flags] +``` + +### Options + +``` + -h, --help help for export +``` + +### Options inherited from parent commands + +``` + -e, --env string Path to .env file which contains sensitive info (default ".env") + -R, --project-root string Path to the project root + -T, --target string Use target settings from YAML config + -v, --verbose Run command in VERBOSE mode +``` + +### SEE ALSO + +* [cre workflow limits](cre_workflow_limits.md) - Manage simulation limits + diff --git a/docs/cre_workflow_simulate.md b/docs/cre_workflow_simulate.md index 635c7b2c..18b05013 100644 --- a/docs/cre_workflow_simulate.md +++ b/docs/cre_workflow_simulate.md @@ -25,6 +25,7 @@ cre workflow simulate ./my-workflow --evm-tx-hash string EVM trigger transaction hash (0x...) -h, --help help for simulate --http-payload string HTTP trigger payload as JSON string or path to JSON file (with or without @ prefix) + --limits string Production limits to enforce during simulation. Use 'default' for prod defaults, path to custom limits.json, or 'none' to disable (default "default") --non-interactive Run without prompts; requires --trigger-index and inputs for the selected trigger type --trigger-index int Index of the trigger to run (0-based) (default -1) ``` From a0763ac54c4bf222bc3bc98cf1d73b19b6e2e152 Mon Sep 17 00:00:00 2001 From: De Clercq Wentzel <10665586+wentzeld@users.noreply.github.com> Date: Sat, 28 Feb 2026 14:47:58 -0800 Subject: [PATCH 3/3] feat: add --limits flag to cre workflow simulate --- cmd/root.go | 108 +++++++++--------- cmd/workflow/simulate/limited_capabilities.go | 52 +++++---- cmd/workflow/simulate/limits.go | 1 - 3 files changed, 81 insertions(+), 80 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index b49eb6b9..d754a9d7 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -385,31 +385,31 @@ func newRootCommand() *cobra.Command { func isLoadSettings(cmd *cobra.Command) bool { // It is not expected to have the settings file when running the following commands var excludedCommands = map[string]struct{}{ - "cre version": {}, - "cre login": {}, - "cre logout": {}, - "cre whoami": {}, - "cre account access": {}, - "cre account list-key": {}, - "cre init": {}, - "cre generate-bindings": {}, - "cre completion bash": {}, - "cre completion fish": {}, - "cre completion powershell": {}, - "cre completion zsh": {}, - "cre help": {}, - "cre update": {}, - "cre workflow": {}, + "cre version": {}, + "cre login": {}, + "cre logout": {}, + "cre whoami": {}, + "cre account access": {}, + "cre account list-key": {}, + "cre init": {}, + "cre generate-bindings": {}, + "cre completion bash": {}, + "cre completion fish": {}, + "cre completion powershell": {}, + "cre completion zsh": {}, + "cre help": {}, + "cre update": {}, + "cre workflow": {}, "cre workflow custom-build": {}, "cre workflow limits": {}, "cre workflow limits export": {}, "cre account": {}, - "cre secrets": {}, - "cre templates": {}, - "cre templates list": {}, - "cre templates add": {}, - "cre templates remove": {}, - "cre": {}, + "cre secrets": {}, + "cre templates": {}, + "cre templates list": {}, + "cre templates add": {}, + "cre templates remove": {}, + "cre": {}, } _, exists := excludedCommands[cmd.CommandPath()] @@ -419,26 +419,26 @@ func isLoadSettings(cmd *cobra.Command) bool { func isLoadCredentials(cmd *cobra.Command) bool { // It is not expected to have the credentials loaded when running the following commands var excludedCommands = map[string]struct{}{ - "cre version": {}, - "cre login": {}, - "cre logout": {}, - "cre completion bash": {}, - "cre completion fish": {}, - "cre completion powershell": {}, - "cre completion zsh": {}, - "cre help": {}, - "cre generate-bindings": {}, - "cre update": {}, - "cre workflow": {}, + "cre version": {}, + "cre login": {}, + "cre logout": {}, + "cre completion bash": {}, + "cre completion fish": {}, + "cre completion powershell": {}, + "cre completion zsh": {}, + "cre help": {}, + "cre generate-bindings": {}, + "cre update": {}, + "cre workflow": {}, "cre workflow limits": {}, "cre workflow limits export": {}, "cre account": {}, "cre secrets": {}, - "cre templates": {}, - "cre templates list": {}, - "cre templates add": {}, - "cre templates remove": {}, - "cre": {}, + "cre templates": {}, + "cre templates list": {}, + "cre templates add": {}, + "cre templates remove": {}, + "cre": {}, } _, exists := excludedCommands[cmd.CommandPath()] @@ -489,26 +489,26 @@ func shouldShowSpinner(cmd *cobra.Command) bool { // Don't show spinner for commands that don't do async work // or commands that have their own interactive UI (like init) var excludedCommands = map[string]struct{}{ - "cre": {}, - "cre version": {}, - "cre help": {}, - "cre completion bash": {}, - "cre completion fish": {}, - "cre completion powershell": {}, - "cre completion zsh": {}, - "cre init": {}, // Has its own Huh forms UI - "cre login": {}, // Has its own interactive flow - "cre logout": {}, - "cre update": {}, - "cre workflow": {}, // Just shows help + "cre": {}, + "cre version": {}, + "cre help": {}, + "cre completion bash": {}, + "cre completion fish": {}, + "cre completion powershell": {}, + "cre completion zsh": {}, + "cre init": {}, // Has its own Huh forms UI + "cre login": {}, // Has its own interactive flow + "cre logout": {}, + "cre update": {}, + "cre workflow": {}, // Just shows help "cre workflow limits": {}, // Just shows help "cre workflow limits export": {}, // Static data, no project needed "cre account": {}, // Just shows help - "cre secrets": {}, // Just shows help - "cre templates": {}, // Just shows help - "cre templates list": {}, - "cre templates add": {}, - "cre templates remove": {}, + "cre secrets": {}, // Just shows help + "cre templates": {}, // Just shows help + "cre templates list": {}, + "cre templates add": {}, + "cre templates remove": {}, } _, exists := excludedCommands[cmd.CommandPath()] diff --git a/cmd/workflow/simulate/limited_capabilities.go b/cmd/workflow/simulate/limited_capabilities.go index 4d9110fa..ec9a834d 100644 --- a/cmd/workflow/simulate/limited_capabilities.go +++ b/cmd/workflow/simulate/limited_capabilities.go @@ -16,9 +16,9 @@ import ( evmcappb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/evm" evmserver "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/evm/server" consensusserver "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/consensus/server" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" sdkpb "github.com/smartcontractkit/chainlink-protos/cre/go/sdk" valuespb "github.com/smartcontractkit/chainlink-protos/cre/go/values/pb" - "github.com/smartcontractkit/chainlink-common/pkg/types/core" ) // --- LimitedHTTPAction --- @@ -72,12 +72,12 @@ func (l *LimitedHTTPAction) SendRequest(ctx context.Context, metadata commonCap. return resp, nil } -func (l *LimitedHTTPAction) Start(ctx context.Context) error { return l.inner.Start(ctx) } -func (l *LimitedHTTPAction) Close() error { return l.inner.Close() } -func (l *LimitedHTTPAction) HealthReport() map[string]error { return l.inner.HealthReport() } -func (l *LimitedHTTPAction) Name() string { return l.inner.Name() } -func (l *LimitedHTTPAction) Description() string { return l.inner.Description() } -func (l *LimitedHTTPAction) Ready() error { return l.inner.Ready() } +func (l *LimitedHTTPAction) Start(ctx context.Context) error { return l.inner.Start(ctx) } +func (l *LimitedHTTPAction) Close() error { return l.inner.Close() } +func (l *LimitedHTTPAction) HealthReport() map[string]error { return l.inner.HealthReport() } +func (l *LimitedHTTPAction) Name() string { return l.inner.Name() } +func (l *LimitedHTTPAction) Description() string { return l.inner.Description() } +func (l *LimitedHTTPAction) Ready() error { return l.inner.Ready() } func (l *LimitedHTTPAction) Initialise(ctx context.Context, deps core.StandardCapabilitiesDependencies) error { return l.inner.Initialise(ctx, deps) } @@ -136,12 +136,14 @@ func (l *LimitedConfidentialHTTPAction) SendRequest(ctx context.Context, metadat return resp, nil } -func (l *LimitedConfidentialHTTPAction) Start(ctx context.Context) error { return l.inner.Start(ctx) } -func (l *LimitedConfidentialHTTPAction) Close() error { return l.inner.Close() } -func (l *LimitedConfidentialHTTPAction) HealthReport() map[string]error { return l.inner.HealthReport() } -func (l *LimitedConfidentialHTTPAction) Name() string { return l.inner.Name() } -func (l *LimitedConfidentialHTTPAction) Description() string { return l.inner.Description() } -func (l *LimitedConfidentialHTTPAction) Ready() error { return l.inner.Ready() } +func (l *LimitedConfidentialHTTPAction) Start(ctx context.Context) error { return l.inner.Start(ctx) } +func (l *LimitedConfidentialHTTPAction) Close() error { return l.inner.Close() } +func (l *LimitedConfidentialHTTPAction) HealthReport() map[string]error { + return l.inner.HealthReport() +} +func (l *LimitedConfidentialHTTPAction) Name() string { return l.inner.Name() } +func (l *LimitedConfidentialHTTPAction) Description() string { return l.inner.Description() } +func (l *LimitedConfidentialHTTPAction) Ready() error { return l.inner.Ready() } func (l *LimitedConfidentialHTTPAction) Initialise(ctx context.Context, deps core.StandardCapabilitiesDependencies) error { return l.inner.Initialise(ctx, deps) } @@ -182,12 +184,12 @@ func (l *LimitedConsensusNoDAG) Report(ctx context.Context, metadata commonCap.R return l.inner.Report(ctx, metadata, input) } -func (l *LimitedConsensusNoDAG) Start(ctx context.Context) error { return l.inner.Start(ctx) } -func (l *LimitedConsensusNoDAG) Close() error { return l.inner.Close() } -func (l *LimitedConsensusNoDAG) HealthReport() map[string]error { return l.inner.HealthReport() } -func (l *LimitedConsensusNoDAG) Name() string { return l.inner.Name() } -func (l *LimitedConsensusNoDAG) Description() string { return l.inner.Description() } -func (l *LimitedConsensusNoDAG) Ready() error { return l.inner.Ready() } +func (l *LimitedConsensusNoDAG) Start(ctx context.Context) error { return l.inner.Start(ctx) } +func (l *LimitedConsensusNoDAG) Close() error { return l.inner.Close() } +func (l *LimitedConsensusNoDAG) HealthReport() map[string]error { return l.inner.HealthReport() } +func (l *LimitedConsensusNoDAG) Name() string { return l.inner.Name() } +func (l *LimitedConsensusNoDAG) Description() string { return l.inner.Description() } +func (l *LimitedConsensusNoDAG) Ready() error { return l.inner.Ready() } func (l *LimitedConsensusNoDAG) Initialise(ctx context.Context, deps core.StandardCapabilitiesDependencies) error { return l.inner.Initialise(ctx, deps) } @@ -266,13 +268,13 @@ func (l *LimitedEVMChain) UnregisterLogTrigger(ctx context.Context, triggerID st return l.inner.UnregisterLogTrigger(ctx, triggerID, metadata, input) } -func (l *LimitedEVMChain) ChainSelector() uint64 { return l.inner.ChainSelector() } +func (l *LimitedEVMChain) ChainSelector() uint64 { return l.inner.ChainSelector() } func (l *LimitedEVMChain) Start(ctx context.Context) error { return l.inner.Start(ctx) } -func (l *LimitedEVMChain) Close() error { return l.inner.Close() } -func (l *LimitedEVMChain) HealthReport() map[string]error { return l.inner.HealthReport() } -func (l *LimitedEVMChain) Name() string { return l.inner.Name() } -func (l *LimitedEVMChain) Description() string { return l.inner.Description() } -func (l *LimitedEVMChain) Ready() error { return l.inner.Ready() } +func (l *LimitedEVMChain) Close() error { return l.inner.Close() } +func (l *LimitedEVMChain) HealthReport() map[string]error { return l.inner.HealthReport() } +func (l *LimitedEVMChain) Name() string { return l.inner.Name() } +func (l *LimitedEVMChain) Description() string { return l.inner.Description() } +func (l *LimitedEVMChain) Ready() error { return l.inner.Ready() } func (l *LimitedEVMChain) Initialise(ctx context.Context, deps core.StandardCapabilitiesDependencies) error { return l.inner.Initialise(ctx, deps) } diff --git a/cmd/workflow/simulate/limits.go b/cmd/workflow/simulate/limits.go index 2c273bf4..5c146c87 100644 --- a/cmd/workflow/simulate/limits.go +++ b/cmd/workflow/simulate/limits.go @@ -174,4 +174,3 @@ func ResolveLimits(limitsFlag string) (*SimulationLimits, error) { return LoadLimits(limitsFlag) } -