diff --git a/.changeset/lemon-keys-sniff.md b/.changeset/lemon-keys-sniff.md new file mode 100644 index 00000000000..62f89b6b452 --- /dev/null +++ b/.changeset/lemon-keys-sniff.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +#added GetJobRuns to Job Distributor diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 1a31d66c327..3e0e2d7566a 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -482,7 +482,7 @@ require ( github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20250717121125-2350c82883e2 // indirect github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250729142306-508e798f6a5d // indirect github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20250722225531-876fd6b94976 // indirect - github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1 // indirect + github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 // indirect github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 // indirect github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 // indirect github.com/smartcontractkit/chainlink-protos/svr v1.1.0 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index c0250d13e0e..fdebdd8b8be 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1568,8 +1568,8 @@ github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b0b4605/go.mod h1:jUC52kZzEnWF9tddHh85zolKybmLpbQ1oNA4FjOHt1Q= github.com/smartcontractkit/chainlink-protos/job-distributor v0.13.1 h1:PWwLGimBt37eDzpbfZ9V/ZkW4oCjcwKjKiAwKlSfPc0= github.com/smartcontractkit/chainlink-protos/job-distributor v0.13.1/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= -github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1 h1:VcFo27MBPTMB1d1Tp3q3RzJNqwErKR+z9QLQZ6KBSXo= -github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= +github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 h1:0eroOyBwmdoGUwUdvMI0/J7m5wuzNnJDMglSOK1sfNY= +github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 h1:L6KJ4kGv/yNNoCk8affk7Y1vAY0qglPMXC/hevV/IsA= github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6/go.mod h1:FRwzI3hGj4CJclNS733gfcffmqQ62ONCkbGi49s658w= github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 h1:B7itmjy+CMJ26elVw/cAJqqhBQ3Xa/mBYWK0/rQ5MuI= diff --git a/core/services/feeds/mocks/orm.go b/core/services/feeds/mocks/orm.go index c306308dd72..7ecfff5da5e 100644 --- a/core/services/feeds/mocks/orm.go +++ b/core/services/feeds/mocks/orm.go @@ -1330,6 +1330,64 @@ func (_c *ORM_IsJobManaged_Call) RunAndReturn(run func(context.Context, int64) ( return _c } +// IsJobManagedByFeedsManager provides a mock function with given fields: ctx, jobID, feedsManagerID +func (_m *ORM) IsJobManagedByFeedsManager(ctx context.Context, jobID int64, feedsManagerID int64) (bool, error) { + ret := _m.Called(ctx, jobID, feedsManagerID) + + if len(ret) == 0 { + panic("no return value specified for IsJobManagedByFeedsManager") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, int64) (bool, error)); ok { + return rf(ctx, jobID, feedsManagerID) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, int64) bool); ok { + r0 = rf(ctx, jobID, feedsManagerID) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, int64) error); ok { + r1 = rf(ctx, jobID, feedsManagerID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ORM_IsJobManagedByFeedsManager_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsJobManagedByFeedsManager' +type ORM_IsJobManagedByFeedsManager_Call struct { + *mock.Call +} + +// IsJobManagedByFeedsManager is a helper method to define mock.On call +// - ctx context.Context +// - jobID int64 +// - feedsManagerID int64 +func (_e *ORM_Expecter) IsJobManagedByFeedsManager(ctx interface{}, jobID interface{}, feedsManagerID interface{}) *ORM_IsJobManagedByFeedsManager_Call { + return &ORM_IsJobManagedByFeedsManager_Call{Call: _e.mock.On("IsJobManagedByFeedsManager", ctx, jobID, feedsManagerID)} +} + +func (_c *ORM_IsJobManagedByFeedsManager_Call) Run(run func(ctx context.Context, jobID int64, feedsManagerID int64)) *ORM_IsJobManagedByFeedsManager_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(int64), args[2].(int64)) + }) + return _c +} + +func (_c *ORM_IsJobManagedByFeedsManager_Call) Return(_a0 bool, _a1 error) *ORM_IsJobManagedByFeedsManager_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ORM_IsJobManagedByFeedsManager_Call) RunAndReturn(run func(context.Context, int64, int64) (bool, error)) *ORM_IsJobManagedByFeedsManager_Call { + _c.Call.Return(run) + return _c +} + // ListChainConfigsByManagerIDs provides a mock function with given fields: ctx, mgrIDs func (_m *ORM) ListChainConfigsByManagerIDs(ctx context.Context, mgrIDs []int64) ([]feeds.ChainConfig, error) { ret := _m.Called(ctx, mgrIDs) diff --git a/core/services/feeds/mocks/service.go b/core/services/feeds/mocks/service.go index 20c2f7e4a87..58e9ffe102d 100644 --- a/core/services/feeds/mocks/service.go +++ b/core/services/feeds/mocks/service.go @@ -5,7 +5,9 @@ package mocks import ( context "context" + feedsmanager "github.com/smartcontractkit/chainlink-protos/orchestrator/feedsmanager" feeds "github.com/smartcontractkit/chainlink/v2/core/services/feeds" + mock "github.com/stretchr/testify/mock" ) @@ -627,6 +629,65 @@ func (_c *Service_GetJobProposal_Call) RunAndReturn(run func(context.Context, in return _c } +// GetJobRuns provides a mock function with given fields: ctx, args +func (_m *Service) GetJobRuns(ctx context.Context, args *feeds.GetJobRunsArgs) ([]*feedsmanager.JobRunSummary, error) { + ret := _m.Called(ctx, args) + + if len(ret) == 0 { + panic("no return value specified for GetJobRuns") + } + + var r0 []*feedsmanager.JobRunSummary + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *feeds.GetJobRunsArgs) ([]*feedsmanager.JobRunSummary, error)); ok { + return rf(ctx, args) + } + if rf, ok := ret.Get(0).(func(context.Context, *feeds.GetJobRunsArgs) []*feedsmanager.JobRunSummary); ok { + r0 = rf(ctx, args) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*feedsmanager.JobRunSummary) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *feeds.GetJobRunsArgs) error); ok { + r1 = rf(ctx, args) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Service_GetJobRuns_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetJobRuns' +type Service_GetJobRuns_Call struct { + *mock.Call +} + +// GetJobRuns is a helper method to define mock.On call +// - ctx context.Context +// - args *feeds.GetJobRunsArgs +func (_e *Service_Expecter) GetJobRuns(ctx interface{}, args interface{}) *Service_GetJobRuns_Call { + return &Service_GetJobRuns_Call{Call: _e.mock.On("GetJobRuns", ctx, args)} +} + +func (_c *Service_GetJobRuns_Call) Run(run func(ctx context.Context, args *feeds.GetJobRunsArgs)) *Service_GetJobRuns_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*feeds.GetJobRunsArgs)) + }) + return _c +} + +func (_c *Service_GetJobRuns_Call) Return(_a0 []*feedsmanager.JobRunSummary, _a1 error) *Service_GetJobRuns_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Service_GetJobRuns_Call) RunAndReturn(run func(context.Context, *feeds.GetJobRunsArgs) ([]*feedsmanager.JobRunSummary, error)) *Service_GetJobRuns_Call { + _c.Call.Return(run) + return _c +} + // GetManager provides a mock function with given fields: ctx, id func (_m *Service) GetManager(ctx context.Context, id int64) (*feeds.FeedsManager, error) { ret := _m.Called(ctx, id) diff --git a/core/services/feeds/models_test.go b/core/services/feeds/models_test.go index 7a96d31f475..908751d6d8e 100644 --- a/core/services/feeds/models_test.go +++ b/core/services/feeds/models_test.go @@ -47,8 +47,6 @@ func Test_NewChainType(t *testing.T) { } for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { ct, err := NewChainType(tt.give) @@ -180,8 +178,6 @@ func Test_OCR1Config_Value(t *testing.T) { } for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { val, err := tt.give.Value() require.NoError(t, err) @@ -244,8 +240,6 @@ func Test_OCR1Config_Scan(t *testing.T) { } for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { var actual OCR1Config err := actual.Scan([]byte(tt.give)) @@ -391,7 +385,6 @@ func Test_JobProposal_CanEditDefinition(t *testing.T) { } for _, tc := range tests { - tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() diff --git a/core/services/feeds/orm.go b/core/services/feeds/orm.go index f61f3bd1d95..bc41801da9c 100644 --- a/core/services/feeds/orm.go +++ b/core/services/feeds/orm.go @@ -57,6 +57,7 @@ type ORM interface { UpdateSpecDefinition(ctx context.Context, id int64, spec string) error IsJobManaged(ctx context.Context, jobID int64) (bool, error) + IsJobManagedByFeedsManager(ctx context.Context, jobID int64, feedsManagerID int64) (bool, error) Transact(context.Context, func(ORM) error) error WithDataSource(sqlutil.DataSource) ORM @@ -387,7 +388,7 @@ func (o *orm) CountJobProposals(ctx context.Context) (count int64, err error) { // CountJobProposals counts the number of job proposal records. func (o *orm) CountJobProposalsByStatus(ctx context.Context) (counts *JobProposalCounts, err error) { stmt := ` -SELECT +SELECT COUNT(*) filter (where job_proposals.status = 'pending' OR job_proposals.pending_update = TRUE) as pending, COUNT(*) filter (where job_proposals.status = 'approved' AND job_proposals.pending_update = FALSE) as approved, COUNT(*) filter (where job_proposals.status = 'rejected' AND job_proposals.pending_update = FALSE) as rejected, @@ -878,3 +879,20 @@ SELECT exists ( err = o.ds.GetContext(ctx, &exists, stmt, jobID) return exists, errors.Wrap(err, "IsJobManaged failed") } + +// IsJobManagedByFeedsManager determines if a job is managed by a specific feeds manager. +func (o *orm) IsJobManagedByFeedsManager(ctx context.Context, jobID int64, feedsManagerID int64) (exists bool, err error) { + stmt := ` +SELECT exists ( + SELECT 1 + FROM job_proposals + INNER JOIN jobs ON job_proposals.external_job_id = jobs.external_job_id + WHERE jobs.id = $1 + AND job_proposals.feeds_manager_id = $2 + AND job_proposals.status <> 'deleted' +); +` + + err = o.ds.GetContext(ctx, &exists, stmt, jobID, feedsManagerID) + return exists, errors.Wrap(err, "IsJobManagedByFeedsManager failed") +} diff --git a/core/services/feeds/orm_test.go b/core/services/feeds/orm_test.go index 6098273f616..2eaa4e0a972 100644 --- a/core/services/feeds/orm_test.go +++ b/core/services/feeds/orm_test.go @@ -791,8 +791,6 @@ func Test_ORM_CountJobProposalsByStatus(t *testing.T) { } for _, tc := range testCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { orm := setupORM(t) @@ -1067,8 +1065,6 @@ func Test_ORM_CancelSpec(t *testing.T) { } for _, tc := range testCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { ctx := testutils.Context(t) orm := setupORM(t) @@ -1229,8 +1225,6 @@ func Test_ORM_DeleteProposal(t *testing.T) { } for _, tc := range testCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { ctx := testutils.Context(t) orm := setupORM(t) @@ -1348,8 +1342,6 @@ func Test_ORM_RevokeSpec(t *testing.T) { } for _, tc := range testCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { ctx := testutils.Context(t) orm := setupORM(t) @@ -1597,8 +1589,6 @@ func Test_ORM_RejectSpec(t *testing.T) { } for _, tc := range testCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { ctx := testutils.Context(t) orm := setupORM(t) @@ -1693,6 +1683,88 @@ func Test_ORM_IsJobManaged(t *testing.T) { assert.False(t, isManaged) } +func Test_ORM_IsJobManagedByFeedsManager(t *testing.T) { + t.Parallel() + ctx := testutils.Context(t) + + var ( + orm = setupORM(t) + fmID1 = createFeedsManager(t, orm) + ) + + mgr2 := &feeds.FeedsManager{ + URI: "http://192.168.0.2", + Name: "Chainlink FMS 2", + PublicKey: crypto.PublicKey([]byte("22222222222222222222222222222222")), + } + fmID2, err := orm.CreateManager(ctx, mgr2) + require.NoError(t, err) + + var ( + jpID1 = createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID1) + jpID2 = createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID2) + specID1 = createJobSpec(t, orm, jpID1) + specID2 = createJobSpec(t, orm, jpID2) + externalJobID1 = uuid.NullUUID{UUID: uuid.New(), Valid: true} + externalJobID2 = uuid.NullUUID{UUID: uuid.New(), Valid: true} + ) + + j1 := createJob(t, orm.db, externalJobID1.UUID) + j2 := createJob(t, orm.db, externalJobID2.UUID) + + isManaged, err := orm.IsJobManagedByFeedsManager(ctx, int64(j1.ID), fmID1) + require.NoError(t, err) + assert.False(t, isManaged) + + isManaged, err = orm.IsJobManagedByFeedsManager(ctx, int64(j1.ID), fmID2) + require.NoError(t, err) + assert.False(t, isManaged) + + err = orm.ApproveSpec(ctx, specID1, externalJobID1.UUID) + require.NoError(t, err) + + isManaged, err = orm.IsJobManagedByFeedsManager(ctx, int64(j1.ID), fmID1) + require.NoError(t, err) + assert.True(t, isManaged) + + isManaged, err = orm.IsJobManagedByFeedsManager(ctx, int64(j1.ID), fmID2) + require.NoError(t, err) + assert.False(t, isManaged) + + err = orm.ApproveSpec(ctx, specID2, externalJobID2.UUID) + require.NoError(t, err) + + isManaged, err = orm.IsJobManagedByFeedsManager(ctx, int64(j2.ID), fmID2) + require.NoError(t, err) + assert.True(t, isManaged) + + isManaged, err = orm.IsJobManagedByFeedsManager(ctx, int64(j2.ID), fmID1) + require.NoError(t, err) + assert.False(t, isManaged) + + nonExistentJobID := int64(99998) + nonExistentFeedsManagerID := int64(99999) + + isManaged, err = orm.IsJobManagedByFeedsManager(ctx, nonExistentJobID, fmID1) + require.NoError(t, err) + assert.False(t, isManaged) + + isManaged, err = orm.IsJobManagedByFeedsManager(ctx, int64(j1.ID), nonExistentFeedsManagerID) + require.NoError(t, err) + assert.False(t, isManaged) + + err = orm.DeleteProposal(ctx, jpID1) + require.NoError(t, err) + + isManaged, err = orm.IsJobManagedByFeedsManager(ctx, int64(j1.ID), fmID1) + require.NoError(t, err) + assert.False(t, isManaged) + + isManaged, err = orm.IsJobManagedByFeedsManager(ctx, int64(j2.ID), fmID2) + require.NoError(t, err) + assert.True(t, isManaged) +} + // Helpers func assertChainConfigEqual(t *testing.T, want map[string]interface{}, actual feeds.ChainConfig) { @@ -1758,6 +1830,7 @@ func createJob(t *testing.T, db *sqlx.DB, externalJobID uuid.UUID) *job.Job { testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ JobID: externalJobID.String(), TransmitterAddress: address.Hex(), + ContractAddress: testutils.NewAddress().Hex(), DS1BridgeName: bridge.Name.String(), DS2BridgeName: bridge2.Name.String(), }).Toml(), diff --git a/core/services/feeds/rpc_handlers.go b/core/services/feeds/rpc_handlers.go index a079204534e..867be0cdda0 100644 --- a/core/services/feeds/rpc_handlers.go +++ b/core/services/feeds/rpc_handlers.go @@ -2,22 +2,31 @@ package feeds import ( "context" + "fmt" "github.com/google/uuid" pb "github.com/smartcontractkit/chainlink-protos/orchestrator/feedsmanager" + "github.com/smartcontractkit/chainlink/v2/core/logger" +) + +const ( + MaxJobRunsLimit = 100 + DefaultJobRunsLimit = 50 ) // RPCHandlers define handlers for RPC method calls from the Feeds Manager type RPCHandlers struct { svc Service feedsManagerID int64 + lggr logger.Logger } -func NewRPCHandlers(svc Service, feedsManagerID int64) *RPCHandlers { +func NewRPCHandlers(svc Service, feedsManagerID int64, lggr logger.Logger) *RPCHandlers { return &RPCHandlers{ svc: svc, feedsManagerID: feedsManagerID, + lggr: lggr.Named("RPCHandlers"), } } @@ -77,3 +86,33 @@ func (h *RPCHandlers) RevokeJob(ctx context.Context, req *pb.RevokeJobRequest) ( return &pb.RevokeJobResponse{}, nil } + +// GetJobRuns fetches job run history for the specified job proposal +func (h *RPCHandlers) GetJobRuns(ctx context.Context, req *pb.GetJobRunsRequest) (*pb.GetJobRunsResponse, error) { + remoteUUID, err := uuid.Parse(req.Id) + limit := req.Limit + if err != nil { + return nil, fmt.Errorf("unable to parse request id (%s): %w", req.Id, err) + } + + if limit == 0 || limit > MaxJobRunsLimit { + h.lggr.Warnw("Invalid limit provided, using default", + "requestedLimit", limit, + "defaultLimit", DefaultJobRunsLimit, + ) + limit = DefaultJobRunsLimit + } + + summaries, err := h.svc.GetJobRuns(ctx, &GetJobRunsArgs{ + FeedsManagerID: h.feedsManagerID, + RemoteUUID: remoteUUID, + Limit: limit, + }) + if err != nil { + return nil, fmt.Errorf("failed to get job runs: %w", err) + } + + return &pb.GetJobRunsResponse{ + Runs: summaries, + }, nil +} diff --git a/core/services/feeds/rpc_handlers_test.go b/core/services/feeds/rpc_handlers_test.go index 2ba2fc15816..a9c8f680d8d 100644 --- a/core/services/feeds/rpc_handlers_test.go +++ b/core/services/feeds/rpc_handlers_test.go @@ -9,6 +9,7 @@ import ( pb "github.com/smartcontractkit/chainlink-protos/orchestrator/feedsmanager" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/feeds" "github.com/smartcontractkit/chainlink/v2/core/services/feeds/mocks" ) @@ -24,10 +25,11 @@ func setupTestHandlers(t *testing.T) *TestRPCHandlers { var ( svc = mocks.NewService(t) feedsManagerID = int64(1) + lggr = logger.TestLogger(t) ) return &TestRPCHandlers{ - RPCHandlers: feeds.NewRPCHandlers(svc, feedsManagerID), + RPCHandlers: feeds.NewRPCHandlers(svc, feedsManagerID, lggr), svc: svc, feedsManagerID: feedsManagerID, } @@ -99,3 +101,115 @@ func Test_RPCHandlers_RevokeJob(t *testing.T) { }) require.NoError(t, err) } + +func Test_RPCHandlers_GetJobRuns(t *testing.T) { + var ( + ctx = testutils.Context(t) + jobID = uuid.New() + limit = uint32(10) + ) + h := setupTestHandlers(t) + + mockSummaries := []*pb.JobRunSummary{ + { + RunId: 1, + State: "completed", + AllErrors: []string{}, + FatalErrors: []string{}, + }, + { + RunId: 2, + State: "errored", + AllErrors: []string{"error1"}, + FatalErrors: []string{"fatal1"}, + }, + } + + h.svc.EXPECT(). + GetJobRuns(ctx, &feeds.GetJobRunsArgs{ + FeedsManagerID: h.feedsManagerID, + RemoteUUID: jobID, + Limit: limit, + }). + Return(mockSummaries, nil) + + response, err := h.GetJobRuns(ctx, &pb.GetJobRunsRequest{ + Id: jobID.String(), + Limit: limit, + }) + + require.NoError(t, err) + require.NotNil(t, response) + require.Len(t, response.Runs, 2) + + run1 := response.Runs[0] + require.Equal(t, int64(1), run1.RunId) + require.Equal(t, "completed", run1.State) + require.Empty(t, run1.AllErrors) + require.Empty(t, run1.FatalErrors) + + run2 := response.Runs[1] + require.Equal(t, int64(2), run2.RunId) + require.Equal(t, "errored", run2.State) + require.Len(t, run2.AllErrors, 1) + require.Equal(t, "error1", run2.AllErrors[0]) + require.Len(t, run2.FatalErrors, 1) + require.Equal(t, "fatal1", run2.FatalErrors[0]) +} + +func Test_RPCHandlers_GetJobRuns_InvalidUUID(t *testing.T) { + ctx := testutils.Context(t) + h := setupTestHandlers(t) + + _, err := h.GetJobRuns(ctx, &pb.GetJobRunsRequest{ + Id: "invalid-uuid", + Limit: 10, + }) + + require.Error(t, err) + require.Contains(t, err.Error(), "invalid UUID") +} + +func Test_RPCHandlers_GetJobRuns_DefaultLimit(t *testing.T) { + var ( + ctx = testutils.Context(t) + jobID = uuid.New() + ) + h := setupTestHandlers(t) + + h.svc.EXPECT().GetJobRuns(ctx, &feeds.GetJobRunsArgs{ + FeedsManagerID: h.feedsManagerID, + RemoteUUID: jobID, + Limit: 50, + }). + Return([]*pb.JobRunSummary{}, nil) + + _, err := h.GetJobRuns(ctx, &pb.GetJobRunsRequest{ + Id: jobID.String(), + Limit: 0, + }) + + require.NoError(t, err) +} + +func Test_RPCHandlers_GetJobRuns_ExceedsMaxLimit(t *testing.T) { + var ( + ctx = testutils.Context(t) + jobID = uuid.New() + ) + h := setupTestHandlers(t) + + h.svc.EXPECT().GetJobRuns(ctx, &feeds.GetJobRunsArgs{ + FeedsManagerID: h.feedsManagerID, + RemoteUUID: jobID, + Limit: 50, + }). + Return([]*pb.JobRunSummary{}, nil) + + _, err := h.GetJobRuns(ctx, &pb.GetJobRunsRequest{ + Id: jobID.String(), + Limit: 150, + }) + + require.NoError(t, err) +} diff --git a/core/services/feeds/service.go b/core/services/feeds/service.go index 42cfc783a95..8e884ac8fd7 100644 --- a/core/services/feeds/service.go +++ b/core/services/feeds/service.go @@ -18,6 +18,7 @@ import ( "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "google.golang.org/protobuf/types/known/timestamppb" "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -39,6 +40,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr" ocr2 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/standardcapabilities" "github.com/smartcontractkit/chainlink/v2/core/services/streams" "github.com/smartcontractkit/chainlink/v2/core/services/workflows" @@ -140,6 +142,7 @@ type Service interface { ProposeJob(ctx context.Context, args *ProposeJobArgs) (int64, error) RevokeJob(ctx context.Context, args *RevokeJobArgs) (int64, error) SyncNodeInfo(ctx context.Context, id int64) error + GetJobRuns(ctx context.Context, args *GetJobRunsArgs) ([]*pb.JobRunSummary, error) CountJobProposalsByStatus(ctx context.Context) (*JobProposalCounts, error) GetJobProposal(ctx context.Context, id int64) (*JobProposal, error) @@ -583,6 +586,13 @@ func (s *service) ListJobProposalsByManagersIDs(ctx context.Context, ids []int64 return s.orm.ListJobProposalsByManagersIDs(ctx, ids) } +// GetJobRunsArgs are the arguments to provide to the GetJobRuns method. +type GetJobRunsArgs struct { + FeedsManagerID int64 + RemoteUUID uuid.UUID + Limit uint32 +} + // DeleteJobArgs are the arguments to provide to the DeleteJob method. type DeleteJobArgs struct { FeedsManagerID int64 @@ -685,6 +695,64 @@ func (s *service) RevokeJob(ctx context.Context, args *RevokeJobArgs) (int64, er return proposal.ID, nil } +// GetJobRuns fetches recent job runs for a job by its remote UUID. +func (s *service) GetJobRuns(ctx context.Context, args *GetJobRunsArgs) ([]*pb.JobRunSummary, error) { + s.lggr.Infow("FeedsService.GetJobRuns", "remoteUUID", args.RemoteUUID) + + job, err := s.jobORM.FindJobByExternalJobID(ctx, args.RemoteUUID) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, fmt.Errorf("job not found: %w", err) + } + return nil, fmt.Errorf("failed to find job: %w", err) + } + + isManagedByFM, err := s.orm.IsJobManagedByFeedsManager(ctx, int64(job.ID), args.FeedsManagerID) + if err != nil { + return nil, fmt.Errorf("failed to check if job is managed by feeds manager: %w", err) + } + + if !isManagedByFM { + return nil, errors.New("job is not managed by the requesting feeds manager") + } + + runs, _, err := s.jobORM.PipelineRuns(ctx, &job.ID, 0, int(args.Limit)) + if err != nil { + return nil, fmt.Errorf("failed to fetch job runs: %w", err) + } + + summaries := make([]*pb.JobRunSummary, 0, len(runs)) + for _, run := range runs { + var finishedAt *timestamppb.Timestamp + if run.FinishedAt.Valid { + finishedAt = timestamppb.New(run.FinishedAt.Time) + } + + summaries = append(summaries, &pb.JobRunSummary{ + RunId: run.ID, + State: string(run.State), + CreatedAt: timestamppb.New(run.CreatedAt), + FinishedAt: finishedAt, + AllErrors: ConvertPipelineRunErrors(run.AllErrors), + FatalErrors: ConvertPipelineRunErrors(run.FatalErrors), + }) + } + + s.lggr.Infow("Successfully retrieved job runs", "remoteUUID", args.RemoteUUID, "count", len(summaries)) + return summaries, nil +} + +// ConvertPipelineRunErrors converts pipeline.RunErrors to []string, filtering out zero values +func ConvertPipelineRunErrors(errors pipeline.RunErrors) []string { + var result []string + for _, err := range errors { + if !err.IsZero() { + result = append(result, err.ValueOrZero()) + } + } + return result +} + // ProposeJobArgs are the arguments to provide to the ProposeJob method. type ProposeJobArgs struct { FeedsManagerID int64 @@ -1263,10 +1331,7 @@ func (s *service) connectFeedManager(mgr FeedsManager) { URI: mgr.URI, CSASigner: s.csaSigner, Pubkey: mgr.PublicKey, - Handlers: &RPCHandlers{ - feedsManagerID: mgr.ID, - svc: s, - }, + Handlers: NewRPCHandlers(s, mgr.ID, s.lggr), OnConnect: func(pb.FeedsManagerClient) { // Sync the node's information with FMS once connected s.syncNodeInfoWithRetry(mgr.ID) @@ -1301,8 +1366,6 @@ func (s *service) observeJobProposalCounts(ctx context.Context) error { JobProposalStatusPending, JobProposalStatusApproved, JobProposalStatusCancelled, JobProposalStatusRejected, JobProposalStatusDeleted, JobProposalStatusRevoked, } { - status := status - promJobProposalCounts.With(prometheus.Labels{"status": string(status)}).Set(metrics[status]) promFeedsJobProposalCounts.With(prometheus.Labels{"status": string(status)}).Set(metrics[status]) } @@ -1785,6 +1848,10 @@ func (ns NullService) RevokeJob(ctx context.Context, args *RevokeJobArgs) (int64 return 0, ErrFeedsManagerDisabled } +func (ns NullService) GetJobRuns(ctx context.Context, args *GetJobRunsArgs) ([]*pb.JobRunSummary, error) { + return nil, ErrFeedsManagerDisabled +} + func (ns NullService) RegisterManager(ctx context.Context, params RegisterManagerParams) (int64, error) { return 0, ErrFeedsManagerDisabled } diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index 756bc522c10..5f5520b0f8e 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -21,6 +21,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" + "google.golang.org/protobuf/types/known/timestamppb" "gopkg.in/guregu/null.v4" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" @@ -1314,8 +1315,6 @@ func Test_Service_ProposeJob(t *testing.T) { } for _, tc := range testCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { t.Parallel() @@ -1635,8 +1634,6 @@ func Test_Service_DeleteJob(t *testing.T) { } for _, tc := range testCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { t.Parallel() @@ -1863,8 +1860,6 @@ answer1 [type=median index=0]; } for _, tc := range testCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { t.Parallel() @@ -2478,7 +2473,6 @@ func Test_Service_CancelSpec(t *testing.T) { } for _, tc := range testCases { - tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() @@ -3247,7 +3241,6 @@ answer1 [type=median index=0]; } for _, tc := range testCases { - tc := tc t.Run(tc.name, func(t *testing.T) { svc := setupTestServiceCfg(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.OCR2.Enabled = testutils.Ptr(true) @@ -3837,7 +3830,6 @@ updateInterval = "20m" } for _, tc := range testCases { - tc := tc t.Run(tc.name, func(t *testing.T) { svc := setupTestServiceCfg(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.OCR2.Enabled = testutils.Ptr(true) @@ -4356,7 +4348,6 @@ func Test_Service_ApproveSpec_Stream(t *testing.T) { } for _, tc := range testCases { - tc := tc t.Run(tc.name, func(t *testing.T) { svc := setupTestServiceCfg(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.OCR2.Enabled = testutils.Ptr(true) @@ -4900,7 +4891,6 @@ chainID = 0 } for _, tc := range testCases { - tc := tc t.Run(tc.name, func(t *testing.T) { svc := setupTestServiceCfg(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.OCR2.Enabled = testutils.Ptr(true) @@ -5044,8 +5034,6 @@ func Test_Service_RejectSpec(t *testing.T) { } for _, tc := range testCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { t.Parallel() @@ -5136,7 +5124,6 @@ func Test_Service_UpdateSpecDefinition(t *testing.T) { } for _, tc := range testCases { - tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() @@ -5218,8 +5205,6 @@ func Test_Service_StartStop(t *testing.T) { } for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -5254,6 +5239,186 @@ func logMessages(logEntries []observer.LoggedEntry) []string { return messages } +func Test_Service_GetJobRuns(t *testing.T) { + t.Parallel() + + var ( + remoteUUID = uuid.New() + feedsManagerID = int64(1) + jobID = int32(100) + args = &feeds.GetJobRunsArgs{ + FeedsManagerID: feedsManagerID, + RemoteUUID: remoteUUID, + Limit: 10, + } + + baseTime = time.Date(2024, 1, 15, 12, 0, 0, 0, time.UTC) + createdAt1 = baseTime.Add(-2 * time.Hour) + finishedAt1 = baseTime.Add(-1 * time.Hour) + createdAt2 = baseTime.Add(-1 * time.Hour) + createdAt3 = baseTime.Add(-30 * time.Minute) + finishedAt3 = baseTime.Add(-10 * time.Minute) + + testJob = job.Job{ + ID: jobID, + ExternalJobID: remoteUUID, + Name: null.StringFrom("test job"), + Type: "directrequest", + } + + run1 = pipeline.Run{ + ID: 1, + State: pipeline.RunStatusCompleted, + CreatedAt: createdAt1, + FinishedAt: null.TimeFrom(finishedAt1), + AllErrors: pipeline.RunErrors{null.StringFrom("test error"), null.String{}}, + FatalErrors: pipeline.RunErrors{null.String{}, null.String{}}, + } + + run2 = pipeline.Run{ + ID: 2, + State: pipeline.RunStatusErrored, + CreatedAt: createdAt2, + FinishedAt: null.Time{}, + AllErrors: pipeline.RunErrors{null.String{}, null.StringFrom("fatal error")}, + FatalErrors: pipeline.RunErrors{null.String{}, null.StringFrom("fatal error")}, + } + + run3 = pipeline.Run{ + ID: 3, + State: pipeline.RunStatusCompleted, + CreatedAt: createdAt3, + FinishedAt: null.TimeFrom(finishedAt3), + AllErrors: pipeline.RunErrors{null.String{}, null.String{}}, + FatalErrors: pipeline.RunErrors{null.String{}, null.String{}}, + } + ) + + testCases := []struct { + name string + args *feeds.GetJobRunsArgs + before func(svc *TestService) + want int + wantErr string + }{ + { + name: "success - returns job runs", + args: args, + before: func(svc *TestService) { + svc.jobORM.EXPECT().FindJobByExternalJobID(mock.Anything, remoteUUID).Return(testJob, nil) + svc.orm.EXPECT().IsJobManagedByFeedsManager(mock.Anything, int64(jobID), feedsManagerID).Return(true, nil) + svc.jobORM.EXPECT().PipelineRuns(mock.Anything, &jobID, 0, 10).Return([]pipeline.Run{run1, run2, run3}, 3, nil) + }, + want: 3, + }, + { + name: "success - returns limited job runs", + args: &feeds.GetJobRunsArgs{ + FeedsManagerID: feedsManagerID, + RemoteUUID: remoteUUID, + Limit: 2, + }, + before: func(svc *TestService) { + svc.jobORM.EXPECT().FindJobByExternalJobID(mock.Anything, remoteUUID).Return(testJob, nil) + svc.orm.EXPECT().IsJobManagedByFeedsManager(mock.Anything, int64(jobID), feedsManagerID).Return(true, nil) + svc.jobORM.EXPECT().PipelineRuns(mock.Anything, &jobID, 0, 2).Return([]pipeline.Run{run1, run2}, 3, nil) + }, + want: 2, + }, + { + name: "error - job not found", + args: args, + before: func(svc *TestService) { + svc.jobORM.EXPECT().FindJobByExternalJobID(mock.Anything, remoteUUID).Return(job.Job{}, sql.ErrNoRows) + }, + wantErr: "job not found", + }, + { + name: "error - job ORM error", + args: args, + before: func(svc *TestService) { + svc.jobORM.EXPECT().FindJobByExternalJobID(mock.Anything, remoteUUID).Return(job.Job{}, errors.New("database error")) + }, + wantErr: "failed to find job", + }, + { + name: "error - feeds manager check fails", + args: args, + before: func(svc *TestService) { + svc.jobORM.EXPECT().FindJobByExternalJobID(mock.Anything, remoteUUID).Return(testJob, nil) + svc.orm.EXPECT().IsJobManagedByFeedsManager(mock.Anything, int64(jobID), feedsManagerID).Return(false, errors.New("database error")) + }, + wantErr: "failed to check if job is managed by feeds manager", + }, + { + name: "error - job not managed by feeds manager", + args: args, + before: func(svc *TestService) { + svc.jobORM.EXPECT().FindJobByExternalJobID(mock.Anything, remoteUUID).Return(testJob, nil) + svc.orm.EXPECT().IsJobManagedByFeedsManager(mock.Anything, int64(jobID), feedsManagerID).Return(false, nil) + }, + wantErr: "job is not managed by the requesting feeds manager", + }, + { + name: "error - pipeline runs fetch fails", + args: args, + before: func(svc *TestService) { + svc.jobORM.EXPECT().FindJobByExternalJobID(mock.Anything, remoteUUID).Return(testJob, nil) + svc.orm.EXPECT().IsJobManagedByFeedsManager(mock.Anything, int64(jobID), feedsManagerID).Return(true, nil) + svc.jobORM.EXPECT().PipelineRuns(mock.Anything, &jobID, 0, 10).Return([]pipeline.Run{}, 0, errors.New("database error")) + }, + wantErr: "failed to fetch job runs", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + svc := setupTestService(t) + + if tc.before != nil { + tc.before(svc) + } + + actual, err := svc.GetJobRuns(testutils.Context(t), tc.args) + + if tc.wantErr != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), tc.wantErr) + assert.Nil(t, actual) + } else { + require.NoError(t, err) + assert.Len(t, actual, tc.want) + + if tc.want > 0 { + expectedRuns := []pipeline.Run{run1, run2, run3} + expectedSummaries := make([]*proto.JobRunSummary, 0, tc.want) + + for i := 0; i < tc.want; i++ { + run := expectedRuns[i] + var finishedAt *timestamppb.Timestamp + if run.FinishedAt.Valid { + finishedAt = timestamppb.New(run.FinishedAt.Time) + } + + expectedSummaries = append(expectedSummaries, &proto.JobRunSummary{ + RunId: run.ID, + State: string(run.State), + CreatedAt: timestamppb.New(run.CreatedAt), + FinishedAt: finishedAt, + AllErrors: feeds.ConvertPipelineRunErrors(run.AllErrors), + FatalErrors: feeds.ConvertPipelineRunErrors(run.FatalErrors), + }) + } + + assert.ElementsMatch(t, expectedSummaries, actual) + } + } + }) + } +} + func waitSyncNodeInfoCall(t *testing.T, logs *observer.ObservedLogs) { assert.EventuallyWithT(t, func(collect *assert.CollectT) { assert.Contains(collect, logMessages(logs.All()), "successfully synced node info") diff --git a/deployment/go.mod b/deployment/go.mod index 42059939af2..a682c548487 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -44,7 +44,7 @@ require ( github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250729142306-508e798f6a5d github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b0b4605 github.com/smartcontractkit/chainlink-protos/job-distributor v0.13.1 - github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1 + github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 github.com/smartcontractkit/chainlink-solana v1.1.2-0.20250905170534-87e867e6cf31 github.com/smartcontractkit/chainlink-testing-framework/lib v1.54.4 github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e diff --git a/deployment/go.sum b/deployment/go.sum index 96828dd93b7..dc4b1f43e52 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1302,8 +1302,8 @@ github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b0b4605/go.mod h1:jUC52kZzEnWF9tddHh85zolKybmLpbQ1oNA4FjOHt1Q= github.com/smartcontractkit/chainlink-protos/job-distributor v0.13.1 h1:PWwLGimBt37eDzpbfZ9V/ZkW4oCjcwKjKiAwKlSfPc0= github.com/smartcontractkit/chainlink-protos/job-distributor v0.13.1/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= -github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1 h1:VcFo27MBPTMB1d1Tp3q3RzJNqwErKR+z9QLQZ6KBSXo= -github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= +github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 h1:0eroOyBwmdoGUwUdvMI0/J7m5wuzNnJDMglSOK1sfNY= +github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 h1:L6KJ4kGv/yNNoCk8affk7Y1vAY0qglPMXC/hevV/IsA= github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6/go.mod h1:FRwzI3hGj4CJclNS733gfcffmqQ62ONCkbGi49s658w= github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 h1:B7itmjy+CMJ26elVw/cAJqqhBQ3Xa/mBYWK0/rQ5MuI= diff --git a/go.mod b/go.mod index 593d0199dbe..6e70f4f517c 100644 --- a/go.mod +++ b/go.mod @@ -94,7 +94,7 @@ require ( github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250729142306-508e798f6a5d github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20250722225531-876fd6b94976 github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b0b4605 - github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1 + github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20250822025801-598d3d86f873 github.com/smartcontractkit/chainlink-solana v1.1.2-0.20250905170534-87e867e6cf31 diff --git a/go.sum b/go.sum index b2bf387b9b0..8b0340cd7a9 100644 --- a/go.sum +++ b/go.sum @@ -1136,8 +1136,8 @@ github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20250722225531-87 github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20250722225531-876fd6b94976/go.mod h1:HHGeDUpAsPa0pmOx7wrByCitjQ0mbUxf0R9v+g67uCA= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b0b4605 h1:yVH5tLDzW2ZBUpmkHF5nci1SRSXTcU3A1VZ8iS5qudA= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b0b4605/go.mod h1:jUC52kZzEnWF9tddHh85zolKybmLpbQ1oNA4FjOHt1Q= -github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1 h1:VcFo27MBPTMB1d1Tp3q3RzJNqwErKR+z9QLQZ6KBSXo= -github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= +github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 h1:0eroOyBwmdoGUwUdvMI0/J7m5wuzNnJDMglSOK1sfNY= +github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 h1:L6KJ4kGv/yNNoCk8affk7Y1vAY0qglPMXC/hevV/IsA= github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6/go.mod h1:FRwzI3hGj4CJclNS733gfcffmqQ62ONCkbGi49s658w= github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 h1:B7itmjy+CMJ26elVw/cAJqqhBQ3Xa/mBYWK0/rQ5MuI= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 2803e0eff35..2e40ea5a970 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -486,7 +486,7 @@ require ( github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250729142306-508e798f6a5d // indirect github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20250722225531-876fd6b94976 // indirect github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b0b4605 // indirect - github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1 // indirect + github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 // indirect github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 // indirect github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 // indirect github.com/smartcontractkit/chainlink-protos/svr v1.1.0 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 285989ba57a..013bf223532 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1554,8 +1554,8 @@ github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b0b4605/go.mod h1:jUC52kZzEnWF9tddHh85zolKybmLpbQ1oNA4FjOHt1Q= github.com/smartcontractkit/chainlink-protos/job-distributor v0.13.1 h1:PWwLGimBt37eDzpbfZ9V/ZkW4oCjcwKjKiAwKlSfPc0= github.com/smartcontractkit/chainlink-protos/job-distributor v0.13.1/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= -github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1 h1:VcFo27MBPTMB1d1Tp3q3RzJNqwErKR+z9QLQZ6KBSXo= -github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= +github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 h1:0eroOyBwmdoGUwUdvMI0/J7m5wuzNnJDMglSOK1sfNY= +github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 h1:L6KJ4kGv/yNNoCk8affk7Y1vAY0qglPMXC/hevV/IsA= github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6/go.mod h1:FRwzI3hGj4CJclNS733gfcffmqQ62ONCkbGi49s658w= github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 h1:B7itmjy+CMJ26elVw/cAJqqhBQ3Xa/mBYWK0/rQ5MuI= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 87b1dc16121..8187cea977b 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -476,7 +476,7 @@ require ( github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20250722225531-876fd6b94976 // indirect github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b0b4605 // indirect github.com/smartcontractkit/chainlink-protos/job-distributor v0.13.1 // indirect - github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1 // indirect + github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 // indirect github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 // indirect github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 // indirect github.com/smartcontractkit/chainlink-protos/svr v1.1.0 // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 241abebd441..cb50c590647 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1530,8 +1530,8 @@ github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b0b4605/go.mod h1:jUC52kZzEnWF9tddHh85zolKybmLpbQ1oNA4FjOHt1Q= github.com/smartcontractkit/chainlink-protos/job-distributor v0.13.1 h1:PWwLGimBt37eDzpbfZ9V/ZkW4oCjcwKjKiAwKlSfPc0= github.com/smartcontractkit/chainlink-protos/job-distributor v0.13.1/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= -github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1 h1:VcFo27MBPTMB1d1Tp3q3RzJNqwErKR+z9QLQZ6KBSXo= -github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= +github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 h1:0eroOyBwmdoGUwUdvMI0/J7m5wuzNnJDMglSOK1sfNY= +github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 h1:L6KJ4kGv/yNNoCk8affk7Y1vAY0qglPMXC/hevV/IsA= github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6/go.mod h1:FRwzI3hGj4CJclNS733gfcffmqQ62ONCkbGi49s658w= github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 h1:B7itmjy+CMJ26elVw/cAJqqhBQ3Xa/mBYWK0/rQ5MuI= diff --git a/system-tests/lib/go.mod b/system-tests/lib/go.mod index 386bb8e902c..64af4873ccd 100644 --- a/system-tests/lib/go.mod +++ b/system-tests/lib/go.mod @@ -457,7 +457,7 @@ require ( github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20250717121125-2350c82883e2 // indirect github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250729142306-508e798f6a5d // indirect github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20250722225531-876fd6b94976 // indirect - github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1 // indirect + github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 // indirect github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 // indirect github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 // indirect github.com/smartcontractkit/chainlink-protos/svr v1.1.0 // indirect diff --git a/system-tests/lib/go.sum b/system-tests/lib/go.sum index bae82dbb4a1..9a30e72be34 100644 --- a/system-tests/lib/go.sum +++ b/system-tests/lib/go.sum @@ -1546,8 +1546,8 @@ github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b0b4605/go.mod h1:jUC52kZzEnWF9tddHh85zolKybmLpbQ1oNA4FjOHt1Q= github.com/smartcontractkit/chainlink-protos/job-distributor v0.13.1 h1:PWwLGimBt37eDzpbfZ9V/ZkW4oCjcwKjKiAwKlSfPc0= github.com/smartcontractkit/chainlink-protos/job-distributor v0.13.1/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= -github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1 h1:VcFo27MBPTMB1d1Tp3q3RzJNqwErKR+z9QLQZ6KBSXo= -github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= +github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 h1:0eroOyBwmdoGUwUdvMI0/J7m5wuzNnJDMglSOK1sfNY= +github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 h1:L6KJ4kGv/yNNoCk8affk7Y1vAY0qglPMXC/hevV/IsA= github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6/go.mod h1:FRwzI3hGj4CJclNS733gfcffmqQ62ONCkbGi49s658w= github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 h1:B7itmjy+CMJ26elVw/cAJqqhBQ3Xa/mBYWK0/rQ5MuI= diff --git a/system-tests/tests/go.mod b/system-tests/tests/go.mod index 6d63ad93a10..4168fc1db25 100644 --- a/system-tests/tests/go.mod +++ b/system-tests/tests/go.mod @@ -526,7 +526,7 @@ require ( github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20250717121125-2350c82883e2 // indirect github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250729142306-508e798f6a5d // indirect github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20250722225531-876fd6b94976 // indirect - github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1 // indirect + github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 // indirect github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 // indirect github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 // indirect github.com/smartcontractkit/chainlink-protos/svr v1.1.0 // indirect diff --git a/system-tests/tests/go.sum b/system-tests/tests/go.sum index ca6f32e1e18..9f03dfcb92b 100644 --- a/system-tests/tests/go.sum +++ b/system-tests/tests/go.sum @@ -1749,8 +1749,8 @@ github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250829155125-f4655b0b4605/go.mod h1:jUC52kZzEnWF9tddHh85zolKybmLpbQ1oNA4FjOHt1Q= github.com/smartcontractkit/chainlink-protos/job-distributor v0.13.1 h1:PWwLGimBt37eDzpbfZ9V/ZkW4oCjcwKjKiAwKlSfPc0= github.com/smartcontractkit/chainlink-protos/job-distributor v0.13.1/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= -github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1 h1:VcFo27MBPTMB1d1Tp3q3RzJNqwErKR+z9QLQZ6KBSXo= -github.com/smartcontractkit/chainlink-protos/orchestrator v0.8.1/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= +github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 h1:0eroOyBwmdoGUwUdvMI0/J7m5wuzNnJDMglSOK1sfNY= +github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 h1:L6KJ4kGv/yNNoCk8affk7Y1vAY0qglPMXC/hevV/IsA= github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6/go.mod h1:FRwzI3hGj4CJclNS733gfcffmqQ62ONCkbGi49s658w= github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 h1:B7itmjy+CMJ26elVw/cAJqqhBQ3Xa/mBYWK0/rQ5MuI=