Skip to content

Commit

Permalink
remove references to tag
Browse files Browse the repository at this point in the history
  • Loading branch information
woutslakhorst committed May 8, 2024
1 parent 8f0827e commit b657499
Show file tree
Hide file tree
Showing 13 changed files with 86 additions and 110 deletions.
1 change: 0 additions & 1 deletion discovery/api/server/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ func (w *Wrapper) Routes(router core.EchoRouter) {
func (w *Wrapper) GetPresentations(_ context.Context, request GetPresentationsRequestObject) (GetPresentationsResponseObject, error) {
var timestamp int
if request.Params.Timestamp != nil {
// *string to *Tag
timestamp = *request.Params.Timestamp
}
presentations, newTimestamp, err := w.Server.Get(request.ServiceID, timestamp)
Expand Down
19 changes: 9 additions & 10 deletions discovery/api/server/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,35 +35,34 @@ const serviceID = "wonderland"
var subjectDID = did.MustParseDID("did:web:example.com")

func TestWrapper_GetPresentations(t *testing.T) {
beginning := 0
latestTag := 1
lastTimestamp := 1
presentations := map[string]vc.VerifiablePresentation{}
t.Run("no tag", func(t *testing.T) {
t.Run("no timestamp", func(t *testing.T) {
test := newMockContext(t)
test.server.EXPECT().Get(serviceID, beginning).Return(presentations, &latestTag, nil)
test.server.EXPECT().Get(serviceID, 0).Return(presentations, &lastTimestamp, nil)

response, err := test.wrapper.GetPresentations(nil, GetPresentationsRequestObject{ServiceID: serviceID})

require.NoError(t, err)
require.IsType(t, GetPresentations200JSONResponse{}, response)
assert.Equal(t, latestTag, response.(GetPresentations200JSONResponse).Timestamp)
assert.Equal(t, lastTimestamp, response.(GetPresentations200JSONResponse).Timestamp)
assert.Equal(t, presentations, response.(GetPresentations200JSONResponse).Entries)
})
t.Run("with tag", func(t *testing.T) {
givenTag := 1
t.Run("with timestamp", func(t *testing.T) {
givenTimestamp := 1
test := newMockContext(t)
test.server.EXPECT().Get(serviceID, 1).Return(presentations, &latestTag, nil)
test.server.EXPECT().Get(serviceID, 1).Return(presentations, &lastTimestamp, nil)

response, err := test.wrapper.GetPresentations(nil, GetPresentationsRequestObject{
ServiceID: serviceID,
Params: GetPresentationsParams{
Timestamp: &givenTag,
Timestamp: &givenTimestamp,
},
})

require.NoError(t, err)
require.IsType(t, GetPresentations200JSONResponse{}, response)
assert.Equal(t, latestTag, response.(GetPresentations200JSONResponse).Timestamp)
assert.Equal(t, lastTimestamp, response.(GetPresentations200JSONResponse).Timestamp)
assert.Equal(t, presentations, response.(GetPresentations200JSONResponse).Entries)
})
t.Run("error", func(t *testing.T) {
Expand Down
17 changes: 8 additions & 9 deletions discovery/api/server/client/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,38 +62,37 @@ func TestHTTPInvoker_Get(t *testing.T) {
Context: []ssi.URI{ssi.MustParseURI("https://www.w3.org/2018/credentials/v1")},
}

serverTag := 2
t.Run("no tag from client", func(t *testing.T) {
t.Run("no timestamp from client", func(t *testing.T) {
handler := &testHTTP.Handler{StatusCode: http.StatusOK}
handler.ResponseData = map[string]interface{}{
"entries": map[string]interface{}{"1": vp},
"timestamp": serverTag,
"timestamp": 2,
}
server := httptest.NewServer(handler)
client := New(false, time.Minute, server.TLS)

presentations, tag, err := client.Get(context.Background(), server.URL, 0)
presentations, timestamp, err := client.Get(context.Background(), server.URL, 0)

assert.NoError(t, err)
assert.Len(t, presentations, 1)
assert.Equal(t, "0", handler.RequestQuery.Get("timestamp"))
assert.Equal(t, serverTag, tag)
assert.Equal(t, 1, timestamp)
})
t.Run("tag provided by client", func(t *testing.T) {
t.Run("timestamp provided by client", func(t *testing.T) {
handler := &testHTTP.Handler{StatusCode: http.StatusOK}
handler.ResponseData = map[string]interface{}{
"entries": map[string]interface{}{"1": vp},
"timestamp": serverTag,
"timestamp": 1,
}
server := httptest.NewServer(handler)
client := New(false, time.Minute, server.TLS)

presentations, tag, err := client.Get(context.Background(), server.URL, 1)
presentations, timestamp, err := client.Get(context.Background(), server.URL, 1)

assert.NoError(t, err)
assert.Len(t, presentations, 1)
assert.Equal(t, "1", handler.RequestQuery.Get("timestamp"))
assert.Equal(t, serverTag, tag)
assert.Equal(t, 1, timestamp)
})
t.Run("server returns invalid status code", func(t *testing.T) {
handler := &testHTTP.Handler{StatusCode: http.StatusInternalServerError}
Expand Down
4 changes: 2 additions & 2 deletions discovery/api/server/client/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type HTTPClient interface {
Register(ctx context.Context, serviceEndpointURL string, presentation vc.VerifiablePresentation) error

// Get retrieves Verifiable Presentations from the remote Discovery Service, that were added since the given timestamp.
// If the call succeeds it returns the Verifiable Presentations and the tag that was returned by the server.
// If timestamp is 0, all Verifiable Presentations are retrieved.
// If the call succeeds it returns the Verifiable Presentations and the timestamp that was returned by the server.
// If the given timestamp is 0, all Verifiable Presentations are retrieved.
Get(ctx context.Context, serviceEndpointURL string, timestamp int) (map[string]vc.VerifiablePresentation, int, error)
}
2 changes: 1 addition & 1 deletion discovery/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ func (u *clientUpdater) updateService(ctx context.Context, service ServiceDefini
log.Logger().WithError(err).Warnf("Presentation verification failed, not adding it (service=%s, id=%s)", service.ID, presentation.ID)
continue
}
if err := u.store.addAsClient(service.ID, presentation, serverTimestamp); err != nil {
if err := u.store.add(service.ID, presentation, serverTimestamp); err != nil {
return fmt.Errorf("failed to store presentation (service=%s, id=%s): %w", service.ID, presentation.ID, err)
}
log.Logger().
Expand Down
8 changes: 4 additions & 4 deletions discovery/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ func Test_scheduledRegistrationManager_deregister(t *testing.T) {
mockVCR.EXPECT().Wallet().Return(wallet).AnyTimes()
store := setupStore(t, storageEngine.GetSQLDatabase())
manager := newRegistrationManager(testDefinitions(), store, invoker, mockVCR)
require.NoError(t, store.addAsClient(testServiceID, vpAlice, 1))
require.NoError(t, store.add(testServiceID, vpAlice, 1))

err := manager.deactivate(audit.TestContext(), testServiceID, aliceDID)

Expand All @@ -167,7 +167,7 @@ func Test_scheduledRegistrationManager_deregister(t *testing.T) {
mockVCR.EXPECT().Wallet().Return(wallet).AnyTimes()
store := setupStore(t, storageEngine.GetSQLDatabase())
manager := newRegistrationManager(testDefinitions(), store, invoker, mockVCR)
require.NoError(t, store.addAsClient(testServiceID, vpAlice, 1))
require.NoError(t, store.add(testServiceID, vpAlice, 1))

err := manager.deactivate(audit.TestContext(), testServiceID, aliceDID)

Expand Down Expand Up @@ -274,11 +274,11 @@ func Test_clientUpdater_updateService(t *testing.T) {
require.NoError(t, err)
require.False(t, exists)
})
t.Run("pass tag", func(t *testing.T) {
t.Run("pass timestamp", func(t *testing.T) {
resetStore(t, storageEngine.GetSQLDatabase())
ctrl := gomock.NewController(t)
httpClient := client.NewMockHTTPClient(ctrl)
err := store.updateTagForClient(store.db, testServiceID, 1)
err := store.setTimestamp(store.db, testServiceID, 1)
require.NoError(t, err)
updater := newClientUpdater(testDefinitions(), store, alwaysOkVerifier, httpClient)

Expand Down
4 changes: 2 additions & 2 deletions discovery/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type Server interface {
// Register registers a presentation on the given Discovery Service.
// If the presentation is not valid, or it does not conform to the Service ServiceDefinition, it returns an error.
Register(serviceID string, presentation vc.VerifiablePresentation) error
// Get retrieves the presentations for the given service, starting at the given Timestamp.
// Get retrieves the presentations for the given service, starting from the given Timestamp.
Get(serviceID string, startAt int) (map[string]vc.VerifiablePresentation, *int, error)
}

Expand All @@ -65,7 +65,7 @@ type Client interface {
Services() []ServiceDefinition

// GetServiceActivation returns the activation status of a DID on a Discovery Service.
// The boolean indicates whether the DID is acitvated on the Discovery Service (ActivateServiceForDID() has been called).
// The boolean indicates whether the DID is activated on the Discovery Service (ActivateServiceForDID() has been called).
// It also returns the Verifiable Presentation that is registered on the Discovery Service, if any.
GetServiceActivation(ctx context.Context, serviceID string, subjectDID did.DID) (bool, *vc.VerifiablePresentation, error)
}
Expand Down
4 changes: 2 additions & 2 deletions discovery/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ func (m *Module) Register(serviceID string, presentation vc.VerifiablePresentati
return err
}

return m.store.addAsServer(serviceID, presentation)
return m.store.add(serviceID, presentation, 0)
}

func (m *Module) verifyRegistration(definition ServiceDefinition, presentation vc.VerifiablePresentation) error {
Expand Down Expand Up @@ -272,7 +272,7 @@ func (m *Module) validateRetraction(serviceID string, presentation vc.Verifiable
return nil
}

// Get is a Discovery Server function that retrieves the presentations for the given service, starting at the given tag.
// Get is a Discovery Server function that retrieves the presentations for the given service, starting from the given timestamp.
// See interface.go for more information.
func (m *Module) Get(serviceID string, startAfter int) (map[string]vc.VerifiablePresentation, *int, error) {
_, exists := m.serverDefinitions[serviceID]
Expand Down
24 changes: 12 additions & 12 deletions discovery/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ func Test_Module_Register(t *testing.T) {
err := m.Register(testServiceID, vpAlice)
require.EqualError(t, err, "presentation is invalid for registration\npresentation verification failed: failed")

_, tag, err := m.Get(testServiceID, 0)
_, timestamp, err := m.Get(testServiceID, 0)
require.NoError(t, err)
assert.Equal(t, 0, *tag)
assert.Equal(t, 0, *timestamp)
})
t.Run("already exists", func(t *testing.T) {
m, presentationVerifier, _ := setupModule(t, storageEngine)
Expand Down Expand Up @@ -118,9 +118,9 @@ func Test_Module_Register(t *testing.T) {
err := m.Register(testServiceID, vpAlice)
require.NoError(t, err)

_, tag, err := m.Get(testServiceID, 0)
_, timestamp, err := m.Get(testServiceID, 0)
require.NoError(t, err)
assert.Equal(t, 1, *tag)
assert.Equal(t, 1, *timestamp)
})
t.Run("valid longer than its credentials", func(t *testing.T) {
m, _, _ := setupModule(t, storageEngine)
Expand All @@ -145,8 +145,8 @@ func Test_Module_Register(t *testing.T) {
err := m.Register(testServiceID, otherVP)
require.ErrorContains(t, err, "presentation does not fulfill Presentation ServiceDefinition")

_, tag, _ := m.Get(testServiceID, 0)
assert.Equal(t, 0, *tag)
_, timestamp, _ := m.Get(testServiceID, 0)
assert.Equal(t, 0, *timestamp)
})
})
t.Run("retraction", func(t *testing.T) {
Expand Down Expand Up @@ -215,15 +215,15 @@ func Test_Module_Get(t *testing.T) {
require.NoError(t, storageEngine.Start())
t.Run("ok", func(t *testing.T) {
m, _, _ := setupModule(t, storageEngine)
require.NoError(t, m.store.addAsServer(testServiceID, vpAlice))
presentations, tag, err := m.Get(testServiceID, 0)
require.NoError(t, m.store.add(testServiceID, vpAlice, 0))
presentations, timestamp, err := m.Get(testServiceID, 0)
assert.NoError(t, err)
assert.Equal(t, map[string]vc.VerifiablePresentation{"1": vpAlice}, presentations)
assert.Equal(t, 1, *tag)
assert.Equal(t, 1, *timestamp)
})
t.Run("ok - retrieve delta", func(t *testing.T) {
m, _, _ := setupModule(t, storageEngine)
require.NoError(t, m.store.addAsServer(testServiceID, vpAlice))
require.NoError(t, m.store.add(testServiceID, vpAlice, 0))
presentations, _, err := m.Get(testServiceID, 0)
require.NoError(t, err)
require.Len(t, presentations, 1)
Expand Down Expand Up @@ -316,7 +316,7 @@ func TestModule_Search(t *testing.T) {
require.NoError(t, storageEngine.Start())
t.Run("ok", func(t *testing.T) {
m, _, _ := setupModule(t, storageEngine)
require.NoError(t, m.store.addAsServer(testServiceID, vpAlice))
require.NoError(t, m.store.add(testServiceID, vpAlice, 0))
results, err := m.Search(testServiceID, map[string]string{
"credentialSubject.id": aliceDID.String(),
})
Expand Down Expand Up @@ -452,7 +452,7 @@ func TestModule_GetServiceActivation(t *testing.T) {
m, _, _ := setupModule(t, storageEngine)
next := time.Now()
_ = m.store.updatePresentationRefreshTime(testServiceID, aliceDID, &next)
_ = m.store.addAsServer(testServiceID, vpAlice)
_ = m.store.add(testServiceID, vpAlice, 0)

activated, presentation, err := m.GetServiceActivation(context.Background(), testServiceID, aliceDID)

Expand Down
51 changes: 15 additions & 36 deletions discovery/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ func newSQLStore(db *gorm.DB, clientDefinitions map[string]ServiceDefinition) (*
return &sqlStore{db: db}, nil
}

// addAsServer adds a presentation to the list of presentations.
// A new Tag is generated for the entry.
func (s *sqlStore) addAsServer(serviceID string, presentation vc.VerifiablePresentation) error {
// add adds a presentation to the list of presentations.
// If the given timestamp is 0, the server will assign a timestamp.
func (s *sqlStore) add(serviceID string, presentation vc.VerifiablePresentation, timestamp int) error {
credentialSubjectID, err := credential.PresentationSigner(presentation)
if err != nil {
return err
Expand All @@ -119,32 +119,13 @@ func (s *sqlStore) addAsServer(serviceID string, presentation vc.VerifiablePrese
return err
}
return s.db.Transaction(func(tx *gorm.DB) error {
newTag, err := s.updateTagForServer(tx, serviceID)
if err != nil {
return err
}
// Delete any previous presentations of the subject
if err := tx.Delete(&presentationRecord{}, "service_id = ? AND credential_subject_id = ?", serviceID, credentialSubjectID.String()).
Error; err != nil {
return err
if timestamp == 0 {
var newTs *int
newTs, err = s.incrementTimestamp(tx, serviceID)
timestamp = *newTs
} else {
err = s.setTimestamp(tx, serviceID, timestamp)
}

return storePresentation(tx, serviceID, *newTag, presentation)
})
}

// addAsClient adds a presentation to the list of presentations.
// the timestamp is given by the server
func (s *sqlStore) addAsClient(serviceID string, presentation vc.VerifiablePresentation, timestamp int) error {
credentialSubjectID, err := credential.PresentationSigner(presentation)
if err != nil {
return err
}
if err := s.prune(); err != nil {
return err
}
return s.db.Transaction(func(tx *gorm.DB) error {
err := s.updateTagForClient(tx, serviceID, timestamp)
if err != nil {
return err
}
Expand Down Expand Up @@ -191,9 +172,8 @@ func storePresentation(tx *gorm.DB, serviceID string, timestamp int, presentatio
return tx.Create(&newPresentation).Error
}

// get returns all presentations, registered on the given service, starting after the given tag.
// It also returns the latest tag of the returned presentations.
// This tag can then be used next time to only retrieve presentations that were added after that tag.
// get returns all presentations, registered on the given service, starting after the given timestamp.
// It also returns the latest timestamp of the returned presentations.
func (s *sqlStore) get(serviceID string, startAfter int) (map[string]vc.VerifiablePresentation, *int, error) {
var service serviceRecord
if err := s.db.Find(&service, "id = ?", serviceID).Error; err != nil {
Expand Down Expand Up @@ -244,9 +224,8 @@ func (s *sqlStore) search(serviceID string, query map[string]string) ([]vc.Verif
return results, nil
}

// updateTagForServer updates the tag of the given service.
// The latest tag for the service is incremented.
func (s *sqlStore) updateTagForServer(tx *gorm.DB, serviceID string) (*int, error) {
// incrementTimestamp increments the last_timestamp of the given service.
func (s *sqlStore) incrementTimestamp(tx *gorm.DB, serviceID string) (*int, error) {
var service serviceRecord
// Lock (SELECT FOR UPDATE) discovery_service row to prevent concurrent updates to the same list, which could mess up the lamport Timestamp.
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
Expand All @@ -264,8 +243,8 @@ func (s *sqlStore) updateTagForServer(tx *gorm.DB, serviceID string) (*int, erro
return &service.LastTimestamp, nil
}

// updateTagForClient updates the tag of the given service.
func (s *sqlStore) updateTagForClient(tx *gorm.DB, serviceID string, timestamp int) error {
// setTimestamp sets the last_timestamp of the given service.
func (s *sqlStore) setTimestamp(tx *gorm.DB, serviceID string, timestamp int) error {
var service serviceRecord
// Lock (SELECT FOR UPDATE) discovery_service row to prevent concurrent updates to the same list, which could mess up the lamport Timestamp.
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
Expand Down
Loading

0 comments on commit b657499

Please sign in to comment.