Try to establish auth difference for state res v2

This commit is contained in:
Neil Alexander 2020-03-04 11:37:23 +00:00
parent 0ec7403c2d
commit 3f31c4d5ca
3 changed files with 133 additions and 13 deletions

2
go.mod
View file

@ -14,7 +14,7 @@ require (
github.com/lib/pq v1.2.0
github.com/matrix-org/dugong v0.0.0-20171220115018-ea0a4690a0d5
github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26
github.com/matrix-org/gomatrixserverlib v0.0.0-20200303114503-f4a1756605cf
github.com/matrix-org/gomatrixserverlib v0.0.0-20200304113232-f827b01e450c
github.com/matrix-org/naffka v0.0.0-20200127221512-0716baaabaf1
github.com/matrix-org/util v0.0.0-20171127121716-2e2df66af2f5
github.com/mattn/go-sqlite3 v2.0.2+incompatible

2
go.sum
View file

@ -73,6 +73,8 @@ github.com/matrix-org/gomatrixserverlib v0.0.0-20200228114906-771d251ca458 h1:xC
github.com/matrix-org/gomatrixserverlib v0.0.0-20200228114906-771d251ca458/go.mod h1:FsKa2pWE/bpQql9H7U4boOPXFoJX/QcqaZZ6ijLkaZI=
github.com/matrix-org/gomatrixserverlib v0.0.0-20200303114503-f4a1756605cf h1:v1wIWdlIICrOyua4oSsw5jrqTJGmRibIL9Mpo1Ro4uc=
github.com/matrix-org/gomatrixserverlib v0.0.0-20200303114503-f4a1756605cf/go.mod h1:FsKa2pWE/bpQql9H7U4boOPXFoJX/QcqaZZ6ijLkaZI=
github.com/matrix-org/gomatrixserverlib v0.0.0-20200304113232-f827b01e450c h1:cQtAr/WkUam8xzWoYaoQVVb+7cqSpjdbG6srtWke1qk=
github.com/matrix-org/gomatrixserverlib v0.0.0-20200304113232-f827b01e450c/go.mod h1:FsKa2pWE/bpQql9H7U4boOPXFoJX/QcqaZZ6ijLkaZI=
github.com/matrix-org/naffka v0.0.0-20200127221512-0716baaabaf1 h1:osLoFdOy+ChQqVUn2PeTDETFftVkl4w9t/OW18g3lnk=
github.com/matrix-org/naffka v0.0.0-20200127221512-0716baaabaf1/go.mod h1:cXoYQIENbdWIQHt1SyCo6Bl3C3raHwJ0wgVrXHSqf+A=
github.com/matrix-org/util v0.0.0-20171127121716-2e2df66af2f5 h1:W7l5CP4V7wPyPb4tYE11dbmeAOwtFQBTW0rf4OonOS8=

View file

@ -557,7 +557,6 @@ func (v StateResolution) calculateAndStoreStateAfterManyEvents(
func (v StateResolution) calculateStateAfterManyEvents(
ctx context.Context,
prevStates []types.StateAtEvent,
) (state []types.StateEntry, algorithm string, conflictLength int, err error) {
var combined []types.StateEntry
@ -608,6 +607,19 @@ func (v StateResolution) calculateStateAfterManyEvents(
return
}
func (v StateResolution) resolveConflicts(
ctx context.Context,
notConflicted, conflicted []types.StateEntry,
) ([]types.StateEntry, error) {
switch v.version {
case StateResolutionAlgorithmV1:
return v.resolveConflictsV1(ctx, notConflicted, conflicted)
case StateResolutionAlgorithmV2:
return v.resolveConflictsV2(ctx, notConflicted, conflicted)
}
return nil, errors.New("unsupported state resolution algorithm")
}
// resolveConflicts resolves a list of conflicted state entries. It takes two lists.
// The first is a list of all state entries that are not conflicted.
// The second is a list of all state entries that are conflicted
@ -615,7 +627,7 @@ func (v StateResolution) calculateStateAfterManyEvents(
// Returns a list that combines the entries without conflicts with the result of state resolution for the entries with conflicts.
// The returned list is sorted by state key tuple.
// Returns an error if there was a problem talking to the database.
func (v StateResolution) resolveConflicts(
func (v StateResolution) resolveConflictsV1(
ctx context.Context,
notConflicted, conflicted []types.StateEntry,
) ([]types.StateEntry, error) {
@ -655,18 +667,124 @@ func (v StateResolution) resolveConflicts(
}
// Resolve the conflicts.
var resolvedEvents []gomatrixserverlib.Event
switch v.version {
case StateResolutionAlgorithmV1:
fmt.Println("using room version 1")
resolvedEvents = gomatrixserverlib.ResolveStateConflicts(conflictedEvents, authEvents)
case StateResolutionAlgorithmV2:
fmt.Println("using room version 2")
resolvedEvents = gomatrixserverlib.ResolveStateConflictsV2(conflictedEvents, nil, authEvents)
default:
return nil, errors.New("unsupported room version")
resolvedEvents := gomatrixserverlib.ResolveStateConflicts(conflictedEvents, authEvents)
// Map from the full events back to numeric state entries.
for _, resolvedEvent := range resolvedEvents {
entry, ok := eventIDMap[resolvedEvent.EventID()]
if !ok {
panic(fmt.Errorf("Missing state entry for event ID %q", resolvedEvent.EventID()))
}
notConflicted = append(notConflicted, entry)
}
// Sort the result so it can be searched.
sort.Sort(shared.StateEntrySorter(notConflicted))
return notConflicted, nil
}
// resolveConflicts resolves a list of conflicted state entries. It takes two lists.
// The first is a list of all state entries that are not conflicted.
// The second is a list of all state entries that are conflicted
// A state entry is conflicted when there is more than one numeric event ID for the same state key tuple.
// Returns a list that combines the entries without conflicts with the result of state resolution for the entries with conflicts.
// The returned list is sorted by state key tuple.
// Returns an error if there was a problem talking to the database.
func (v StateResolution) resolveConflictsV2(
ctx context.Context,
notConflicted, conflicted []types.StateEntry,
) ([]types.StateEntry, error) {
// Load the non-conflicted events
nonConflictedEvents, _, err := v.loadStateEvents(ctx, notConflicted)
if err != nil {
return nil, err
}
// Load the conflicted events
conflictedEvents, eventIDMap, err := v.loadStateEvents(ctx, conflicted)
if err != nil {
return nil, err
}
// For each conflicted event, we will add a new set of auth events. Auth
// events may be duplicated across these sets but that's OK.
authSets := make(map[string][]gomatrixserverlib.Event)
var authEvents []gomatrixserverlib.Event
var authDifference []gomatrixserverlib.Event
// For each conflicted event, let's try and get the needed auth events.
for _, conflictedEvent := range conflictedEvents {
// Work out which auth events we need to load.
key := conflictedEvent.EventID()
needed := gomatrixserverlib.StateNeededForAuth([]gomatrixserverlib.Event{conflictedEvent})
// Find the numeric IDs for the necessary state keys.
var neededStateKeys []string
neededStateKeys = append(neededStateKeys, needed.Member...)
neededStateKeys = append(neededStateKeys, needed.ThirdPartyInvite...)
stateKeyNIDMap, err := v.db.EventStateKeyNIDs(ctx, neededStateKeys)
if err != nil {
return nil, err
}
// Load the necessary auth events.
tuplesNeeded := v.stateKeyTuplesNeeded(stateKeyNIDMap, needed)
var authEntries []types.StateEntry
for _, tuple := range tuplesNeeded {
if eventNID, ok := shared.StateEntryMap(notConflicted).Lookup(tuple); ok {
authEntries = append(authEntries, types.StateEntry{
StateKeyTuple: tuple,
EventNID: eventNID,
})
}
}
// Store the newly found auth events in the auth set for this event.
authSets[key], _, err = v.loadStateEvents(ctx, authEntries)
if err != nil {
return nil, err
}
authEvents = append(authEvents, authSets[key]...)
}
// This function helps us to work out whether an event exists in one of the
// auth sets.
isInAuthList := func(k string, event gomatrixserverlib.Event) bool {
for _, e := range authSets[k] {
if e.EventID() == event.EventID() {
return true
}
}
return false
}
// This function works out if an event exists in all of the auth sets.
isInAllAuthLists := func(event gomatrixserverlib.Event) bool {
found := true
for k := range authSets {
found = found && isInAuthList(k, event)
}
return found
}
// Look through all of the auth events that we've been given and work out if
// there are any events which don't appear in all of the auth sets. If they
// don't then we add them to the auth difference.
for _, event := range authEvents {
if !isInAllAuthLists(event) {
authDifference = append(authDifference, event)
}
}
// Resolve the conflicts.
resolvedEvents := gomatrixserverlib.ResolveStateConflictsV2(
conflictedEvents,
nonConflictedEvents,
authEvents,
authDifference,
)
// Map from the full events back to numeric state entries.
for _, resolvedEvent := range resolvedEvents {
entry, ok := eventIDMap[resolvedEvent.EventID()]