Skip to content

Commit

Permalink
always write index data for VDR, never check on duplicate (#2141)
Browse files Browse the repository at this point in the history
  • Loading branch information
woutslakhorst committed May 15, 2023
1 parent 6dbb6d7 commit 338621b
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 55 deletions.
14 changes: 14 additions & 0 deletions vdr/didstore/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ func (e event) before(other event) bool {
return e.Ref.Compare(other.Ref) < 0
}

// equal returns true when event.Ref are equal.
func (e event) equal(other event) bool {
return e.Ref.Equals(other.Ref)
}

// eventList is an in-memory representation of an Events shelf entry
type eventList struct {
Events []event `json:"events"`
Expand Down Expand Up @@ -92,3 +97,12 @@ func (el *eventList) insert(newEvent event) int {
el.Events = newList
return index
}

func (el *eventList) contains(newEvent event) bool {
for _, e := range el.Events {
if e.equal(newEvent) {
return true
}
}
return false
}
15 changes: 15 additions & 0 deletions vdr/didstore/event_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,18 @@ func TestEventList_insert(t *testing.T) {
assert.Equal(t, sha2s, el.Events[2].Ref)
})
}

func TestEventList_contains(t *testing.T) {
t.Run("false", func(t *testing.T) {
el := eventList{}

assert.False(t, el.contains(event{Ref: sha0s}))
})

t.Run("true", func(t *testing.T) {
el := eventList{}
el.insert(event{Ref: sha0s})

assert.True(t, el.contains(event{Ref: sha0s}))
})
}
9 changes: 0 additions & 9 deletions vdr/didstore/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,3 @@ func readEventList(tx stoabs.ReadTx, id did.DID) (eventList, error) {
}
return el, nil
}

func transactionExists(tx stoabs.ReadTx, ref hash.SHA256Hash) (bool, error) {
txReader := tx.GetShelfReader(transactionIndexShelf)
bytes, err := txReader.Get(stoabs.HashKey(ref))
if err != nil && !errors.Is(err, stoabs.ErrKeyNotFound) {
return false, err
}
return len(bytes) > 0, nil
}
35 changes: 0 additions & 35 deletions vdr/didstore/reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,38 +96,3 @@ func Test_readEventList(t *testing.T) {
require.NoError(t, err)
})
}

func Test_transactionExists(t *testing.T) {
store := NewTestStore(t)

t.Run("false", func(t *testing.T) {
err := store.db.Read(context.Background(), func(tx stoabs.ReadTx) error {
dup, _ := transactionExists(tx, hash.RandomHash())

assert.False(t, dup)

return nil
})
require.NoError(t, err)
})

t.Run("true", func(t *testing.T) {
transaction := newTestTransaction(did.Document{})

err := store.db.Write(context.Background(), func(tx stoabs.WriteTx) error {
txShelf := tx.GetShelfWriter(transactionIndexShelf)
_ = txShelf.Put(stoabs.HashKey(transaction.Ref), []byte{0})
return nil
})
require.NoError(t, err)

err = store.db.Read(context.Background(), func(tx stoabs.ReadTx) error {
dup, _ := transactionExists(tx, transaction.Ref)

assert.True(t, dup)

return nil
})
require.NoError(t, err)
})
}
29 changes: 18 additions & 11 deletions vdr/didstore/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,33 +75,40 @@ func (tl *store) Configure(_ core.ServerConfig) (err error) {
// Add inserts the document version at the correct place and updates all later versions if needed
// The integrity of the document has already been checked by the DAG.
func (tl *store) Add(didDocument did.Document, transaction Transaction) error {
// prevents parallel execution
// First write the document and transaction to the transactionIndexShelf and documentShelf.
// This operation is duplicate save, since it uses hash values as key.
// This operation must succeed because otherwise the second transaction will be broken forever.
// Due to the way Redis works, there's no guarantee all the data is written transactionally when
// executed in a single write operation.
err := tl.db.Write(context.Background(), func(tx stoabs.WriteTx) error {
if exists, err := transactionExists(tx, transaction.Ref); err != nil {
return err
} else if exists {
return nil
// write document to documentShelf
err := writeDocument(tx, didDocument, transaction)
if err != nil {
return fmt.Errorf("writeDocument failed: %w", err)
}
return nil
}, stoabs.WithWriteLock())
if err != nil {
return fmt.Errorf("database error on commit: %w", err)
}

err = tl.db.Write(context.Background(), func(tx stoabs.WriteTx) error {
currentEventList, err := readEventList(tx, didDocument.ID)
if err != nil {
return fmt.Errorf("read eventList failed: %w", err)
}

// write document to documentShelf
err = writeDocument(tx, didDocument, transaction)
if err != nil {
return fmt.Errorf("writeDocument failed: %w", err)
transaction.document = &didDocument
if currentEventList.contains(event(transaction)) {
return nil
}

transaction.document = &didDocument
index := currentEventList.insert(event(transaction))
var base *event
applyList := currentEventList.Events[index:]
if index > 0 {
base = &currentEventList.Events[index-1]
}

if err = applyFrom(tx, base, applyList); err != nil {
return fmt.Errorf("applying event list failed: %w", err)
}
Expand Down
31 changes: 31 additions & 0 deletions vdr/didstore/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,37 @@ func TestStore_Add(t *testing.T) {
})
})

t.Run("duplicate ok", func(t *testing.T) {
store := NewTestStore(t)

require.NoError(t, store.Add(create, txCreate))
require.NoError(t, store.Add(create, txCreate))

err := store.db.ReadShelf(context.Background(), metadataShelf, func(reader stoabs.Reader) error {
metaBytes, err := reader.Get(stoabs.BytesKey(fmt.Sprintf("%s0", testDID.String())))
if err != nil {
return err
}
metadata := documentMetadata{}
err = json.Unmarshal(metaBytes, &metadata)
if err != nil {
return err
}

assert.Equal(t, txCreate.SigningTime.Unix(), metadata.Created.Unix())
assert.Equal(t, txCreate.SigningTime.Unix(), metadata.Updated.Unix())
assert.Nil(t, metadata.PreviousHash)
assert.Equal(t, txCreate.PayloadHash, metadata.Hash)
assert.Nil(t, metadata.PreviousTransaction)
assert.Equal(t, []hash.SHA256Hash{txCreate.Ref}, metadata.SourceTransactions)
assert.Equal(t, 0, metadata.Version)
assert.Equal(t, false, metadata.Deactivated)

return nil
})
require.NoError(t, err)
})

t.Run("update ok", func(t *testing.T) {
store := NewTestStore(t)

Expand Down

0 comments on commit 338621b

Please sign in to comment.