diff --git a/.changeset/shaggy-ears-share.md b/.changeset/shaggy-ears-share.md new file mode 100644 index 00000000000..5946faf03cf --- /dev/null +++ b/.changeset/shaggy-ears-share.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +#internal Add RegistrySyncer diff --git a/core/capabilities/reader.go b/core/capabilities/reader.go new file mode 100644 index 00000000000..1c86cb1e28b --- /dev/null +++ b/core/capabilities/reader.go @@ -0,0 +1,110 @@ +package capabilities + +import ( + "context" + "encoding/json" + + "github.com/smartcontractkit/chainlink-common/pkg/types" + kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/keystone_capability_registry" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" + evmrelaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +type remoteRegistryReader struct { + r types.ContractReader +} + +var _ reader = (*remoteRegistryReader)(nil) + +type hashedCapabilityID [32]byte +type donID uint32 + +type state struct { + IDsToDONs map[donID]kcr.CapabilityRegistryDONInfo + IDsToNodes map[p2ptypes.PeerID]kcr.CapabilityRegistryNodeInfo + IDsToCapabilities map[hashedCapabilityID]kcr.CapabilityRegistryCapability +} + +func (r *remoteRegistryReader) state(ctx context.Context) (state, error) { + dons := []kcr.CapabilityRegistryDONInfo{} + err := r.r.GetLatestValue(ctx, "capabilityRegistry", "getDONs", nil, &dons) + if err != nil { + return state{}, err + } + + idsToDONs := map[donID]kcr.CapabilityRegistryDONInfo{} + for _, d := range dons { + idsToDONs[donID(d.Id)] = d + } + + caps := kcr.GetCapabilities{} + err = r.r.GetLatestValue(ctx, "capabilityRegistry", "getCapabilities", nil, &caps) + if err != nil { + return state{}, err + } + + idsToCapabilities := map[hashedCapabilityID]kcr.CapabilityRegistryCapability{} + for i, c := range caps.Capabilities { + idsToCapabilities[caps.HashedCapabilityIds[i]] = c + } + + nodes := &kcr.GetNodes{} + err = r.r.GetLatestValue(ctx, "capabilityRegistry", "getNodes", nil, &nodes) + if err != nil { + return state{}, err + } + + idsToNodes := map[p2ptypes.PeerID]kcr.CapabilityRegistryNodeInfo{} + for _, node := range nodes.NodeInfo { + idsToNodes[node.P2pId] = node + } + + return state{IDsToDONs: idsToDONs, IDsToCapabilities: idsToCapabilities, IDsToNodes: idsToNodes}, nil +} + +type contractReaderFactory interface { + NewContractReader(context.Context, []byte) (types.ContractReader, error) +} + +func newRemoteRegistryReader(ctx context.Context, relayer contractReaderFactory, remoteRegistryAddress string) (*remoteRegistryReader, error) { + contractReaderConfig := evmrelaytypes.ChainReaderConfig{ + Contracts: map[string]evmrelaytypes.ChainContractReader{ + "capabilityRegistry": { + ContractABI: kcr.CapabilityRegistryABI, + Configs: map[string]*evmrelaytypes.ChainReaderDefinition{ + "getDONs": { + ChainSpecificName: "getDONs", + }, + "getCapabilities": { + ChainSpecificName: "getCapabilities", + }, + "getNodes": { + ChainSpecificName: "getNodes", + }, + }, + }, + }, + } + + contractReaderConfigEncoded, err := json.Marshal(contractReaderConfig) + if err != nil { + return nil, err + } + + cr, err := relayer.NewContractReader(ctx, contractReaderConfigEncoded) + if err != nil { + return nil, err + } + + err = cr.Bind(ctx, []types.BoundContract{ + { + Address: remoteRegistryAddress, + Name: "capabilityRegistry", + }, + }) + if err != nil { + return nil, err + } + + return &remoteRegistryReader{r: cr}, err +} diff --git a/core/capabilities/reader_test.go b/core/capabilities/reader_test.go new file mode 100644 index 00000000000..3407ec43a43 --- /dev/null +++ b/core/capabilities/reader_test.go @@ -0,0 +1,210 @@ +package capabilities + +import ( + "context" + "crypto/rand" + "encoding/json" + "fmt" + "math/big" + "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/types" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/keystone_capability_registry" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" + "github.com/smartcontractkit/chainlink/v2/core/logger" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" + evmrelaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +var writeChainCapability = kcr.CapabilityRegistryCapability{ + LabelledName: "write-chain", + Version: "1.0.1", + ResponseType: uint8(1), +} + +func startNewChainWithRegistry(t *testing.T) (*kcr.CapabilityRegistry, common.Address, *bind.TransactOpts, *backends.SimulatedBackend) { + owner := testutils.MustNewSimTransactor(t) + + oneEth, _ := new(big.Int).SetString("100000000000000000000", 10) + gasLimit := ethconfig.Defaults.Miner.GasCeil * 2 // 60 M blocks + + simulatedBackend := backends.NewSimulatedBackend(core.GenesisAlloc{owner.From: { + Balance: oneEth, + }}, gasLimit) + simulatedBackend.Commit() + + capabilityRegistryAddress, _, capabilityRegistry, err := kcr.DeployCapabilityRegistry(owner, simulatedBackend) + require.NoError(t, err, "DeployCapabilityRegistry failed") + + fmt.Println("Deployed CapabilityRegistry at", capabilityRegistryAddress.Hex()) + simulatedBackend.Commit() + + return capabilityRegistry, capabilityRegistryAddress, owner, simulatedBackend +} + +type crFactory struct { + lggr logger.Logger + logPoller logpoller.LogPoller + client evmclient.Client +} + +func (c *crFactory) NewContractReader(ctx context.Context, cfg []byte) (types.ContractReader, error) { + crCfg := &evmrelaytypes.ChainReaderConfig{} + if err := json.Unmarshal(cfg, crCfg); err != nil { + return nil, err + } + svc, err := evm.NewChainReaderService(ctx, c.lggr, c.logPoller, c.client, *crCfg) + if err != nil { + return nil, err + } + + return svc, svc.Start(ctx) +} + +func newContractReaderFactory(t *testing.T, simulatedBackend *backends.SimulatedBackend) *crFactory { + lggr := logger.TestLogger(t) + client := evmclient.NewSimulatedBackendClient( + t, + simulatedBackend, + testutils.SimulatedChainID, + ) + db := pgtest.NewSqlxDB(t) + lp := logpoller.NewLogPoller( + logpoller.NewORM(testutils.SimulatedChainID, db, lggr), + client, + lggr, + logpoller.Opts{ + PollPeriod: 100 * time.Millisecond, + FinalityDepth: 2, + BackfillBatchSize: 3, + RpcBatchSize: 2, + KeepFinalizedBlocksDepth: 1000, + }, + ) + return &crFactory{ + lggr: lggr, + client: client, + logPoller: lp, + } +} + +func randomWord() [32]byte { + word := make([]byte, 32) + _, err := rand.Read(word) + if err != nil { + panic(err) + } + return [32]byte(word) +} + +func TestReader_Integration(t *testing.T) { + ctx := testutils.Context(t) + reg, regAddress, owner, sim := startNewChainWithRegistry(t) + + _, err := reg.AddCapabilities(owner, []kcr.CapabilityRegistryCapability{writeChainCapability}) + require.NoError(t, err, "AddCapability failed for %s", writeChainCapability.LabelledName) + sim.Commit() + + cid, err := reg.GetHashedCapabilityId(&bind.CallOpts{}, writeChainCapability.LabelledName, writeChainCapability.Version) + require.NoError(t, err) + + _, err = reg.AddNodeOperators(owner, []kcr.CapabilityRegistryNodeOperator{ + { + Admin: owner.From, + Name: "TEST_NOP", + }, + }) + require.NoError(t, err) + + nodeSet := [][32]byte{ + randomWord(), + randomWord(), + randomWord(), + } + + nodes := []kcr.CapabilityRegistryNodeInfo{ + { + // The first NodeOperatorId has id 1 since the id is auto-incrementing. + NodeOperatorId: uint32(1), + Signer: randomWord(), + P2pId: nodeSet[0], + HashedCapabilityIds: [][32]byte{cid}, + }, + { + // The first NodeOperatorId has id 1 since the id is auto-incrementing. + NodeOperatorId: uint32(1), + Signer: randomWord(), + P2pId: nodeSet[1], + HashedCapabilityIds: [][32]byte{cid}, + }, + { + // The first NodeOperatorId has id 1 since the id is auto-incrementing. + NodeOperatorId: uint32(1), + Signer: randomWord(), + P2pId: nodeSet[2], + HashedCapabilityIds: [][32]byte{cid}, + }, + } + _, err = reg.AddNodes(owner, nodes) + require.NoError(t, err) + + cfgs := []kcr.CapabilityRegistryCapabilityConfiguration{ + { + CapabilityId: cid, + Config: []byte(`{"hello": "world"}`), + }, + } + _, err = reg.AddDON( + owner, + nodeSet, + cfgs, + true, + true, + 1, + ) + sim.Commit() + + require.NoError(t, err) + + factory := newContractReaderFactory(t, sim) + reader, err := newRemoteRegistryReader(ctx, factory, regAddress.Hex()) + require.NoError(t, err) + + s, err := reader.state(ctx) + require.NoError(t, err) + assert.Len(t, s.IDsToCapabilities, 1) + + gotCap := s.IDsToCapabilities[cid] + assert.Equal(t, writeChainCapability, gotCap) + + assert.Len(t, s.IDsToDONs, 1) + assert.Equal(t, kcr.CapabilityRegistryDONInfo{ + Id: 1, // initial Id + ConfigCount: 1, // initial Count + IsPublic: true, + AcceptsWorkflows: true, + F: 1, + NodeP2PIds: nodeSet, + CapabilityConfigurations: cfgs, + }, s.IDsToDONs[1]) + + assert.Len(t, s.IDsToNodes, 3) + assert.Equal(t, map[p2ptypes.PeerID]kcr.CapabilityRegistryNodeInfo{ + nodeSet[0]: nodes[0], + nodeSet[1]: nodes[1], + nodeSet[2]: nodes[2], + }, s.IDsToNodes) +} diff --git a/core/capabilities/registry.go b/core/capabilities/registry.go index 84174e0232f..6a3a4ffb83b 100644 --- a/core/capabilities/registry.go +++ b/core/capabilities/registry.go @@ -2,6 +2,7 @@ package capabilities import ( "context" + "errors" "fmt" "sync" @@ -9,6 +10,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" ) +var ( + ErrCapabilityAlreadyExists = errors.New("capability already exists") +) + // Registry is a struct for the registry of capabilities. // Registry is safe for concurrent use. type Registry struct { @@ -141,7 +146,7 @@ func (r *Registry) Add(ctx context.Context, c capabilities.BaseCapability) error id := info.ID _, ok := r.m[id] if ok { - return fmt.Errorf("capability with id: %s already exists", id) + return fmt.Errorf("%w: id %s found in registry", ErrCapabilityAlreadyExists, id) } r.m[id] = c diff --git a/core/capabilities/registry_test.go b/core/capabilities/registry_test.go index 5208781700a..77e5d9edcd6 100644 --- a/core/capabilities/registry_test.go +++ b/core/capabilities/registry_test.go @@ -2,6 +2,7 @@ package capabilities_test import ( "context" + "errors" "fmt" "testing" @@ -85,7 +86,7 @@ func TestRegistry_NoDuplicateIDs(t *testing.T) { c2 := &mockCapability{CapabilityInfo: ci} err = r.Add(ctx, c2) - assert.ErrorContains(t, err, "capability with id: capability-1@1.0.0 already exists") + assert.True(t, errors.Is(err, coreCapabilities.ErrCapabilityAlreadyExists)) } func TestRegistry_ChecksExecutionAPIByType(t *testing.T) { diff --git a/core/capabilities/remote/trigger_publisher.go b/core/capabilities/remote/trigger_publisher.go index 12d539a2dc0..9710d102d49 100644 --- a/core/capabilities/remote/trigger_publisher.go +++ b/core/capabilities/remote/trigger_publisher.go @@ -21,7 +21,7 @@ import ( // // TriggerPublisher communicates with corresponding TriggerSubscribers on remote nodes. type triggerPublisher struct { - config types.RemoteTriggerConfig + config *types.RemoteTriggerConfig underlying commoncap.TriggerCapability capInfo commoncap.CapabilityInfo capDonInfo commoncap.DON @@ -48,7 +48,7 @@ type pubRegState struct { var _ types.Receiver = &triggerPublisher{} var _ services.Service = &triggerPublisher{} -func NewTriggerPublisher(config types.RemoteTriggerConfig, underlying commoncap.TriggerCapability, capInfo commoncap.CapabilityInfo, capDonInfo commoncap.DON, workflowDONs map[string]commoncap.DON, dispatcher types.Dispatcher, lggr logger.Logger) *triggerPublisher { +func NewTriggerPublisher(config *types.RemoteTriggerConfig, underlying commoncap.TriggerCapability, capInfo commoncap.CapabilityInfo, capDonInfo commoncap.DON, workflowDONs map[string]commoncap.DON, dispatcher types.Dispatcher, lggr logger.Logger) *triggerPublisher { config.ApplyDefaults() return &triggerPublisher{ config: config, diff --git a/core/capabilities/remote/trigger_publisher_test.go b/core/capabilities/remote/trigger_publisher_test.go index 15bdd39b55f..ff7c1cde3c7 100644 --- a/core/capabilities/remote/trigger_publisher_test.go +++ b/core/capabilities/remote/trigger_publisher_test.go @@ -40,7 +40,7 @@ func TestTriggerPublisher_Register(t *testing.T) { } dispatcher := remoteMocks.NewDispatcher(t) - config := remotetypes.RemoteTriggerConfig{ + config := &remotetypes.RemoteTriggerConfig{ RegistrationRefreshMs: 100, RegistrationExpiryMs: 100_000, MinResponsesToAggregate: 1, diff --git a/core/capabilities/remote/trigger_subscriber.go b/core/capabilities/remote/trigger_subscriber.go index b8c3d37a596..a16725af49a 100644 --- a/core/capabilities/remote/trigger_subscriber.go +++ b/core/capabilities/remote/trigger_subscriber.go @@ -23,7 +23,7 @@ import ( // // TriggerSubscriber communicates with corresponding TriggerReceivers on remote nodes. type triggerSubscriber struct { - config types.RemoteTriggerConfig + config *types.RemoteTriggerConfig capInfo commoncap.CapabilityInfo capDonInfo capabilities.DON capDonMembers map[p2ptypes.PeerID]struct{} @@ -55,7 +55,7 @@ var _ services.Service = &triggerSubscriber{} // TODO makes this configurable with a default const defaultSendChannelBufferSize = 1000 -func NewTriggerSubscriber(config types.RemoteTriggerConfig, capInfo commoncap.CapabilityInfo, capDonInfo capabilities.DON, localDonInfo capabilities.DON, dispatcher types.Dispatcher, aggregator types.Aggregator, lggr logger.Logger) *triggerSubscriber { +func NewTriggerSubscriber(config *types.RemoteTriggerConfig, capInfo commoncap.CapabilityInfo, capDonInfo capabilities.DON, localDonInfo capabilities.DON, dispatcher types.Dispatcher, aggregator types.Aggregator, lggr logger.Logger) *triggerSubscriber { if aggregator == nil { lggr.Warnw("no aggregator provided, using default MODE aggregator", "capabilityId", capInfo.ID) aggregator = NewDefaultModeAggregator(uint32(capDonInfo.F + 1)) diff --git a/core/capabilities/remote/trigger_subscriber_test.go b/core/capabilities/remote/trigger_subscriber_test.go index e50f570bb7b..f8c5e6ff6e9 100644 --- a/core/capabilities/remote/trigger_subscriber_test.go +++ b/core/capabilities/remote/trigger_subscriber_test.go @@ -58,7 +58,7 @@ func TestTriggerSubscriber_RegisterAndReceive(t *testing.T) { }) // register trigger - config := remotetypes.RemoteTriggerConfig{ + config := &remotetypes.RemoteTriggerConfig{ RegistrationRefreshMs: 100, RegistrationExpiryMs: 100, MinResponsesToAggregate: 1, diff --git a/core/capabilities/remote/types/config.go b/core/capabilities/remote/types/config.go index 588ae98095c..bb9e0fa4347 100644 --- a/core/capabilities/remote/types/config.go +++ b/core/capabilities/remote/types/config.go @@ -8,13 +8,6 @@ const ( // NOTE: consider splitting this config into values stored in Registry (KS-118) // and values defined locally by Capability owners. -type RemoteTriggerConfig struct { - RegistrationRefreshMs uint32 - RegistrationExpiryMs uint32 - MinResponsesToAggregate uint32 - MessageExpiryMs uint32 -} - func (c *RemoteTriggerConfig) ApplyDefaults() { if c.RegistrationRefreshMs == 0 { c.RegistrationRefreshMs = DefaultRegistrationRefreshMs diff --git a/core/capabilities/remote/types/message.pb.go b/core/capabilities/remote/types/message.pb.go deleted file mode 100644 index 7cef9d45748..00000000000 --- a/core/capabilities/remote/types/message.pb.go +++ /dev/null @@ -1,597 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.33.0 -// protoc v4.25.1 -// source: core/capabilities/remote/types/message.proto - -package types - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type Error int32 - -const ( - Error_OK Error = 0 - Error_VALIDATION_FAILED Error = 1 - Error_CAPABILITY_NOT_FOUND Error = 2 - Error_INVALID_REQUEST Error = 3 - Error_TIMEOUT Error = 4 - Error_INTERNAL_ERROR Error = 5 -) - -// Enum value maps for Error. -var ( - Error_name = map[int32]string{ - 0: "OK", - 1: "VALIDATION_FAILED", - 2: "CAPABILITY_NOT_FOUND", - 3: "INVALID_REQUEST", - 4: "TIMEOUT", - 5: "INTERNAL_ERROR", - } - Error_value = map[string]int32{ - "OK": 0, - "VALIDATION_FAILED": 1, - "CAPABILITY_NOT_FOUND": 2, - "INVALID_REQUEST": 3, - "TIMEOUT": 4, - "INTERNAL_ERROR": 5, - } -) - -func (x Error) Enum() *Error { - p := new(Error) - *p = x - return p -} - -func (x Error) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (Error) Descriptor() protoreflect.EnumDescriptor { - return file_core_capabilities_remote_types_message_proto_enumTypes[0].Descriptor() -} - -func (Error) Type() protoreflect.EnumType { - return &file_core_capabilities_remote_types_message_proto_enumTypes[0] -} - -func (x Error) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use Error.Descriptor instead. -func (Error) EnumDescriptor() ([]byte, []int) { - return file_core_capabilities_remote_types_message_proto_rawDescGZIP(), []int{0} -} - -type Message struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"` - Body []byte `protobuf:"bytes,2,opt,name=body,proto3" json:"body,omitempty"` // proto-encoded MessageBody to sign -} - -func (x *Message) Reset() { - *x = Message{} - if protoimpl.UnsafeEnabled { - mi := &file_core_capabilities_remote_types_message_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Message) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Message) ProtoMessage() {} - -func (x *Message) ProtoReflect() protoreflect.Message { - mi := &file_core_capabilities_remote_types_message_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Message.ProtoReflect.Descriptor instead. -func (*Message) Descriptor() ([]byte, []int) { - return file_core_capabilities_remote_types_message_proto_rawDescGZIP(), []int{0} -} - -func (x *Message) GetSignature() []byte { - if x != nil { - return x.Signature - } - return nil -} - -func (x *Message) GetBody() []byte { - if x != nil { - return x.Body - } - return nil -} - -type MessageBody struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` - Sender []byte `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"` - Receiver []byte `protobuf:"bytes,3,opt,name=receiver,proto3" json:"receiver,omitempty"` - Timestamp int64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - MessageId []byte `protobuf:"bytes,5,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` // scoped to sender - CapabilityId string `protobuf:"bytes,6,opt,name=capability_id,json=capabilityId,proto3" json:"capability_id,omitempty"` - CapabilityDonId string `protobuf:"bytes,7,opt,name=capability_don_id,json=capabilityDonId,proto3" json:"capability_don_id,omitempty"` - CallerDonId string `protobuf:"bytes,8,opt,name=caller_don_id,json=callerDonId,proto3" json:"caller_don_id,omitempty"` - Method string `protobuf:"bytes,9,opt,name=method,proto3" json:"method,omitempty"` - Error Error `protobuf:"varint,10,opt,name=error,proto3,enum=remote.Error" json:"error,omitempty"` - ErrorMsg string `protobuf:"bytes,11,opt,name=errorMsg,proto3" json:"errorMsg,omitempty"` - // payload contains a CapabilityRequest or CapabilityResponse - Payload []byte `protobuf:"bytes,12,opt,name=payload,proto3" json:"payload,omitempty"` - // Types that are assignable to Metadata: - // - // *MessageBody_TriggerRegistrationMetadata - // *MessageBody_TriggerEventMetadata - Metadata isMessageBody_Metadata `protobuf_oneof:"metadata"` -} - -func (x *MessageBody) Reset() { - *x = MessageBody{} - if protoimpl.UnsafeEnabled { - mi := &file_core_capabilities_remote_types_message_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *MessageBody) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MessageBody) ProtoMessage() {} - -func (x *MessageBody) ProtoReflect() protoreflect.Message { - mi := &file_core_capabilities_remote_types_message_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MessageBody.ProtoReflect.Descriptor instead. -func (*MessageBody) Descriptor() ([]byte, []int) { - return file_core_capabilities_remote_types_message_proto_rawDescGZIP(), []int{1} -} - -func (x *MessageBody) GetVersion() uint32 { - if x != nil { - return x.Version - } - return 0 -} - -func (x *MessageBody) GetSender() []byte { - if x != nil { - return x.Sender - } - return nil -} - -func (x *MessageBody) GetReceiver() []byte { - if x != nil { - return x.Receiver - } - return nil -} - -func (x *MessageBody) GetTimestamp() int64 { - if x != nil { - return x.Timestamp - } - return 0 -} - -func (x *MessageBody) GetMessageId() []byte { - if x != nil { - return x.MessageId - } - return nil -} - -func (x *MessageBody) GetCapabilityId() string { - if x != nil { - return x.CapabilityId - } - return "" -} - -func (x *MessageBody) GetCapabilityDonId() string { - if x != nil { - return x.CapabilityDonId - } - return "" -} - -func (x *MessageBody) GetCallerDonId() string { - if x != nil { - return x.CallerDonId - } - return "" -} - -func (x *MessageBody) GetMethod() string { - if x != nil { - return x.Method - } - return "" -} - -func (x *MessageBody) GetError() Error { - if x != nil { - return x.Error - } - return Error_OK -} - -func (x *MessageBody) GetErrorMsg() string { - if x != nil { - return x.ErrorMsg - } - return "" -} - -func (x *MessageBody) GetPayload() []byte { - if x != nil { - return x.Payload - } - return nil -} - -func (m *MessageBody) GetMetadata() isMessageBody_Metadata { - if m != nil { - return m.Metadata - } - return nil -} - -func (x *MessageBody) GetTriggerRegistrationMetadata() *TriggerRegistrationMetadata { - if x, ok := x.GetMetadata().(*MessageBody_TriggerRegistrationMetadata); ok { - return x.TriggerRegistrationMetadata - } - return nil -} - -func (x *MessageBody) GetTriggerEventMetadata() *TriggerEventMetadata { - if x, ok := x.GetMetadata().(*MessageBody_TriggerEventMetadata); ok { - return x.TriggerEventMetadata - } - return nil -} - -type isMessageBody_Metadata interface { - isMessageBody_Metadata() -} - -type MessageBody_TriggerRegistrationMetadata struct { - TriggerRegistrationMetadata *TriggerRegistrationMetadata `protobuf:"bytes,13,opt,name=trigger_registration_metadata,json=triggerRegistrationMetadata,proto3,oneof"` -} - -type MessageBody_TriggerEventMetadata struct { - TriggerEventMetadata *TriggerEventMetadata `protobuf:"bytes,14,opt,name=trigger_event_metadata,json=triggerEventMetadata,proto3,oneof"` -} - -func (*MessageBody_TriggerRegistrationMetadata) isMessageBody_Metadata() {} - -func (*MessageBody_TriggerEventMetadata) isMessageBody_Metadata() {} - -type TriggerRegistrationMetadata struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - LastReceivedEventId string `protobuf:"bytes,1,opt,name=last_received_event_id,json=lastReceivedEventId,proto3" json:"last_received_event_id,omitempty"` -} - -func (x *TriggerRegistrationMetadata) Reset() { - *x = TriggerRegistrationMetadata{} - if protoimpl.UnsafeEnabled { - mi := &file_core_capabilities_remote_types_message_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TriggerRegistrationMetadata) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TriggerRegistrationMetadata) ProtoMessage() {} - -func (x *TriggerRegistrationMetadata) ProtoReflect() protoreflect.Message { - mi := &file_core_capabilities_remote_types_message_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TriggerRegistrationMetadata.ProtoReflect.Descriptor instead. -func (*TriggerRegistrationMetadata) Descriptor() ([]byte, []int) { - return file_core_capabilities_remote_types_message_proto_rawDescGZIP(), []int{2} -} - -func (x *TriggerRegistrationMetadata) GetLastReceivedEventId() string { - if x != nil { - return x.LastReceivedEventId - } - return "" -} - -type TriggerEventMetadata struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - TriggerEventId string `protobuf:"bytes,1,opt,name=trigger_event_id,json=triggerEventId,proto3" json:"trigger_event_id,omitempty"` - WorkflowIds []string `protobuf:"bytes,2,rep,name=workflow_ids,json=workflowIds,proto3" json:"workflow_ids,omitempty"` -} - -func (x *TriggerEventMetadata) Reset() { - *x = TriggerEventMetadata{} - if protoimpl.UnsafeEnabled { - mi := &file_core_capabilities_remote_types_message_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TriggerEventMetadata) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TriggerEventMetadata) ProtoMessage() {} - -func (x *TriggerEventMetadata) ProtoReflect() protoreflect.Message { - mi := &file_core_capabilities_remote_types_message_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TriggerEventMetadata.ProtoReflect.Descriptor instead. -func (*TriggerEventMetadata) Descriptor() ([]byte, []int) { - return file_core_capabilities_remote_types_message_proto_rawDescGZIP(), []int{3} -} - -func (x *TriggerEventMetadata) GetTriggerEventId() string { - if x != nil { - return x.TriggerEventId - } - return "" -} - -func (x *TriggerEventMetadata) GetWorkflowIds() []string { - if x != nil { - return x.WorkflowIds - } - return nil -} - -var File_core_capabilities_remote_types_message_proto protoreflect.FileDescriptor - -var file_core_capabilities_remote_types_message_proto_rawDesc = []byte{ - 0x0a, 0x2c, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, - 0x69, 0x65, 0x73, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, - 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x22, 0x3b, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, - 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62, - 0x6f, 0x64, 0x79, 0x22, 0xcd, 0x04, 0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, - 0x6f, 0x64, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, - 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, - 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, - 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, - 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, - 0x1d, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x23, - 0x0a, 0x0d, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, - 0x79, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, - 0x79, 0x5f, 0x64, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, - 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6e, 0x49, 0x64, 0x12, - 0x22, 0x0a, 0x0d, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x64, 0x6f, 0x6e, 0x5f, 0x69, 0x64, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x44, 0x6f, - 0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x23, 0x0a, 0x05, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x72, 0x65, 0x6d, - 0x6f, 0x74, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x18, 0x0b, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x18, 0x0a, 0x07, - 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, - 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x69, 0x0a, 0x1d, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, - 0x72, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, - 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x48, 0x00, 0x52, 0x1b, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x52, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x12, 0x54, 0x0a, 0x16, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x5f, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0e, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, - 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, - 0x00, 0x52, 0x14, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x0a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x22, 0x52, 0x0a, 0x1b, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x12, 0x33, 0x0a, 0x16, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, - 0x76, 0x65, 0x64, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x13, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x63, 0x0a, 0x14, 0x54, 0x72, 0x69, 0x67, 0x67, - 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, - 0x28, 0x0a, 0x10, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x72, 0x69, 0x67, 0x67, - 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x6f, 0x72, - 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x73, 0x2a, 0x76, 0x0a, 0x05, - 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x15, 0x0a, - 0x11, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x46, 0x41, 0x49, 0x4c, - 0x45, 0x44, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x41, 0x50, 0x41, 0x42, 0x49, 0x4c, 0x49, - 0x54, 0x59, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x02, 0x12, 0x13, - 0x0a, 0x0f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, - 0x54, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x04, - 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x5f, 0x45, 0x52, 0x52, - 0x4f, 0x52, 0x10, 0x05, 0x42, 0x20, 0x5a, 0x1e, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x61, 0x70, - 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, - 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_core_capabilities_remote_types_message_proto_rawDescOnce sync.Once - file_core_capabilities_remote_types_message_proto_rawDescData = file_core_capabilities_remote_types_message_proto_rawDesc -) - -func file_core_capabilities_remote_types_message_proto_rawDescGZIP() []byte { - file_core_capabilities_remote_types_message_proto_rawDescOnce.Do(func() { - file_core_capabilities_remote_types_message_proto_rawDescData = protoimpl.X.CompressGZIP(file_core_capabilities_remote_types_message_proto_rawDescData) - }) - return file_core_capabilities_remote_types_message_proto_rawDescData -} - -var file_core_capabilities_remote_types_message_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_core_capabilities_remote_types_message_proto_msgTypes = make([]protoimpl.MessageInfo, 4) -var file_core_capabilities_remote_types_message_proto_goTypes = []interface{}{ - (Error)(0), // 0: remote.Error - (*Message)(nil), // 1: remote.Message - (*MessageBody)(nil), // 2: remote.MessageBody - (*TriggerRegistrationMetadata)(nil), // 3: remote.TriggerRegistrationMetadata - (*TriggerEventMetadata)(nil), // 4: remote.TriggerEventMetadata -} -var file_core_capabilities_remote_types_message_proto_depIdxs = []int32{ - 0, // 0: remote.MessageBody.error:type_name -> remote.Error - 3, // 1: remote.MessageBody.trigger_registration_metadata:type_name -> remote.TriggerRegistrationMetadata - 4, // 2: remote.MessageBody.trigger_event_metadata:type_name -> remote.TriggerEventMetadata - 3, // [3:3] is the sub-list for method output_type - 3, // [3:3] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name -} - -func init() { file_core_capabilities_remote_types_message_proto_init() } -func file_core_capabilities_remote_types_message_proto_init() { - if File_core_capabilities_remote_types_message_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_core_capabilities_remote_types_message_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Message); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_core_capabilities_remote_types_message_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MessageBody); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_core_capabilities_remote_types_message_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TriggerRegistrationMetadata); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_core_capabilities_remote_types_message_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TriggerEventMetadata); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_core_capabilities_remote_types_message_proto_msgTypes[1].OneofWrappers = []interface{}{ - (*MessageBody_TriggerRegistrationMetadata)(nil), - (*MessageBody_TriggerEventMetadata)(nil), - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_core_capabilities_remote_types_message_proto_rawDesc, - NumEnums: 1, - NumMessages: 4, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_core_capabilities_remote_types_message_proto_goTypes, - DependencyIndexes: file_core_capabilities_remote_types_message_proto_depIdxs, - EnumInfos: file_core_capabilities_remote_types_message_proto_enumTypes, - MessageInfos: file_core_capabilities_remote_types_message_proto_msgTypes, - }.Build() - File_core_capabilities_remote_types_message_proto = out.File - file_core_capabilities_remote_types_message_proto_rawDesc = nil - file_core_capabilities_remote_types_message_proto_goTypes = nil - file_core_capabilities_remote_types_message_proto_depIdxs = nil -} diff --git a/core/capabilities/remote/types/messages.pb.go b/core/capabilities/remote/types/messages.pb.go new file mode 100644 index 00000000000..0e51b395993 --- /dev/null +++ b/core/capabilities/remote/types/messages.pb.go @@ -0,0 +1,696 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v4.25.1 +// source: core/capabilities/remote/types/messages.proto + +package types + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Error int32 + +const ( + Error_OK Error = 0 + Error_VALIDATION_FAILED Error = 1 + Error_CAPABILITY_NOT_FOUND Error = 2 + Error_INVALID_REQUEST Error = 3 + Error_TIMEOUT Error = 4 + Error_INTERNAL_ERROR Error = 5 +) + +// Enum value maps for Error. +var ( + Error_name = map[int32]string{ + 0: "OK", + 1: "VALIDATION_FAILED", + 2: "CAPABILITY_NOT_FOUND", + 3: "INVALID_REQUEST", + 4: "TIMEOUT", + 5: "INTERNAL_ERROR", + } + Error_value = map[string]int32{ + "OK": 0, + "VALIDATION_FAILED": 1, + "CAPABILITY_NOT_FOUND": 2, + "INVALID_REQUEST": 3, + "TIMEOUT": 4, + "INTERNAL_ERROR": 5, + } +) + +func (x Error) Enum() *Error { + p := new(Error) + *p = x + return p +} + +func (x Error) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Error) Descriptor() protoreflect.EnumDescriptor { + return file_core_capabilities_remote_types_messages_proto_enumTypes[0].Descriptor() +} + +func (Error) Type() protoreflect.EnumType { + return &file_core_capabilities_remote_types_messages_proto_enumTypes[0] +} + +func (x Error) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Error.Descriptor instead. +func (Error) EnumDescriptor() ([]byte, []int) { + return file_core_capabilities_remote_types_messages_proto_rawDescGZIP(), []int{0} +} + +type Message struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"` + Body []byte `protobuf:"bytes,2,opt,name=body,proto3" json:"body,omitempty"` // proto-encoded MessageBody to sign +} + +func (x *Message) Reset() { + *x = Message{} + if protoimpl.UnsafeEnabled { + mi := &file_core_capabilities_remote_types_messages_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Message) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Message) ProtoMessage() {} + +func (x *Message) ProtoReflect() protoreflect.Message { + mi := &file_core_capabilities_remote_types_messages_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Message.ProtoReflect.Descriptor instead. +func (*Message) Descriptor() ([]byte, []int) { + return file_core_capabilities_remote_types_messages_proto_rawDescGZIP(), []int{0} +} + +func (x *Message) GetSignature() []byte { + if x != nil { + return x.Signature + } + return nil +} + +func (x *Message) GetBody() []byte { + if x != nil { + return x.Body + } + return nil +} + +type MessageBody struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + Sender []byte `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"` + Receiver []byte `protobuf:"bytes,3,opt,name=receiver,proto3" json:"receiver,omitempty"` + Timestamp int64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + MessageId []byte `protobuf:"bytes,5,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` // scoped to sender + CapabilityId string `protobuf:"bytes,6,opt,name=capability_id,json=capabilityId,proto3" json:"capability_id,omitempty"` + CapabilityDonId string `protobuf:"bytes,7,opt,name=capability_don_id,json=capabilityDonId,proto3" json:"capability_don_id,omitempty"` + CallerDonId string `protobuf:"bytes,8,opt,name=caller_don_id,json=callerDonId,proto3" json:"caller_don_id,omitempty"` + Method string `protobuf:"bytes,9,opt,name=method,proto3" json:"method,omitempty"` + Error Error `protobuf:"varint,10,opt,name=error,proto3,enum=remote.Error" json:"error,omitempty"` + ErrorMsg string `protobuf:"bytes,11,opt,name=errorMsg,proto3" json:"errorMsg,omitempty"` + // payload contains a CapabilityRequest or CapabilityResponse + Payload []byte `protobuf:"bytes,12,opt,name=payload,proto3" json:"payload,omitempty"` + // Types that are assignable to Metadata: + // + // *MessageBody_TriggerRegistrationMetadata + // *MessageBody_TriggerEventMetadata + Metadata isMessageBody_Metadata `protobuf_oneof:"metadata"` +} + +func (x *MessageBody) Reset() { + *x = MessageBody{} + if protoimpl.UnsafeEnabled { + mi := &file_core_capabilities_remote_types_messages_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MessageBody) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MessageBody) ProtoMessage() {} + +func (x *MessageBody) ProtoReflect() protoreflect.Message { + mi := &file_core_capabilities_remote_types_messages_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MessageBody.ProtoReflect.Descriptor instead. +func (*MessageBody) Descriptor() ([]byte, []int) { + return file_core_capabilities_remote_types_messages_proto_rawDescGZIP(), []int{1} +} + +func (x *MessageBody) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *MessageBody) GetSender() []byte { + if x != nil { + return x.Sender + } + return nil +} + +func (x *MessageBody) GetReceiver() []byte { + if x != nil { + return x.Receiver + } + return nil +} + +func (x *MessageBody) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *MessageBody) GetMessageId() []byte { + if x != nil { + return x.MessageId + } + return nil +} + +func (x *MessageBody) GetCapabilityId() string { + if x != nil { + return x.CapabilityId + } + return "" +} + +func (x *MessageBody) GetCapabilityDonId() string { + if x != nil { + return x.CapabilityDonId + } + return "" +} + +func (x *MessageBody) GetCallerDonId() string { + if x != nil { + return x.CallerDonId + } + return "" +} + +func (x *MessageBody) GetMethod() string { + if x != nil { + return x.Method + } + return "" +} + +func (x *MessageBody) GetError() Error { + if x != nil { + return x.Error + } + return Error_OK +} + +func (x *MessageBody) GetErrorMsg() string { + if x != nil { + return x.ErrorMsg + } + return "" +} + +func (x *MessageBody) GetPayload() []byte { + if x != nil { + return x.Payload + } + return nil +} + +func (m *MessageBody) GetMetadata() isMessageBody_Metadata { + if m != nil { + return m.Metadata + } + return nil +} + +func (x *MessageBody) GetTriggerRegistrationMetadata() *TriggerRegistrationMetadata { + if x, ok := x.GetMetadata().(*MessageBody_TriggerRegistrationMetadata); ok { + return x.TriggerRegistrationMetadata + } + return nil +} + +func (x *MessageBody) GetTriggerEventMetadata() *TriggerEventMetadata { + if x, ok := x.GetMetadata().(*MessageBody_TriggerEventMetadata); ok { + return x.TriggerEventMetadata + } + return nil +} + +type isMessageBody_Metadata interface { + isMessageBody_Metadata() +} + +type MessageBody_TriggerRegistrationMetadata struct { + TriggerRegistrationMetadata *TriggerRegistrationMetadata `protobuf:"bytes,13,opt,name=trigger_registration_metadata,json=triggerRegistrationMetadata,proto3,oneof"` +} + +type MessageBody_TriggerEventMetadata struct { + TriggerEventMetadata *TriggerEventMetadata `protobuf:"bytes,14,opt,name=trigger_event_metadata,json=triggerEventMetadata,proto3,oneof"` +} + +func (*MessageBody_TriggerRegistrationMetadata) isMessageBody_Metadata() {} + +func (*MessageBody_TriggerEventMetadata) isMessageBody_Metadata() {} + +type TriggerRegistrationMetadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LastReceivedEventId string `protobuf:"bytes,1,opt,name=last_received_event_id,json=lastReceivedEventId,proto3" json:"last_received_event_id,omitempty"` +} + +func (x *TriggerRegistrationMetadata) Reset() { + *x = TriggerRegistrationMetadata{} + if protoimpl.UnsafeEnabled { + mi := &file_core_capabilities_remote_types_messages_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TriggerRegistrationMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TriggerRegistrationMetadata) ProtoMessage() {} + +func (x *TriggerRegistrationMetadata) ProtoReflect() protoreflect.Message { + mi := &file_core_capabilities_remote_types_messages_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TriggerRegistrationMetadata.ProtoReflect.Descriptor instead. +func (*TriggerRegistrationMetadata) Descriptor() ([]byte, []int) { + return file_core_capabilities_remote_types_messages_proto_rawDescGZIP(), []int{2} +} + +func (x *TriggerRegistrationMetadata) GetLastReceivedEventId() string { + if x != nil { + return x.LastReceivedEventId + } + return "" +} + +type TriggerEventMetadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TriggerEventId string `protobuf:"bytes,1,opt,name=trigger_event_id,json=triggerEventId,proto3" json:"trigger_event_id,omitempty"` + WorkflowIds []string `protobuf:"bytes,2,rep,name=workflow_ids,json=workflowIds,proto3" json:"workflow_ids,omitempty"` +} + +func (x *TriggerEventMetadata) Reset() { + *x = TriggerEventMetadata{} + if protoimpl.UnsafeEnabled { + mi := &file_core_capabilities_remote_types_messages_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TriggerEventMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TriggerEventMetadata) ProtoMessage() {} + +func (x *TriggerEventMetadata) ProtoReflect() protoreflect.Message { + mi := &file_core_capabilities_remote_types_messages_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TriggerEventMetadata.ProtoReflect.Descriptor instead. +func (*TriggerEventMetadata) Descriptor() ([]byte, []int) { + return file_core_capabilities_remote_types_messages_proto_rawDescGZIP(), []int{3} +} + +func (x *TriggerEventMetadata) GetTriggerEventId() string { + if x != nil { + return x.TriggerEventId + } + return "" +} + +func (x *TriggerEventMetadata) GetWorkflowIds() []string { + if x != nil { + return x.WorkflowIds + } + return nil +} + +type RemoteTriggerConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RegistrationRefreshMs uint32 `protobuf:"varint,1,opt,name=registrationRefreshMs,proto3" json:"registrationRefreshMs,omitempty"` + RegistrationExpiryMs uint32 `protobuf:"varint,2,opt,name=registrationExpiryMs,proto3" json:"registrationExpiryMs,omitempty"` + MinResponsesToAggregate uint32 `protobuf:"varint,3,opt,name=minResponsesToAggregate,proto3" json:"minResponsesToAggregate,omitempty"` + MessageExpiryMs uint32 `protobuf:"varint,4,opt,name=messageExpiryMs,proto3" json:"messageExpiryMs,omitempty"` +} + +func (x *RemoteTriggerConfig) Reset() { + *x = RemoteTriggerConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_core_capabilities_remote_types_messages_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RemoteTriggerConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoteTriggerConfig) ProtoMessage() {} + +func (x *RemoteTriggerConfig) ProtoReflect() protoreflect.Message { + mi := &file_core_capabilities_remote_types_messages_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoteTriggerConfig.ProtoReflect.Descriptor instead. +func (*RemoteTriggerConfig) Descriptor() ([]byte, []int) { + return file_core_capabilities_remote_types_messages_proto_rawDescGZIP(), []int{4} +} + +func (x *RemoteTriggerConfig) GetRegistrationRefreshMs() uint32 { + if x != nil { + return x.RegistrationRefreshMs + } + return 0 +} + +func (x *RemoteTriggerConfig) GetRegistrationExpiryMs() uint32 { + if x != nil { + return x.RegistrationExpiryMs + } + return 0 +} + +func (x *RemoteTriggerConfig) GetMinResponsesToAggregate() uint32 { + if x != nil { + return x.MinResponsesToAggregate + } + return 0 +} + +func (x *RemoteTriggerConfig) GetMessageExpiryMs() uint32 { + if x != nil { + return x.MessageExpiryMs + } + return 0 +} + +var File_core_capabilities_remote_types_messages_proto protoreflect.FileDescriptor + +var file_core_capabilities_remote_types_messages_proto_rawDesc = []byte{ + 0x0a, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, + 0x69, 0x65, 0x73, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x22, 0x3b, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, + 0x62, 0x6f, 0x64, 0x79, 0x22, 0xcd, 0x04, 0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x42, 0x6f, 0x64, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, + 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, + 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, + 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, + 0x23, 0x0a, 0x0d, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, + 0x74, 0x79, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, + 0x74, 0x79, 0x5f, 0x64, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0f, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6e, 0x49, 0x64, + 0x12, 0x22, 0x0a, 0x0d, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x64, 0x6f, 0x6e, 0x5f, 0x69, + 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x44, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x23, 0x0a, 0x05, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x72, 0x65, + 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x18, 0x0b, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x18, 0x0a, + 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, + 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x69, 0x0a, 0x1d, 0x74, 0x72, 0x69, 0x67, 0x67, + 0x65, 0x72, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, + 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x1b, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x12, 0x54, 0x0a, 0x16, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x5f, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0e, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x54, 0x72, 0x69, 0x67, + 0x67, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x48, 0x00, 0x52, 0x14, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x0a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x22, 0x52, 0x0a, 0x1b, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x12, 0x33, 0x0a, 0x16, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x63, 0x65, + 0x69, 0x76, 0x65, 0x64, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x13, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x63, 0x0a, 0x14, 0x54, 0x72, 0x69, 0x67, + 0x67, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x12, 0x28, 0x0a, 0x10, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x5f, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x72, 0x69, 0x67, + 0x67, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x6f, + 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x73, 0x22, 0xe3, 0x01, + 0x0a, 0x13, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x0a, 0x15, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x4d, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x15, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x4d, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x72, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x69, 0x72, + 0x79, 0x4d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x72, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x4d, 0x73, 0x12, + 0x38, 0x0a, 0x17, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x54, + 0x6f, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x17, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x54, 0x6f, + 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x4d, 0x73, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x78, 0x70, 0x69, 0x72, + 0x79, 0x4d, 0x73, 0x2a, 0x76, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x06, 0x0a, 0x02, + 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, + 0x4f, 0x4e, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x43, + 0x41, 0x50, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, + 0x55, 0x4e, 0x44, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, + 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x54, 0x49, + 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x54, 0x45, 0x52, + 0x4e, 0x41, 0x4c, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x05, 0x42, 0x20, 0x5a, 0x1e, 0x63, + 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, + 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_core_capabilities_remote_types_messages_proto_rawDescOnce sync.Once + file_core_capabilities_remote_types_messages_proto_rawDescData = file_core_capabilities_remote_types_messages_proto_rawDesc +) + +func file_core_capabilities_remote_types_messages_proto_rawDescGZIP() []byte { + file_core_capabilities_remote_types_messages_proto_rawDescOnce.Do(func() { + file_core_capabilities_remote_types_messages_proto_rawDescData = protoimpl.X.CompressGZIP(file_core_capabilities_remote_types_messages_proto_rawDescData) + }) + return file_core_capabilities_remote_types_messages_proto_rawDescData +} + +var file_core_capabilities_remote_types_messages_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_core_capabilities_remote_types_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_core_capabilities_remote_types_messages_proto_goTypes = []interface{}{ + (Error)(0), // 0: remote.Error + (*Message)(nil), // 1: remote.Message + (*MessageBody)(nil), // 2: remote.MessageBody + (*TriggerRegistrationMetadata)(nil), // 3: remote.TriggerRegistrationMetadata + (*TriggerEventMetadata)(nil), // 4: remote.TriggerEventMetadata + (*RemoteTriggerConfig)(nil), // 5: remote.RemoteTriggerConfig +} +var file_core_capabilities_remote_types_messages_proto_depIdxs = []int32{ + 0, // 0: remote.MessageBody.error:type_name -> remote.Error + 3, // 1: remote.MessageBody.trigger_registration_metadata:type_name -> remote.TriggerRegistrationMetadata + 4, // 2: remote.MessageBody.trigger_event_metadata:type_name -> remote.TriggerEventMetadata + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_core_capabilities_remote_types_messages_proto_init() } +func file_core_capabilities_remote_types_messages_proto_init() { + if File_core_capabilities_remote_types_messages_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_core_capabilities_remote_types_messages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Message); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_core_capabilities_remote_types_messages_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MessageBody); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_core_capabilities_remote_types_messages_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TriggerRegistrationMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_core_capabilities_remote_types_messages_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TriggerEventMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_core_capabilities_remote_types_messages_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RemoteTriggerConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_core_capabilities_remote_types_messages_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*MessageBody_TriggerRegistrationMetadata)(nil), + (*MessageBody_TriggerEventMetadata)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_core_capabilities_remote_types_messages_proto_rawDesc, + NumEnums: 1, + NumMessages: 5, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_core_capabilities_remote_types_messages_proto_goTypes, + DependencyIndexes: file_core_capabilities_remote_types_messages_proto_depIdxs, + EnumInfos: file_core_capabilities_remote_types_messages_proto_enumTypes, + MessageInfos: file_core_capabilities_remote_types_messages_proto_msgTypes, + }.Build() + File_core_capabilities_remote_types_messages_proto = out.File + file_core_capabilities_remote_types_messages_proto_rawDesc = nil + file_core_capabilities_remote_types_messages_proto_goTypes = nil + file_core_capabilities_remote_types_messages_proto_depIdxs = nil +} diff --git a/core/capabilities/remote/types/message.proto b/core/capabilities/remote/types/messages.proto similarity index 85% rename from core/capabilities/remote/types/message.proto rename to core/capabilities/remote/types/messages.proto index 4d0507fd1e0..a576e0e5fa1 100644 --- a/core/capabilities/remote/types/message.proto +++ b/core/capabilities/remote/types/messages.proto @@ -48,3 +48,10 @@ message TriggerEventMetadata { string trigger_event_id = 1; repeated string workflow_ids = 2; } + +message RemoteTriggerConfig { + uint32 registrationRefreshMs = 1; + uint32 registrationExpiryMs = 2; + uint32 minResponsesToAggregate = 3; + uint32 messageExpiryMs = 4; +} diff --git a/core/capabilities/remote/types/types.go b/core/capabilities/remote/types/types.go index a825c42be56..37d05174dfb 100644 --- a/core/capabilities/remote/types/types.go +++ b/core/capabilities/remote/types/types.go @@ -1,3 +1,7 @@ +// Note: the proto_path below directive ensures the generated protobuf's file descriptor has a fully +// qualified path, ensuring we avoid conflicts with other files called messages.proto +// +//go:generate protoc --proto_path=../../../../ --go_out=../../../../ --go_opt=paths=source_relative core/capabilities/remote/types/messages.proto package types import ( diff --git a/core/capabilities/syncer.go b/core/capabilities/syncer.go index 2361f60d8b4..ca55fe1ba8d 100644 --- a/core/capabilities/syncer.go +++ b/core/capabilities/syncer.go @@ -2,36 +2,46 @@ package capabilities import ( "context" - "encoding/hex" + "errors" "fmt" "math/big" "slices" + "strings" "sync" "time" + "google.golang.org/protobuf/proto" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/capabilities/datastreams" "github.com/smartcontractkit/chainlink-common/pkg/capabilities/triggers" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/types/core" - "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/target" "github.com/smartcontractkit/libocr/ragep2p" ragetypes "github.com/smartcontractkit/libocr/ragep2p/types" "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/target" remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" "github.com/smartcontractkit/chainlink/v2/core/capabilities/streams" + kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/keystone_capability_registry" "github.com/smartcontractkit/chainlink/v2/core/logger" p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" ) +type reader interface { + state(ctx context.Context) (state, error) +} + type registrySyncer struct { peerWrapper p2ptypes.PeerWrapper registry core.CapabilitiesRegistry dispatcher remotetypes.Dispatcher + stopCh services.StopChan subServices []services.Service networkSetup HardcodedDonNetworkSetup + reader reader wg sync.WaitGroup lggr logger.Logger @@ -39,6 +49,10 @@ type registrySyncer struct { var _ services.Service = ®istrySyncer{} +var ( + defaultTickInterval = 12 * time.Second +) + var defaultStreamConfig = p2ptypes.StreamConfig{ IncomingMessageBufferSize: 1000000, OutgoingMessageBufferSize: 1000000, @@ -53,172 +67,652 @@ var defaultStreamConfig = p2ptypes.StreamConfig{ }, } -const maxRetryCount = 60 - // RegistrySyncer updates local Registry to match its onchain counterpart -func NewRegistrySyncer(peerWrapper p2ptypes.PeerWrapper, registry core.CapabilitiesRegistry, dispatcher remotetypes.Dispatcher, lggr logger.Logger, - networkSetup HardcodedDonNetworkSetup) *registrySyncer { +func NewRegistrySyncer( + peerWrapper p2ptypes.PeerWrapper, + registry core.CapabilitiesRegistry, + dispatcher remotetypes.Dispatcher, + lggr logger.Logger, + networkSetup HardcodedDonNetworkSetup, + relayer contractReaderFactory, + registryAddress string, +) (*registrySyncer, error) { + stopCh := make(services.StopChan) + ctx, _ := stopCh.NewCtx() + reader, err := newRemoteRegistryReader(ctx, relayer, registryAddress) + if err != nil { + return nil, err + } + + return newRegistrySyncer( + stopCh, + peerWrapper, + registry, + dispatcher, + lggr.Named("RegistrySyncer"), + networkSetup, + reader, + ), nil +} + +func newRegistrySyncer( + stopCh services.StopChan, + peerWrapper p2ptypes.PeerWrapper, + registry core.CapabilitiesRegistry, + dispatcher remotetypes.Dispatcher, + lggr logger.Logger, + networkSetup HardcodedDonNetworkSetup, + reader reader, +) *registrySyncer { return ®istrySyncer{ + stopCh: stopCh, peerWrapper: peerWrapper, registry: registry, dispatcher: dispatcher, networkSetup: networkSetup, lggr: lggr, + reader: reader, } } func (s *registrySyncer) Start(ctx context.Context) error { + // NOTE: Decrease wg.Add and uncomment line 124 below + // this for a hardcoded syncer s.wg.Add(1) - go s.launch(context.Background()) + // go s.launch() + go s.syncLoop() return nil } -// NOTE: this implementation of the Syncer is temporary and will be replaced by one -// that reads the configuration from chain (KS-117). -func (s *registrySyncer) launch(ctx context.Context) { +func (s *registrySyncer) syncLoop() { defer s.wg.Done() - capId := "streams-trigger@1.0.0" - triggerInfo, err := capabilities.NewRemoteCapabilityInfo( - capId, - capabilities.CapabilityTypeTrigger, - "Remote Trigger", - &s.networkSetup.TriggerCapabilityDonInfo, - ) + + ctx, cancel := s.stopCh.NewCtx() + defer cancel() + + ticker := time.NewTicker(defaultTickInterval) + defer ticker.Stop() + + // Sync for a first time outside the loop; this means we'll start a remote + // sync immediately once spinning up syncLoop, as by default a ticker will + // fire for the first time at T+N, where N is the interval. + s.lggr.Debug("starting initial sync with remote registry") + err := s.sync(ctx) if err != nil { - s.lggr.Errorw("failed to create capability info for streams-trigger", "error", err) - return + s.lggr.Errorw("failed to sync with remote registry", "error", err) } - targetCapId := "write_ethereum-testnet-sepolia@1.0.0" - targetInfo, err := capabilities.NewRemoteCapabilityInfo( - targetCapId, - capabilities.CapabilityTypeTarget, - "Remote Target", - &s.networkSetup.TargetCapabilityDonInfo, - ) + for { + select { + case <-s.stopCh: + return + case <-ticker.C: + s.lggr.Debug("starting regular sync with the remote registry") + err := s.sync(ctx) + if err != nil { + s.lggr.Errorw("failed to sync with remote registry", "error", err) + } + } + } +} + +func (s *registrySyncer) sync(ctx context.Context) error { + readerState, err := s.reader.state(ctx) if err != nil { - s.lggr.Errorw("failed to create capability info for write_ethereum-testnet-sepolia", "error", err) - return + return fmt.Errorf("failed to sync with remote registry: %w", err) + } + + // Let's start by updating the list of Peers + // We do this by creating a new entry for each node belonging + // to a public DON. + // We also add the hardcoded peers determined by the NetworkSetup. + allPeers := make(map[ragetypes.PeerID]p2ptypes.StreamConfig) + // TODO: Remove this when we're no longer hard-coding + // a `networkSetup`. + for p, cfg := range s.networkSetup.allPeers { + allPeers[p] = cfg } - myId := s.peerWrapper.GetPeer().ID() - config := remotetypes.RemoteTriggerConfig{ - RegistrationRefreshMs: 20000, - RegistrationExpiryMs: 60000, - MinResponsesToAggregate: uint32(s.networkSetup.TriggerCapabilityDonInfo.F) + 1, + publicDONs := []kcr.CapabilityRegistryDONInfo{} + for _, d := range readerState.IDsToDONs { + if !d.IsPublic { + continue + } + + publicDONs = append(publicDONs, d) + + for _, nid := range d.NodeP2PIds { + allPeers[nid] = defaultStreamConfig + } } - err = s.peerWrapper.GetPeer().UpdateConnections(s.networkSetup.allPeers) + + // TODO: be a bit smarter about who we connect to; we should ideally only + // be connecting to peers when we need to. + // https://smartcontract-it.atlassian.net/browse/KS-330 + err = s.peerWrapper.GetPeer().UpdateConnections(allPeers) if err != nil { - s.lggr.Errorw("failed to update connections", "error", err) - return - } - if s.networkSetup.IsWorkflowDon(myId) { - s.lggr.Info("member of a workflow DON - starting remote subscribers") - codec := streams.NewCodec(s.lggr) - aggregator := triggers.NewMercuryRemoteAggregator(codec, hexStringsToBytes(s.networkSetup.triggerDonSigners), int(s.networkSetup.TriggerCapabilityDonInfo.F+1), s.lggr) - triggerCap := remote.NewTriggerSubscriber(config, triggerInfo, s.networkSetup.TriggerCapabilityDonInfo, s.networkSetup.WorkflowsDonInfo, s.dispatcher, aggregator, s.lggr) - err = s.registry.Add(ctx, triggerCap) - if err != nil { - s.lggr.Errorw("failed to add remote trigger capability to registry", "error", err) - return + return fmt.Errorf("failed to update peer connections: %w", err) + } + + // Next, we need to split the DONs into the following: + // - workflow DONs the current node is a part of. + // These will need remote shims to all remote capabilities on other DONs. + // + // We'll also construct a set to record what DONs the current node is a part of, + // regardless of any modifiers (public/acceptsWorkflows etc). + myID := s.peerWrapper.GetPeer().ID() + myWorkflowDONs := []kcr.CapabilityRegistryDONInfo{} + remoteWorkflowDONs := []kcr.CapabilityRegistryDONInfo{} + myDONs := map[uint32]bool{} + for _, d := range readerState.IDsToDONs { + for _, peerID := range d.NodeP2PIds { + if peerID == myID { + myDONs[d.Id] = true + } } - err = s.dispatcher.SetReceiver(capId, s.networkSetup.TriggerCapabilityDonInfo.ID, triggerCap) - if err != nil { - s.lggr.Errorw("workflow DON failed to set receiver for trigger", "capabilityId", capId, "donId", s.networkSetup.TriggerCapabilityDonInfo.ID, "error", err) - return + + if d.AcceptsWorkflows { + if myDONs[d.Id] { + myWorkflowDONs = append(myWorkflowDONs, d) + } else { + remoteWorkflowDONs = append(remoteWorkflowDONs, d) + } } - s.subServices = append(s.subServices, triggerCap) + } - s.lggr.Info("member of a workflow DON - starting remote targets") - targetCap := target.NewClient(targetInfo, s.networkSetup.WorkflowsDonInfo, s.dispatcher, 60*time.Second, s.lggr) - err = s.registry.Add(ctx, targetCap) - if err != nil { - s.lggr.Errorw("failed to add remote target capability to registry", "error", err) - return + // - remote capability DONs (with IsPublic = true) the current node is a part of. + // These need server-side shims. + myCapabilityDONs := []kcr.CapabilityRegistryDONInfo{} + remoteCapabilityDONs := []kcr.CapabilityRegistryDONInfo{} + for _, d := range publicDONs { + if len(d.CapabilityConfigurations) > 0 { + if myDONs[d.Id] { + myCapabilityDONs = append(myCapabilityDONs, d) + } else { + remoteCapabilityDONs = append(remoteCapabilityDONs, d) + } } - err = s.dispatcher.SetReceiver(targetCapId, s.networkSetup.TargetCapabilityDonInfo.ID, targetCap) - if err != nil { - s.lggr.Errorw("workflow DON failed to set receiver for target", "capabilityId", capId, "donId", s.networkSetup.TargetCapabilityDonInfo.ID, "error", err) - return + } + + // Now, if my node is a workflow DON, let's setup any shims + // to external capabilities. + if len(myWorkflowDONs) > 0 { + myDON := myWorkflowDONs[0] + + // TODO: this is a bit nasty; figure out how best to handle this. + if len(myWorkflowDONs) > 1 { + s.lggr.Warn("node is part of more than one workflow DON; assigning first DON as caller") + } + + for _, rcd := range remoteCapabilityDONs { + err := s.addRemoteCapabilities(ctx, myDON, rcd, readerState) + if err != nil { + return err + } } - s.subServices = append(s.subServices, targetCap) } - if s.networkSetup.IsTriggerDon(myId) { - s.lggr.Info("member of a capability DON - starting remote publishers") - /*{ - // ---- This is for local tests only, until a full-blown Syncer is implemented - // ---- Normally this is set up asynchronously (by the Relayer + job specs in Mercury's case) - localTrigger := triggers.NewMercuryTriggerService(1000, s.lggr) - mockMercuryDataProducer := NewMockMercuryDataProducer(localTrigger, s.lggr) - err = s.registry.Add(ctx, localTrigger) + // Finally, if I'm a capability DON, let's enable external access + // to the capability. + if len(myCapabilityDONs) > 0 { + for _, mcd := range myCapabilityDONs { + err := s.enableExternalAccess(ctx, myID, mcd, readerState, remoteWorkflowDONs) if err != nil { - s.lggr.Errorw("failed to add local trigger capability to registry", "error", err) return err } - s.subServices = append(s.subServices, localTrigger) - s.subServices = append(s.subServices, mockMercuryDataProducer) - // ---- - }*/ - - count := 0 - for { - count++ - if count > maxRetryCount { - s.lggr.Error("failed to get Streams Trigger from the Registry") - return + } + } + + return nil +} + +func signersFor(don kcr.CapabilityRegistryDONInfo, state state) ([][]byte, error) { + s := [][]byte{} + for _, nodeID := range don.NodeP2PIds { + node, ok := state.IDsToNodes[nodeID] + if !ok { + return nil, fmt.Errorf("could not find node for id %s", nodeID) + } + + // NOTE: the capability registry stores signers as [32]byte, + // but we only need the first [20], as the rest is padded. + s = append(s, node.Signer[0:20]) + } + + return s, nil +} + +func toDONInfo(don kcr.CapabilityRegistryDONInfo) *capabilities.DON { + peerIDs := []p2ptypes.PeerID{} + for _, p := range don.NodeP2PIds { + peerIDs = append(peerIDs, p) + } + + return &capabilities.DON{ + ID: fmt.Sprint(don.Id), + Members: peerIDs, + F: don.F, + } +} + +func toCapabilityType(capabilityType uint8) capabilities.CapabilityType { + switch capabilityType { + case 0: + return capabilities.CapabilityTypeTrigger + case 1: + return capabilities.CapabilityTypeAction + case 2: + return capabilities.CapabilityTypeConsensus + case 3: + return capabilities.CapabilityTypeTarget + default: + // Not found + return capabilities.CapabilityType(-1) + } +} + +func (s *registrySyncer) addRemoteCapabilities(ctx context.Context, myDON kcr.CapabilityRegistryDONInfo, remoteDON kcr.CapabilityRegistryDONInfo, state state) error { + for _, c := range remoteDON.CapabilityConfigurations { + capability, ok := state.IDsToCapabilities[c.CapabilityId] + if !ok { + return fmt.Errorf("could not find capability matching id %s", c.CapabilityId) + } + + switch toCapabilityType(capability.CapabilityType) { + case capabilities.CapabilityTypeTrigger: + newTriggerFn := func(info capabilities.CapabilityInfo) (capabilityService, error) { + if !strings.HasPrefix(info.ID, "streams-trigger") { + return nil, errors.New("not supported: trigger capability does not have id = streams-trigger") + } + + codec := streams.NewCodec(s.lggr) + + signers, err := signersFor(remoteDON, state) + if err != nil { + return nil, err + } + + aggregator := triggers.NewMercuryRemoteAggregator( + codec, + signers, + int(remoteDON.F+1), + s.lggr, + ) + cfg := &remotetypes.RemoteTriggerConfig{} + cfg.ApplyDefaults() + err = proto.Unmarshal(c.Config, cfg) + if err != nil { + return nil, err + } + // TODO: We need to implement a custom, Mercury-specific + // aggregator here, because there is no guarantee that + // all trigger events in the workflow will have the same + // payloads. As a workaround, we validate the signatures. + // When this is solved, we can move to a generic aggregator + // and remove this. + triggerCap := remote.NewTriggerSubscriber( + cfg, + info, + *toDONInfo(remoteDON), + *toDONInfo(myDON), + s.dispatcher, + aggregator, + s.lggr, + ) + return triggerCap, nil } - underlying, err2 := s.registry.GetTrigger(ctx, capId) - if err2 != nil { - // NOTE: it's possible that the jobs are not launched yet at this moment. - // If not found yet, Syncer won't add to Registry but retry on the next tick. - s.lggr.Infow("trigger not found yet ...", "capabilityId", capId, "error", err2) - time.Sleep(1 * time.Second) - continue + err := s.addToRegistryAndSetDispatcher(ctx, capability, remoteDON, newTriggerFn) + if err != nil { + return fmt.Errorf("failed to add trigger shim: %w", err) } - workflowDONs := map[string]capabilities.DON{ - s.networkSetup.WorkflowsDonInfo.ID: s.networkSetup.WorkflowsDonInfo, + case capabilities.CapabilityTypeAction: + s.lggr.Warn("no remote client configured for capability type action, skipping configuration") + case capabilities.CapabilityTypeConsensus: + s.lggr.Warn("no remote client configured for capability type consensus, skipping configuration") + case capabilities.CapabilityTypeTarget: + newTargetFn := func(info capabilities.CapabilityInfo) (capabilityService, error) { + client := target.NewClient( + info, + *toDONInfo(myDON), + s.dispatcher, + defaultTargetRequestTimeout, + s.lggr, + ) + return client, nil } - triggerCap := remote.NewTriggerPublisher(config, underlying, triggerInfo, s.networkSetup.TriggerCapabilityDonInfo, workflowDONs, s.dispatcher, s.lggr) - err = s.dispatcher.SetReceiver(capId, s.networkSetup.TriggerCapabilityDonInfo.ID, triggerCap) + + err := s.addToRegistryAndSetDispatcher(ctx, capability, remoteDON, newTargetFn) if err != nil { - s.lggr.Errorw("capability DON failed to set receiver", "capabilityId", capId, "donId", s.networkSetup.TriggerCapabilityDonInfo.ID, "error", err) - return + return fmt.Errorf("failed to add target shim: %w", err) } - s.subServices = append(s.subServices, triggerCap) - break + default: + s.lggr.Warnf("unknown capability type, skipping configuration: %+v", capability) } } - if s.networkSetup.IsTargetDon(myId) { - s.lggr.Info("member of a target DON - starting remote shims") - underlying, err2 := s.registry.GetTarget(ctx, targetCapId) - if err2 != nil { - s.lggr.Errorw("target not found yet", "capabilityId", targetCapId, "error", err2) - return + return nil +} + +type capabilityService interface { + capabilities.BaseCapability + remotetypes.Receiver + services.Service +} + +func (s *registrySyncer) addToRegistryAndSetDispatcher(ctx context.Context, capabilityInfo kcr.CapabilityRegistryCapability, don kcr.CapabilityRegistryDONInfo, newCapFn func(info capabilities.CapabilityInfo) (capabilityService, error)) error { + fullCapID := fmt.Sprintf("%s@%s", capabilityInfo.LabelledName, capabilityInfo.Version) + info, err := capabilities.NewRemoteCapabilityInfo( + fullCapID, + toCapabilityType(capabilityInfo.CapabilityType), + fmt.Sprintf("Remote Capability for %s", fullCapID), + toDONInfo(don), + ) + if err != nil { + return err + } + s.lggr.Debugw("Adding remote capability to registry", "id", info.ID, "don", info.DON) + capability, err := newCapFn(info) + if err != nil { + return err + } + + err = s.registry.Add(ctx, capability) + if err != nil { + // If the capability already exists, then it's either local + // or we've handled this in a previous syncer iteration, + // let's skip and move on to other capabilities. + if errors.Is(err, ErrCapabilityAlreadyExists) { + return nil } - workflowDONs := map[string]capabilities.DON{ - s.networkSetup.WorkflowsDonInfo.ID: s.networkSetup.WorkflowsDonInfo, + + return err + } + + err = s.dispatcher.SetReceiver( + fullCapID, + fmt.Sprint(don.Id), + capability, + ) + if err != nil { + return err + } + s.lggr.Debugw("Setting receiver for capability", "id", fullCapID, "donID", don.Id) + err = capability.Start(ctx) + if err != nil { + return err + } + s.subServices = append(s.subServices, capability) + return nil +} + +var ( + defaultTargetRequestTimeout = time.Minute +) + +func (s *registrySyncer) enableExternalAccess(ctx context.Context, myPeerID p2ptypes.PeerID, don kcr.CapabilityRegistryDONInfo, state state, remoteWorkflowDONs []kcr.CapabilityRegistryDONInfo) error { + idsToDONs := map[string]capabilities.DON{} + for _, d := range remoteWorkflowDONs { + idsToDONs[fmt.Sprint(d.Id)] = *toDONInfo(d) + } + + for _, c := range don.CapabilityConfigurations { + capability, ok := state.IDsToCapabilities[c.CapabilityId] + if !ok { + return fmt.Errorf("could not find capability matching id %s", c.CapabilityId) } - targetCap := target.NewServer(myId, underlying, targetInfo, *targetInfo.DON, workflowDONs, s.dispatcher, 60*time.Second, s.lggr) - err = s.dispatcher.SetReceiver(targetCapId, s.networkSetup.TargetCapabilityDonInfo.ID, targetCap) - if err != nil { - s.lggr.Errorw("capability DON failed to set receiver", "capabilityId", capId, "donId", s.networkSetup.TargetCapabilityDonInfo.ID, "error", err) - return + + switch toCapabilityType(capability.CapabilityType) { + case capabilities.CapabilityTypeTrigger: + newTriggerPublisher := func(capability capabilities.BaseCapability, info capabilities.CapabilityInfo) (receiverService, error) { + cfg := &remotetypes.RemoteTriggerConfig{} + cfg.ApplyDefaults() + err := proto.Unmarshal(c.Config, cfg) + if err != nil { + return nil, err + } + publisher := remote.NewTriggerPublisher( + cfg, + capability.(capabilities.TriggerCapability), + info, + *toDONInfo(don), + idsToDONs, + s.dispatcher, + s.lggr, + ) + return publisher, nil + } + + err := s.addReceiver(ctx, capability, don, newTriggerPublisher) + if err != nil { + return fmt.Errorf("failed to add server-side receiver: %w", err) + } + case capabilities.CapabilityTypeAction: + s.lggr.Warn("no remote client configured for capability type action, skipping configuration") + case capabilities.CapabilityTypeConsensus: + s.lggr.Warn("no remote client configured for capability type consensus, skipping configuration") + case capabilities.CapabilityTypeTarget: + newTargetServer := func(capability capabilities.BaseCapability, info capabilities.CapabilityInfo) (receiverService, error) { + return target.NewServer( + myPeerID, + capability.(capabilities.TargetCapability), + info, + *toDONInfo(don), + idsToDONs, + s.dispatcher, + defaultTargetRequestTimeout, + s.lggr, + ), nil + } + + err := s.addReceiver(ctx, capability, don, newTargetServer) + if err != nil { + return fmt.Errorf("failed to add server-side receiver: %w", err) + } + default: + s.lggr.Warnf("unknown capability type, skipping configuration: %+v", capability) } - s.subServices = append(s.subServices, targetCap) } - // NOTE: temporary service start - should be managed by capability creation - for _, srv := range s.subServices { - err = srv.Start(ctx) - if err != nil { - s.lggr.Errorw("failed to start remote trigger caller", "error", err) - return - } + return nil +} + +type receiverService interface { + services.Service + remotetypes.Receiver +} + +func (s *registrySyncer) addReceiver(ctx context.Context, capability kcr.CapabilityRegistryCapability, don kcr.CapabilityRegistryDONInfo, newReceiverFn func(capability capabilities.BaseCapability, info capabilities.CapabilityInfo) (receiverService, error)) error { + fullCapID := fmt.Sprintf("%s@%s", capability.LabelledName, capability.Version) + info, err := capabilities.NewRemoteCapabilityInfo( + fullCapID, + toCapabilityType(capability.CapabilityType), + fmt.Sprintf("Remote Capability for %s", fullCapID), + toDONInfo(don), + ) + if err != nil { + return err + } + underlying, err := s.registry.Get(ctx, fullCapID) + if err != nil { + return err + } + + receiver, err := newReceiverFn(underlying, info) + if err != nil { + return err + } + + s.lggr.Debugw("Enabling external access for capability", "id", fullCapID, "donID", don.Id) + err = s.dispatcher.SetReceiver(fullCapID, fmt.Sprint(don.Id), receiver) + if err != nil { + return err } - s.lggr.Info("registry syncer started") + + err = receiver.Start(ctx) + if err != nil { + return err + } + + s.subServices = append(s.subServices, receiver) + return nil } +//func hexStringsToBytes(strs []string) (res [][]byte) { +// for _, s := range strs { +// b, _ := hex.DecodeString(s[2:]) +// res = append(res, b) +// } +// return res +//} + +//const maxRetryCount = 60 + +//// NOTE: this implementation of the Syncer is temporary and will be replaced by one +//// that reads the configuration from chain (KS-117). +//func (s *registrySyncer) launch() { +// ctx, _ := s.stopCh.NewCtx() +// defer s.wg.Done() +// capId := "streams-trigger@1.0.0" +// triggerInfo, err := capabilities.NewRemoteCapabilityInfo( +// capId, +// capabilities.CapabilityTypeTrigger, +// "Remote Trigger", +// &s.networkSetup.TriggerCapabilityDonInfo, +// ) +// if err != nil { +// s.lggr.Errorw("failed to create capability info for streams-trigger", "error", err) +// return +// } +// +// targetCapId := "write_ethereum-testnet-sepolia@1.0.0" +// targetInfo, err := capabilities.NewRemoteCapabilityInfo( +// targetCapId, +// capabilities.CapabilityTypeTarget, +// "Remote Target", +// &s.networkSetup.TargetCapabilityDonInfo, +// ) +// if err != nil { +// s.lggr.Errorw("failed to create capability info for write_ethereum-testnet-sepolia", "error", err) +// return +// } +// +// myId := s.peerWrapper.GetPeer().ID() +// config := &remotetypes.RemoteTriggerConfig{ +// RegistrationRefreshMs: 20000, +// RegistrationExpiryMs: 60000, +// MinResponsesToAggregate: uint32(s.networkSetup.TriggerCapabilityDonInfo.F) + 1, +// } +// err = s.peerWrapper.GetPeer().UpdateConnections(s.networkSetup.allPeers) +// if err != nil { +// s.lggr.Errorw("failed to update connections", "error", err) +// return +// } +// if s.networkSetup.IsWorkflowDon(myId) { +// s.lggr.Info("member of a workflow DON - starting remote subscribers") +// codec := streams.NewCodec(s.lggr) +// aggregator := triggers.NewMercuryRemoteAggregator(codec, hexStringsToBytes(s.networkSetup.triggerDonSigners), int(s.networkSetup.TriggerCapabilityDonInfo.F+1), s.lggr) +// triggerCap := remote.NewTriggerSubscriber(config, triggerInfo, s.networkSetup.TriggerCapabilityDonInfo, s.networkSetup.WorkflowsDonInfo, s.dispatcher, aggregator, s.lggr) +// err = s.registry.Add(ctx, triggerCap) +// if err != nil { +// s.lggr.Errorw("failed to add remote trigger capability to registry", "error", err) +// return +// } +// err = s.dispatcher.SetReceiver(capId, s.networkSetup.TriggerCapabilityDonInfo.ID, triggerCap) +// if err != nil { +// s.lggr.Errorw("workflow DON failed to set receiver for trigger", "capabilityId", capId, "donId", s.networkSetup.TriggerCapabilityDonInfo.ID, "error", err) +// return +// } +// s.subServices = append(s.subServices, triggerCap) +// +// s.lggr.Info("member of a workflow DON - starting remote targets") +// targetCap := target.NewClient(targetInfo, s.networkSetup.WorkflowsDonInfo, s.dispatcher, 60*time.Second, s.lggr) +// err = s.registry.Add(ctx, targetCap) +// if err != nil { +// s.lggr.Errorw("failed to add remote target capability to registry", "error", err) +// return +// } +// err = s.dispatcher.SetReceiver(targetCapId, s.networkSetup.TargetCapabilityDonInfo.ID, targetCap) +// if err != nil { +// s.lggr.Errorw("workflow DON failed to set receiver for target", "capabilityId", capId, "donId", s.networkSetup.TargetCapabilityDonInfo.ID, "error", err) +// return +// } +// s.subServices = append(s.subServices, targetCap) +// } +// if s.networkSetup.IsTriggerDon(myId) { +// s.lggr.Info("member of a capability DON - starting remote publishers") +// +// /*{ +// // ---- This is for local tests only, until a full-blown Syncer is implemented +// // ---- Normally this is set up asynchronously (by the Relayer + job specs in Mercury's case) +// localTrigger := triggers.NewMercuryTriggerService(1000, s.lggr) +// mockMercuryDataProducer := NewMockMercuryDataProducer(localTrigger, s.lggr) +// err = s.registry.Add(ctx, localTrigger) +// if err != nil { +// s.lggr.Errorw("failed to add local trigger capability to registry", "error", err) +// return err +// } +// s.subServices = append(s.subServices, localTrigger) +// s.subServices = append(s.subServices, mockMercuryDataProducer) +// // ---- +// }*/ +// +// count := 0 +// for { +// count++ +// if count > maxRetryCount { +// s.lggr.Error("failed to get Streams Trigger from the Registry") +// return +// } +// underlying, err2 := s.registry.GetTrigger(ctx, capId) +// if err2 != nil { +// // NOTE: it's possible that the jobs are not launched yet at this moment. +// // If not found yet, Syncer won't add to Registry but retry on the next tick. +// s.lggr.Infow("trigger not found yet ...", "capabilityId", capId, "error", err2) +// time.Sleep(1 * time.Second) +// continue +// } +// workflowDONs := map[string]capabilities.DON{ +// s.networkSetup.WorkflowsDonInfo.ID: s.networkSetup.WorkflowsDonInfo, +// } +// triggerCap := remote.NewTriggerPublisher(config, underlying, triggerInfo, s.networkSetup.TriggerCapabilityDonInfo, workflowDONs, s.dispatcher, s.lggr) +// err = s.dispatcher.SetReceiver(capId, s.networkSetup.TriggerCapabilityDonInfo.ID, triggerCap) +// if err != nil { +// s.lggr.Errorw("capability DON failed to set receiver", "capabilityId", capId, "donId", s.networkSetup.TriggerCapabilityDonInfo.ID, "error", err) +// return +// } +// s.subServices = append(s.subServices, triggerCap) +// break +// } +// } +// if s.networkSetup.IsTargetDon(myId) { +// s.lggr.Info("member of a target DON - starting remote shims") +// underlying, err2 := s.registry.GetTarget(ctx, targetCapId) +// if err2 != nil { +// s.lggr.Errorw("target not found yet", "capabilityId", targetCapId, "error", err2) +// return +// } +// workflowDONs := map[string]capabilities.DON{ +// s.networkSetup.WorkflowsDonInfo.ID: s.networkSetup.WorkflowsDonInfo, +// } +// targetCap := target.NewServer(myId, underlying, targetInfo, *targetInfo.DON, workflowDONs, s.dispatcher, 60*time.Second, s.lggr) +// err = s.dispatcher.SetReceiver(targetCapId, s.networkSetup.TargetCapabilityDonInfo.ID, targetCap) +// if err != nil { +// s.lggr.Errorw("capability DON failed to set receiver", "capabilityId", capId, "donId", s.networkSetup.TargetCapabilityDonInfo.ID, "error", err) +// return +// } +// s.subServices = append(s.subServices, targetCap) +// } +// // NOTE: temporary service start - should be managed by capability creation +// for _, srv := range s.subServices { +// err = srv.Start(ctx) +// if err != nil { +// s.lggr.Errorw("failed to start remote trigger caller", "error", err) +// return +// } +// } +// s.lggr.Info("registry syncer started") +//} + func (s *registrySyncer) Close() error { + close(s.stopCh) s.wg.Wait() for _, subService := range s.subServices { err := subService.Close() @@ -416,11 +910,3 @@ func (m *mockMercuryDataProducer) Ready() error { func (m *mockMercuryDataProducer) Name() string { return "mockMercuryDataProducer" } - -func hexStringsToBytes(strs []string) (res [][]byte) { - for _, s := range strs { - b, _ := hex.DecodeString(s[2:]) - res = append(res, b) - } - return res -} diff --git a/core/capabilities/syncer_test.go b/core/capabilities/syncer_test.go index a654f303a95..c0eaa26a5b8 100644 --- a/core/capabilities/syncer_test.go +++ b/core/capabilities/syncer_test.go @@ -1,18 +1,25 @@ -package capabilities_test +package capabilities import ( + "context" + "fmt" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ragetypes "github.com/smartcontractkit/libocr/ragep2p/types" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink-common/pkg/services" commonMocks "github.com/smartcontractkit/chainlink-common/pkg/types/mocks" - coreCapabilities "github.com/smartcontractkit/chainlink/v2/core/capabilities" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" remoteMocks "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types/mocks" + kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/keystone_capability_registry" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types/mocks" ) @@ -28,13 +35,575 @@ func TestSyncer_CleanStartClose(t *testing.T) { wrapper := mocks.NewPeerWrapper(t) wrapper.On("GetPeer").Return(peer) registry := commonMocks.NewCapabilitiesRegistry(t) - registry.On("Add", mock.Anything, mock.Anything).Return(nil) dispatcher := remoteMocks.NewDispatcher(t) - dispatcher.On("SetReceiver", mock.Anything, mock.Anything, mock.Anything).Return(nil) - networkSetup, err := coreCapabilities.NewHardcodedDonNetworkSetup() + networkSetup, err := NewHardcodedDonNetworkSetup() + require.NoError(t, err) + mr := &mockReader{} + syncer := newRegistrySyncer(make(services.StopChan), wrapper, registry, dispatcher, lggr, networkSetup, mr) require.NoError(t, err) - syncer := coreCapabilities.NewRegistrySyncer(wrapper, registry, dispatcher, lggr, networkSetup) require.NoError(t, syncer.Start(ctx)) require.NoError(t, syncer.Close()) } + +type mockReader struct { + s state + err error +} + +func (m mockReader) state(ctx context.Context) (state, error) { + return m.s, m.err +} + +type mockTrigger struct { + capabilities.CapabilityInfo +} + +func (m *mockTrigger) RegisterTrigger(ctx context.Context, request capabilities.CapabilityRequest) (<-chan capabilities.CapabilityResponse, error) { + return nil, nil +} + +func (m *mockTrigger) UnregisterTrigger(ctx context.Context, request capabilities.CapabilityRequest) error { + return nil +} + +func newMockTrigger(info capabilities.CapabilityInfo) *mockTrigger { + return &mockTrigger{CapabilityInfo: info} +} + +type mockCapability struct { + capabilities.CapabilityInfo +} + +func (m *mockCapability) Execute(ctx context.Context, req capabilities.CapabilityRequest) (<-chan capabilities.CapabilityResponse, error) { + return nil, nil +} + +func (m *mockCapability) RegisterToWorkflow(ctx context.Context, request capabilities.RegisterToWorkflowRequest) error { + return nil +} + +func (m *mockCapability) UnregisterFromWorkflow(ctx context.Context, request capabilities.UnregisterFromWorkflowRequest) error { + return nil +} + +func TestSyncer_WiresUpExternalCapabilities(t *testing.T) { + ctx := tests.Context(t) + lggr := logger.TestLogger(t) + registry := NewRegistry(lggr) + dispatcher := remoteMocks.NewDispatcher(t) + + var pid ragetypes.PeerID + err := pid.UnmarshalText([]byte("12D3KooWBCF1XT5Wi8FzfgNCqRL76Swv8TRU3TiD4QiJm8NMNX7N")) + require.NoError(t, err) + peer := mocks.NewPeer(t) + peer.On("UpdateConnections", mock.Anything).Return(nil) + peer.On("ID").Return(pid) + wrapper := mocks.NewPeerWrapper(t) + wrapper.On("GetPeer").Return(peer) + + nodes := [][32]byte{ + pid, + randomWord(), + randomWord(), + randomWord(), + } + + fullTriggerCapID := "streams-trigger@1.0.0" + mt := newMockTrigger(capabilities.MustNewCapabilityInfo( + fullTriggerCapID, + capabilities.CapabilityTypeTrigger, + "streams trigger", + )) + require.NoError(t, registry.Add(ctx, mt)) + + fullTargetID := "write-chain_evm_1@1.0.0" + mtarg := &mockCapability{ + CapabilityInfo: capabilities.MustNewCapabilityInfo( + fullTargetID, + capabilities.CapabilityTypeTarget, + "write chain", + ), + } + require.NoError(t, registry.Add(ctx, mtarg)) + + triggerCapID := randomWord() + targetCapID := randomWord() + dID := uint32(1) + // The below state describes a Workflow DON (AcceptsWorkflows = true), + // which exposes the streams-trigger and write_chain capabilities. + // We expect a publisher to be wired up with this configuration, and + // no entries should be added to the registry. + mr := &mockReader{ + s: state{ + IDsToDONs: map[donID]kcr.CapabilityRegistryDONInfo{ + donID(dID): { + Id: dID, + ConfigCount: uint32(0), + F: uint8(1), + IsPublic: true, + AcceptsWorkflows: true, + NodeP2PIds: nodes, + CapabilityConfigurations: []kcr.CapabilityRegistryCapabilityConfiguration{ + { + CapabilityId: triggerCapID, + Config: []byte(""), + }, + { + CapabilityId: targetCapID, + Config: []byte(""), + }, + }, + }, + }, + IDsToCapabilities: map[hashedCapabilityID]kcr.CapabilityRegistryCapability{ + triggerCapID: { + LabelledName: "streams-trigger", + Version: "1.0.0", + CapabilityType: 0, + }, + targetCapID: { + LabelledName: "write-chain_evm_1", + Version: "1.0.0", + CapabilityType: 3, + }, + }, + IDsToNodes: map[p2ptypes.PeerID]kcr.CapabilityRegistryNodeInfo{ + nodes[0]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: nodes[0], + HashedCapabilityIds: [][32]byte{triggerCapID, targetCapID}, + }, + nodes[1]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: nodes[1], + HashedCapabilityIds: [][32]byte{triggerCapID, targetCapID}, + }, + nodes[2]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: nodes[2], + HashedCapabilityIds: [][32]byte{triggerCapID, targetCapID}, + }, + nodes[3]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: nodes[3], + HashedCapabilityIds: [][32]byte{triggerCapID, targetCapID}, + }, + }, + }, + } + syncer := newRegistrySyncer(make(services.StopChan), wrapper, registry, dispatcher, lggr, HardcodedDonNetworkSetup{}, mr) + require.NoError(t, err) + + dispatcher.On("SetReceiver", fullTriggerCapID, fmt.Sprint(dID), mock.AnythingOfType("*remote.triggerPublisher")).Return(nil) + dispatcher.On("SetReceiver", fullTargetID, fmt.Sprint(dID), mock.AnythingOfType("*target.server")).Return(nil) + + err = syncer.sync(ctx) + require.NoError(t, err) + defer syncer.Close() +} + +func TestSyncer_IgnoresCapabilitiesForPrivateDON(t *testing.T) { + ctx := tests.Context(t) + lggr := logger.TestLogger(t) + registry := NewRegistry(lggr) + dispatcher := remoteMocks.NewDispatcher(t) + + var pid ragetypes.PeerID + err := pid.UnmarshalText([]byte("12D3KooWBCF1XT5Wi8FzfgNCqRL76Swv8TRU3TiD4QiJm8NMNX7N")) + require.NoError(t, err) + peer := mocks.NewPeer(t) + peer.On("UpdateConnections", mock.Anything).Return(nil) + peer.On("ID").Return(pid) + wrapper := mocks.NewPeerWrapper(t) + wrapper.On("GetPeer").Return(peer) + + nodes := [][32]byte{ + pid, + randomWord(), + randomWord(), + randomWord(), + } + + triggerCapID := randomWord() + targetCapID := randomWord() + dID := uint32(1) + // The below state describes a Workflow DON (AcceptsWorkflows = true), + // which isn't public (IsPublic = false), but hosts the + // the streams-trigger and write_chain capabilities. + // We expect no action to be taken by the syncer. + mr := &mockReader{ + s: state{ + IDsToDONs: map[donID]kcr.CapabilityRegistryDONInfo{ + donID(dID): { + Id: dID, + ConfigCount: uint32(0), + F: uint8(1), + IsPublic: false, + AcceptsWorkflows: true, + NodeP2PIds: nodes, + CapabilityConfigurations: []kcr.CapabilityRegistryCapabilityConfiguration{ + { + CapabilityId: triggerCapID, + Config: []byte(""), + }, + { + CapabilityId: targetCapID, + Config: []byte(""), + }, + }, + }, + }, + IDsToCapabilities: map[hashedCapabilityID]kcr.CapabilityRegistryCapability{ + triggerCapID: { + LabelledName: "streams-trigger", + Version: "1.0.0", + CapabilityType: 0, + }, + targetCapID: { + LabelledName: "write-chain_evm_1", + Version: "1.0.0", + CapabilityType: 3, + }, + }, + IDsToNodes: map[p2ptypes.PeerID]kcr.CapabilityRegistryNodeInfo{ + nodes[0]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: nodes[0], + HashedCapabilityIds: [][32]byte{triggerCapID, targetCapID}, + }, + nodes[1]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: nodes[1], + HashedCapabilityIds: [][32]byte{triggerCapID, targetCapID}, + }, + nodes[2]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: nodes[2], + HashedCapabilityIds: [][32]byte{triggerCapID, targetCapID}, + }, + nodes[3]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: nodes[3], + HashedCapabilityIds: [][32]byte{triggerCapID, targetCapID}, + }, + }, + }, + } + syncer := newRegistrySyncer(make(services.StopChan), wrapper, registry, dispatcher, lggr, HardcodedDonNetworkSetup{}, mr) + require.NoError(t, err) + + // If the DON were public, this would fail with two errors: + // - error fetching the capabilities from the registry since they haven't been added + // - erroneous calls to dispatcher.SetReceiver, since the call hasn't been registered. + err = syncer.sync(ctx) + require.NoError(t, err) + defer syncer.Close() + + // Finally, assert that no services were added. + assert.Len(t, syncer.subServices, 0) +} + +func TestSyncer_WiresUpClientsForPublicWorkflowDON(t *testing.T) { + ctx := tests.Context(t) + lggr := logger.TestLogger(t) + registry := NewRegistry(lggr) + dispatcher := remoteMocks.NewDispatcher(t) + + var pid ragetypes.PeerID + err := pid.UnmarshalText([]byte("12D3KooWBCF1XT5Wi8FzfgNCqRL76Swv8TRU3TiD4QiJm8NMNX7N")) + require.NoError(t, err) + peer := mocks.NewPeer(t) + peer.On("UpdateConnections", mock.Anything).Return(nil) + peer.On("ID").Return(pid) + wrapper := mocks.NewPeerWrapper(t) + wrapper.On("GetPeer").Return(peer) + + workflowDonNodes := [][32]byte{ + pid, + randomWord(), + randomWord(), + randomWord(), + } + + capabilityDonNodes := [][32]byte{ + randomWord(), + randomWord(), + randomWord(), + randomWord(), + } + + fullTriggerCapID := "streams-trigger@1.0.0" + fullTargetID := "write-chain_evm_1@1.0.0" + triggerCapID := randomWord() + targetCapID := randomWord() + dID := uint32(1) + capDonID := uint32(2) + // The below state describes a Workflow DON (AcceptsWorkflows = true), + // which exposes the streams-trigger and write_chain capabilities. + // We expect receivers to be wired up and both capabilities to be added to the registry. + mr := &mockReader{ + s: state{ + IDsToDONs: map[donID]kcr.CapabilityRegistryDONInfo{ + donID(dID): { + Id: dID, + ConfigCount: uint32(0), + F: uint8(1), + IsPublic: true, + AcceptsWorkflows: true, + NodeP2PIds: workflowDonNodes, + }, + donID(capDonID): { + Id: capDonID, + ConfigCount: uint32(0), + F: uint8(1), + IsPublic: true, + AcceptsWorkflows: false, + NodeP2PIds: capabilityDonNodes, + CapabilityConfigurations: []kcr.CapabilityRegistryCapabilityConfiguration{ + { + CapabilityId: triggerCapID, + Config: []byte(""), + }, + { + CapabilityId: targetCapID, + Config: []byte(""), + }, + }, + }, + }, + IDsToCapabilities: map[hashedCapabilityID]kcr.CapabilityRegistryCapability{ + triggerCapID: { + LabelledName: "streams-trigger", + Version: "1.0.0", + CapabilityType: 0, + }, + targetCapID: { + LabelledName: "write-chain_evm_1", + Version: "1.0.0", + CapabilityType: 3, + }, + }, + IDsToNodes: map[p2ptypes.PeerID]kcr.CapabilityRegistryNodeInfo{ + capabilityDonNodes[0]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: capabilityDonNodes[0], + HashedCapabilityIds: [][32]byte{triggerCapID, targetCapID}, + }, + capabilityDonNodes[1]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: capabilityDonNodes[1], + HashedCapabilityIds: [][32]byte{triggerCapID, targetCapID}, + }, + capabilityDonNodes[2]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: capabilityDonNodes[2], + HashedCapabilityIds: [][32]byte{triggerCapID, targetCapID}, + }, + capabilityDonNodes[3]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: capabilityDonNodes[3], + HashedCapabilityIds: [][32]byte{triggerCapID, targetCapID}, + }, + workflowDonNodes[0]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: workflowDonNodes[0], + }, + workflowDonNodes[1]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: workflowDonNodes[1], + }, + workflowDonNodes[2]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: workflowDonNodes[2], + }, + workflowDonNodes[3]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: workflowDonNodes[3], + }, + }, + }, + } + syncer := newRegistrySyncer(make(services.StopChan), wrapper, registry, dispatcher, lggr, HardcodedDonNetworkSetup{}, mr) + require.NoError(t, err) + + dispatcher.On("SetReceiver", fullTriggerCapID, fmt.Sprint(capDonID), mock.AnythingOfType("*remote.triggerSubscriber")).Return(nil) + dispatcher.On("SetReceiver", fullTargetID, fmt.Sprint(capDonID), mock.AnythingOfType("*target.client")).Return(nil) + + err = syncer.sync(ctx) + require.NoError(t, err) + defer syncer.Close() + + _, err = registry.Get(ctx, fullTriggerCapID) + require.NoError(t, err) + + _, err = registry.Get(ctx, fullTargetID) + require.NoError(t, err) +} + +func TestSyncer_WiresUpClientsForPublicWorkflowDONButIgnoresPrivateCapabilities(t *testing.T) { + ctx := tests.Context(t) + lggr := logger.TestLogger(t) + registry := NewRegistry(lggr) + dispatcher := remoteMocks.NewDispatcher(t) + + var pid ragetypes.PeerID + err := pid.UnmarshalText([]byte("12D3KooWBCF1XT5Wi8FzfgNCqRL76Swv8TRU3TiD4QiJm8NMNX7N")) + require.NoError(t, err) + peer := mocks.NewPeer(t) + peer.On("UpdateConnections", mock.Anything).Return(nil) + peer.On("ID").Return(pid) + wrapper := mocks.NewPeerWrapper(t) + wrapper.On("GetPeer").Return(peer) + + workflowDonNodes := [][32]byte{ + pid, + randomWord(), + randomWord(), + randomWord(), + } + + capabilityDonNodes := [][32]byte{ + randomWord(), + randomWord(), + randomWord(), + randomWord(), + } + + fullTriggerCapID := "streams-trigger@1.0.0" + triggerCapID := randomWord() + targetCapID := randomWord() + dID := uint32(1) + triggerCapDonID := uint32(2) + targetCapDonID := uint32(3) + // The below state describes a Workflow DON (AcceptsWorkflows = true), + // which exposes the streams-trigger and write_chain capabilities. + // We expect receivers to be wired up and both capabilities to be added to the registry. + mr := &mockReader{ + s: state{ + IDsToDONs: map[donID]kcr.CapabilityRegistryDONInfo{ + donID(dID): { + Id: dID, + ConfigCount: uint32(0), + F: uint8(1), + IsPublic: true, + AcceptsWorkflows: true, + NodeP2PIds: workflowDonNodes, + }, + donID(triggerCapDonID): { + Id: triggerCapDonID, + ConfigCount: uint32(0), + F: uint8(1), + IsPublic: true, + AcceptsWorkflows: false, + NodeP2PIds: capabilityDonNodes, + CapabilityConfigurations: []kcr.CapabilityRegistryCapabilityConfiguration{ + { + CapabilityId: triggerCapID, + Config: []byte(""), + }, + }, + }, + donID(targetCapDonID): { + Id: targetCapDonID, + ConfigCount: uint32(0), + F: uint8(1), + IsPublic: false, + AcceptsWorkflows: false, + NodeP2PIds: capabilityDonNodes, + CapabilityConfigurations: []kcr.CapabilityRegistryCapabilityConfiguration{ + { + CapabilityId: targetCapID, + Config: []byte(""), + }, + }, + }, + }, + IDsToCapabilities: map[hashedCapabilityID]kcr.CapabilityRegistryCapability{ + triggerCapID: { + LabelledName: "streams-trigger", + Version: "1.0.0", + CapabilityType: 0, + }, + targetCapID: { + LabelledName: "write-chain_evm_1", + Version: "1.0.0", + CapabilityType: 3, + }, + }, + IDsToNodes: map[p2ptypes.PeerID]kcr.CapabilityRegistryNodeInfo{ + capabilityDonNodes[0]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: capabilityDonNodes[0], + HashedCapabilityIds: [][32]byte{triggerCapID, targetCapID}, + }, + capabilityDonNodes[1]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: capabilityDonNodes[1], + HashedCapabilityIds: [][32]byte{triggerCapID, targetCapID}, + }, + capabilityDonNodes[2]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: capabilityDonNodes[2], + HashedCapabilityIds: [][32]byte{triggerCapID, targetCapID}, + }, + capabilityDonNodes[3]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: capabilityDonNodes[3], + HashedCapabilityIds: [][32]byte{triggerCapID, targetCapID}, + }, + workflowDonNodes[0]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: workflowDonNodes[0], + }, + workflowDonNodes[1]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: workflowDonNodes[1], + }, + workflowDonNodes[2]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: workflowDonNodes[2], + }, + workflowDonNodes[3]: { + NodeOperatorId: 1, + Signer: randomWord(), + P2pId: workflowDonNodes[3], + }, + }, + }, + } + syncer := newRegistrySyncer(make(services.StopChan), wrapper, registry, dispatcher, lggr, HardcodedDonNetworkSetup{}, mr) + require.NoError(t, err) + + dispatcher.On("SetReceiver", fullTriggerCapID, fmt.Sprint(triggerCapDonID), mock.AnythingOfType("*remote.triggerSubscriber")).Return(nil) + + err = syncer.sync(ctx) + require.NoError(t, err) + defer syncer.Close() + + _, err = registry.Get(ctx, fullTriggerCapID) + require.NoError(t, err) +} diff --git a/core/config/capabilities_config.go b/core/config/capabilities_config.go index 8cde986ccb7..ae542c062c5 100644 --- a/core/config/capabilities_config.go +++ b/core/config/capabilities_config.go @@ -1,6 +1,17 @@ package config +import ( + "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +type CapabilitiesExternalRegistry interface { + Address() string + NetworkID() string + ChainID() string + RelayID() types.RelayID +} + type Capabilities interface { Peering() P2P - // NOTE: RegistrySyncer will need config with relay ID, chain ID and contract address when implemented + ExternalRegistry() CapabilitiesExternalRegistry } diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml index 92d75430daf..265609b064c 100644 --- a/core/config/docs/core.toml +++ b/core/config/docs/core.toml @@ -440,6 +440,14 @@ DeltaReconcile = '1m' # Default # but the host and port must be fully specified and cannot be empty. You can specify `0.0.0.0` (IPv4) or `::` (IPv6) to listen on all interfaces, but that is not recommended. ListenAddresses = ['1.2.3.4:9999', '[a52d:0:a88:1274::abcd]:1337'] # Example +[Capabilities.ExternalRegistry] +# Address is the address for the capabilities registry contract. +Address = '0x0' # Example +# NetworkID identifies the target network where the remote registry is located. +NetworkID = 'evm' # Default +# ChainID identifies the target chain id where the remote registry is located. +ChainID = '1' # Default + [Capabilities.Peering] # IncomingMessageBufferSize is the per-remote number of incoming # messages to buffer. Any additional messages received on top of those diff --git a/core/config/toml/types.go b/core/config/toml/types.go index e3e49dbb18b..c8b983b7c26 100644 --- a/core/config/toml/types.go +++ b/core/config/toml/types.go @@ -1406,12 +1406,34 @@ func (m *MercurySecrets) ValidateConfig() (err error) { return err } +type ExternalRegistry struct { + Address *string + NetworkID *string + ChainID *string +} + +func (r *ExternalRegistry) setFrom(f *ExternalRegistry) { + if f.Address != nil { + r.Address = f.Address + } + + if f.NetworkID != nil { + r.NetworkID = f.NetworkID + } + + if f.ChainID != nil { + r.ChainID = f.ChainID + } +} + type Capabilities struct { - Peering P2P `toml:",omitempty"` + Peering P2P `toml:",omitempty"` + ExternalRegistry ExternalRegistry `toml:",omitempty"` } func (c *Capabilities) setFrom(f *Capabilities) { c.Peering.setFrom(&f.Peering) + c.ExternalRegistry.setFrom(&f.ExternalRegistry) } type ThresholdKeyShareSecrets struct { diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 076c93009a9..2d5eac01670 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -217,9 +217,27 @@ func NewApplication(opts ApplicationOpts) (Application, error) { return nil, fmt.Errorf("failed to create hardcoded Don network setup: %w", err) } - // NOTE: RegistrySyncer will depend on a Relayer when fully implemented dispatcher := remote.NewDispatcher(externalPeerWrapper, signer, opts.CapabilitiesRegistry, globalLogger) - registrySyncer := capabilities.NewRegistrySyncer(externalPeerWrapper, opts.CapabilitiesRegistry, dispatcher, globalLogger, networkSetup) + + rid := cfg.Capabilities().ExternalRegistry().RelayID() + registryAddress := cfg.Capabilities().ExternalRegistry().Address() + relayer, err := relayerChainInterops.Get(rid) + if err != nil { + return nil, fmt.Errorf("could not fetch relayer %s configured for capabilities registry: %w", rid, err) + } + + registrySyncer, err := capabilities.NewRegistrySyncer( + externalPeerWrapper, + opts.CapabilitiesRegistry, + dispatcher, + globalLogger, + networkSetup, + relayer, + registryAddress, + ) + if err != nil { + return nil, fmt.Errorf("could not configure syncer: %w", err) + } srvcs = append(srvcs, dispatcher, registrySyncer) } diff --git a/core/services/chainlink/config_capabilities.go b/core/services/chainlink/config_capabilities.go index d432d31ad18..c438ca249dd 100644 --- a/core/services/chainlink/config_capabilities.go +++ b/core/services/chainlink/config_capabilities.go @@ -3,6 +3,8 @@ package chainlink import ( "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" + + "github.com/smartcontractkit/chainlink-common/pkg/types" ) var _ config.Capabilities = (*capabilitiesConfig)(nil) @@ -14,3 +16,29 @@ type capabilitiesConfig struct { func (c *capabilitiesConfig) Peering() config.P2P { return &p2p{c: c.c.Peering} } + +func (c *capabilitiesConfig) ExternalRegistry() config.CapabilitiesExternalRegistry { + return &capabilitiesExternalRegistry{ + c: c.c.ExternalRegistry, + } +} + +type capabilitiesExternalRegistry struct { + c toml.ExternalRegistry +} + +func (c *capabilitiesExternalRegistry) RelayID() types.RelayID { + return types.NewRelayID(c.NetworkID(), c.ChainID()) +} + +func (c *capabilitiesExternalRegistry) NetworkID() string { + return *c.c.NetworkID +} + +func (c *capabilitiesExternalRegistry) ChainID() string { + return *c.c.ChainID +} + +func (c *capabilitiesExternalRegistry) Address() string { + return *c.c.Address +} diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 11fbfbea3b3..a94aeaa659b 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -444,6 +444,11 @@ func TestConfig_Marshal(t *testing.T) { ListenAddresses: &[]string{"foo", "bar"}, }, }, + ExternalRegistry: toml.ExternalRegistry{ + Address: ptr(""), + ChainID: ptr("1"), + NetworkID: ptr("evm"), + }, } full.Keeper = toml.Keeper{ DefaultTransactionQueueDepth: ptr[uint32](17), diff --git a/core/services/chainlink/testdata/config-empty-effective.toml b/core/services/chainlink/testdata/config-empty-effective.toml index 38c3ed62017..7ee0143870f 100644 --- a/core/services/chainlink/testdata/config-empty-effective.toml +++ b/core/services/chainlink/testdata/config-empty-effective.toml @@ -248,3 +248,8 @@ DefaultBootstrappers = [] DeltaDial = '15s' DeltaReconcile = '1m0s' ListenAddresses = [] + +[Capabilities.ExternalRegistry] +Address = '' +NetworkID = 'evm' +ChainID = '1' diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index 103f068c8e8..fd51d523576 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -259,6 +259,11 @@ DeltaDial = '1m0s' DeltaReconcile = '2s' ListenAddresses = ['foo', 'bar'] +[Capabilities.ExternalRegistry] +Address = '' +NetworkID = 'evm' +ChainID = '1' + [[EVM]] ChainID = '1' Enabled = false diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index 05dfe21a5d8..13aac2db7fa 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -249,6 +249,11 @@ DeltaDial = '15s' DeltaReconcile = '1m0s' ListenAddresses = [] +[Capabilities.ExternalRegistry] +Address = '' +NetworkID = 'evm' +ChainID = '1' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/core/web/resolver/testdata/config-empty-effective.toml b/core/web/resolver/testdata/config-empty-effective.toml index 38c3ed62017..7ee0143870f 100644 --- a/core/web/resolver/testdata/config-empty-effective.toml +++ b/core/web/resolver/testdata/config-empty-effective.toml @@ -248,3 +248,8 @@ DefaultBootstrappers = [] DeltaDial = '15s' DeltaReconcile = '1m0s' ListenAddresses = [] + +[Capabilities.ExternalRegistry] +Address = '' +NetworkID = 'evm' +ChainID = '1' diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index 7e1b2291106..d69f0aa5064 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -259,6 +259,11 @@ DeltaDial = '1m0s' DeltaReconcile = '2s' ListenAddresses = ['foo', 'bar'] +[Capabilities.ExternalRegistry] +Address = '' +NetworkID = 'evm' +ChainID = '1' + [[EVM]] ChainID = '1' Enabled = false diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index 05dfe21a5d8..13aac2db7fa 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -249,6 +249,11 @@ DeltaDial = '15s' DeltaReconcile = '1m0s' ListenAddresses = [] +[Capabilities.ExternalRegistry] +Address = '' +NetworkID = 'evm' +ChainID = '1' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 07a26246d4e..5f40d9fa69d 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -1199,6 +1199,33 @@ ListenAddresses = ['1.2.3.4:9999', '[a52d:0:a88:1274::abcd]:1337'] # Example ListenAddresses is the addresses the peer will listen to on the network in `host:port` form as accepted by `net.Listen()`, but the host and port must be fully specified and cannot be empty. You can specify `0.0.0.0` (IPv4) or `::` (IPv6) to listen on all interfaces, but that is not recommended. +## Capabilities.ExternalRegistry +```toml +[Capabilities.ExternalRegistry] +Address = '0x0' # Example +NetworkID = 'evm' # Default +ChainID = '1' # Default +``` + + +### Address +```toml +Address = '0x0' # Example +``` +Address is the address for the capabilities registry contract. + +### NetworkID +```toml +NetworkID = 'evm' # Default +``` +NetworkID identifies the target network where the remote registry is located. + +### ChainID +```toml +ChainID = '1' # Default +``` +ChainID identifies the target chain id where the remote registry is located. + ## Capabilities.Peering ```toml [Capabilities.Peering] diff --git a/testdata/scripts/keys/eth/list/help.txtar b/testdata/scripts/keys/eth/list/help.txtar index d7156fd3e69..2fa0f957cef 100644 --- a/testdata/scripts/keys/eth/list/help.txtar +++ b/testdata/scripts/keys/eth/list/help.txtar @@ -6,4 +6,4 @@ NAME: chainlink keys eth list - List available Ethereum accounts with their ETH & LINK balances and other metadata USAGE: - chainlink keys eth list [arguments...] \ No newline at end of file + chainlink keys eth list [arguments...] diff --git a/testdata/scripts/node/validate/default.txtar b/testdata/scripts/node/validate/default.txtar index a8e8e41750d..9c50188141c 100644 --- a/testdata/scripts/node/validate/default.txtar +++ b/testdata/scripts/node/validate/default.txtar @@ -261,6 +261,11 @@ DeltaDial = '15s' DeltaReconcile = '1m0s' ListenAddresses = [] +[Capabilities.ExternalRegistry] +Address = '' +NetworkID = 'evm' +ChainID = '1' + Invalid configuration: invalid secrets: 2 errors: - Database.URL: empty: must be provided and non-empty - Password.Keystore: empty: must be provided and non-empty diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index 39cc989ac21..6e2a40beb7f 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -305,6 +305,11 @@ DeltaDial = '15s' DeltaReconcile = '1m0s' ListenAddresses = [] +[Capabilities.ExternalRegistry] +Address = '' +NetworkID = 'evm' +ChainID = '1' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar index 3fa24f63e36..5db4e8527d3 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -305,6 +305,11 @@ DeltaDial = '15s' DeltaReconcile = '1m0s' ListenAddresses = [] +[Capabilities.ExternalRegistry] +Address = '' +NetworkID = 'evm' +ChainID = '1' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar index f80245bb5a5..bcf054cbca3 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -305,6 +305,11 @@ DeltaDial = '15s' DeltaReconcile = '1m0s' ListenAddresses = [] +[Capabilities.ExternalRegistry] +Address = '' +NetworkID = 'evm' +ChainID = '1' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/invalid-ocr-p2p.txtar b/testdata/scripts/node/validate/invalid-ocr-p2p.txtar index 45c97477bd5..3c6e24a897b 100644 --- a/testdata/scripts/node/validate/invalid-ocr-p2p.txtar +++ b/testdata/scripts/node/validate/invalid-ocr-p2p.txtar @@ -290,6 +290,11 @@ DeltaDial = '15s' DeltaReconcile = '1m0s' ListenAddresses = [] +[Capabilities.ExternalRegistry] +Address = '' +NetworkID = 'evm' +ChainID = '1' + Invalid configuration: invalid configuration: P2P.V2.Enabled: invalid value (false): P2P required for OCR or OCR2. Please enable P2P or disable OCR/OCR2. -- err.txt -- diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index 5d9d51f8727..6b5932cfefd 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -295,6 +295,11 @@ DeltaDial = '15s' DeltaReconcile = '1m0s' ListenAddresses = [] +[Capabilities.ExternalRegistry] +Address = '' +NetworkID = 'evm' +ChainID = '1' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index c7510232e59..688829513e9 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -302,6 +302,11 @@ DeltaDial = '15s' DeltaReconcile = '1m0s' ListenAddresses = [] +[Capabilities.ExternalRegistry] +Address = '' +NetworkID = 'evm' +ChainID = '1' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/warnings.txtar b/testdata/scripts/node/validate/warnings.txtar index c047b90c133..d8d0de337aa 100644 --- a/testdata/scripts/node/validate/warnings.txtar +++ b/testdata/scripts/node/validate/warnings.txtar @@ -284,6 +284,11 @@ DeltaDial = '15s' DeltaReconcile = '1m0s' ListenAddresses = [] +[Capabilities.ExternalRegistry] +Address = '' +NetworkID = 'evm' +ChainID = '1' + # Configuration warning: Tracing.TLSCertPath: invalid value (something): must be empty when Tracing.Mode is 'unencrypted' -Valid configuration. \ No newline at end of file +Valid configuration.