Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
0d7133f
[CRE] [5/5] Wire confidential workflow execution into CRE
nadahalli Apr 1, 2026
0137d85
Remove launcher fix (relay DON will be configured as workflow DON ins…
nadahalli Mar 26, 2026
94e1c07
Sync with latest PR 1/2/4 branches for E2E
nadahalli Mar 26, 2026
0da1727
Simplify relay feature plugin: only set Enabled, drop TrustedPCRs/CAR…
nadahalli Mar 26, 2026
057f203
Update CC plugin refs to b7f4350
nadahalli Mar 26, 2026
057d721
Fix mock capability on-chain type: ACTION not TRIGGER
nadahalli Mar 26, 2026
19f9c96
Add BinaryURLResolver to ConfidentialModule for presigned URL support
nadahalli Mar 26, 2026
36dc719
Make BinaryURLResolver injectable via WithBinaryURLResolver option
nadahalli Mar 26, 2026
629731a
Revert BinaryURLResolver changes
nadahalli Mar 26, 2026
d5a71f7
File fetcher: extract filename from HTTP URLs for local resolution
nadahalli Mar 27, 2026
1951ac8
Update CC plugin refs to d7848a5
nadahalli Mar 27, 2026
55b8908
Bump chainlink-common to c1870a5e, merge PR 1/5 review fixes, update …
nadahalli Mar 30, 2026
cc77f09
Unify sendResponseAndCleanup to handle both success and error paths
nadahalli Mar 30, 2026
21ccbf1
Simplify `sendResponseAndCleanup`.
pavel-raykov Mar 30, 2026
7c9f3cb
Fix exhaustive lint: restore missing switch cases in recordMetrics an…
nadahalli Mar 31, 2026
69d4f2c
fan out relay requests to don nodes concurrently
nadahalli Apr 1, 2026
3c4c50f
sync 5/5 workflow wiring with rebased 4/5
nadahalli Apr 1, 2026
b22f1da
use cre settings for relay gateway rate limits
nadahalli Apr 2, 2026
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
5 changes: 5 additions & 0 deletions .changeset/confidential-workflow-execution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": minor
---

Add confidential workflow execution: ConfidentialModule, relay handler, gateway wiring, single-DON capability fix #added #db_update
2 changes: 1 addition & 1 deletion core/scripts/cre/environment/environment/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ func deployWorkflow(

fmt.Printf("\n⚙️ Registering workflow '%s' with the workflow registry\n\n", workflowNameFlag)

workflowID, registerErr := creworkflow.RegisterWithContract(ctx, sethClient, common.HexToAddress(workflowRegistryAddress), workflowRegistryVersion, uint64(donIDFlag), workflowNameFlag, "file://"+wasmWorkflowFilePathFlag, configPath, secretsPath, &containerTargetDirFlag)
workflowID, registerErr := creworkflow.RegisterWithContract(ctx, sethClient, common.HexToAddress(workflowRegistryAddress), workflowRegistryVersion, uint64(donIDFlag), workflowNameFlag, "file://"+wasmWorkflowFilePathFlag, configPath, secretsPath, nil, &containerTargetDirFlag)
if registerErr != nil {
return errors.Wrapf(registerErr, "❌ failed to register workflow %s", workflowNameFlag)
}
Expand Down
8 changes: 8 additions & 0 deletions core/services/cre/cre.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (

"github.com/smartcontractkit/chainlink/v2/core/capabilities"
"github.com/smartcontractkit/chainlink/v2/core/capabilities/compute"
"github.com/smartcontractkit/chainlink/v2/core/capabilities/confidentialrelay"
gatewayconnector "github.com/smartcontractkit/chainlink/v2/core/capabilities/gateway_connector"
"github.com/smartcontractkit/chainlink/v2/core/capabilities/localcapmgr"
"github.com/smartcontractkit/chainlink/v2/core/capabilities/remote"
Expand Down Expand Up @@ -169,6 +170,13 @@ func (s *Services) newSubservices(
}
s.GatewayConnectorWrapper = gatewayConnectorWrapper
srvs = append(srvs, gatewayConnectorWrapper)

relayService := confidentialrelay.NewService(
gatewayConnectorWrapper,
opts.CapabilitiesRegistry,
lggr,
)
srvs = append(srvs, relayService)
}

if cfg.CRE().Linking().URL() != "" {
Expand Down
14 changes: 9 additions & 5 deletions core/services/gateway/handler_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,20 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers"
"github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/capabilities"
v2 "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/capabilities/v2"
"github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/confidentialrelay"
"github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions"
"github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/vault"
"github.com/smartcontractkit/chainlink/v2/core/services/gateway/network"
workflowsyncerv2 "github.com/smartcontractkit/chainlink/v2/core/services/workflows/syncer/v2"
)

const (
FunctionsHandlerType HandlerType = "functions"
DummyHandlerType HandlerType = "dummy"
WebAPICapabilitiesType HandlerType = "web-api-capabilities" // Handler for v0.1 HTTP capabilities for DAG workflows
HTTPCapabilityType HandlerType = "http-capabilities" // Handler for v1.0 HTTP capabilities for NoDAG workflows
VaultHandlerType HandlerType = "vault"
FunctionsHandlerType HandlerType = "functions"
DummyHandlerType HandlerType = "dummy"
WebAPICapabilitiesType HandlerType = "web-api-capabilities" // Handler for v0.1 HTTP capabilities for DAG workflows
HTTPCapabilityType HandlerType = "http-capabilities" // Handler for v1.0 HTTP capabilities for NoDAG workflows
VaultHandlerType HandlerType = "vault"
ConfidentialRelayHandlerType HandlerType = "confidential-compute-relay"
)

type handlerFactory struct {
Expand Down Expand Up @@ -87,6 +89,8 @@ func (hf *handlerFactory) NewHandler(
case VaultHandlerType:
requestAuthorizer := vaultcap.NewRequestAuthorizer(hf.lggr, hf.workflowRegistrySyncer)
return vault.NewHandler(handlerConfig, donConfig, don, hf.capabilitiesRegistry, requestAuthorizer, hf.lggr, clockwork.NewRealClock(), hf.lf)
case ConfidentialRelayHandlerType:
return confidentialrelay.NewHandler(handlerConfig, donConfig, don, hf.lggr, clockwork.NewRealClock(), hf.lf)
default:
return nil, fmt.Errorf("unsupported handler type %s", handlerType)
}
Expand Down
56 changes: 56 additions & 0 deletions core/services/gateway/handlers/confidentialrelay/aggregator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package confidentialrelay

import (
"encoding/json"
"errors"
"fmt"

jsonrpc "github.com/smartcontractkit/chainlink-common/pkg/jsonrpc2"
"github.com/smartcontractkit/chainlink-common/pkg/logger"
)

var (
errInsufficientResponsesForQuorum = errors.New("insufficient valid responses to reach quorum")
errQuorumUnobtainable = errors.New("quorum unobtainable")
)

type aggregator struct{}

func (a *aggregator) Aggregate(resps map[string]jsonrpc.Response[json.RawMessage], donF int, donMembersCount int, l logger.Logger) (*jsonrpc.Response[json.RawMessage], error) {
// F+1 (QuorumFPlusOne) is sufficient because each relay node calls the
// target DON (Vault or capability) through CRE's standard capability
// dispatch, which includes DON-level consensus. Every honest relay node
// receives the same consensus-aggregated response and performs deterministic
// translation, producing byte-identical outputs. F+1 matching responses
// therefore guarantees at least one honest node vouched for the result.
requiredQuorum := donF + 1

if len(resps) < requiredQuorum {
return nil, errInsufficientResponsesForQuorum
}

shaToCount := map[string]int{}
maxShaToCount := 0
for _, r := range resps {
sha, err := r.Digest()
if err != nil {
l.Errorw("failed to compute digest of response during quorum validation, skipping...", "error", err)
continue
}
shaToCount[sha]++
if shaToCount[sha] > maxShaToCount {
maxShaToCount = shaToCount[sha]
}
if shaToCount[sha] >= requiredQuorum {
return &r, nil
}
}

remainingResponses := donMembersCount - len(resps)
if maxShaToCount+remainingResponses < requiredQuorum {
l.Warnw("quorum unattainable for request", "requiredQuorum", requiredQuorum, "remainingResponses", remainingResponses, "maxShaToCount", maxShaToCount)
return nil, fmt.Errorf("%w: requiredQuorum=%d, maxShaToCount=%d, remainingResponses=%d", errQuorumUnobtainable, requiredQuorum, maxShaToCount, remainingResponses)
}

return nil, errInsufficientResponsesForQuorum
}
Loading
Loading