From 76ff47c0522e03eabd72140bf62e1d0d1d1029e0 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 5 Jun 2020 11:48:52 +0100 Subject: [PATCH] Use AuthChainProvider to try and speed up federated joins (#1100) * Use MissingAuthEventHandler on performjoin to try and speed up cases where we have missing events * Update gomatrixserverlib * Use supplied room version * Use AuthChainProvider * Tweaks * Update gomatrixserverlib * Signature checks --- federationapi/routing/send.go | 2 +- federationsender/internal/perform/join.go | 92 ++++++++++++++++------- go.mod | 2 +- go.sum | 4 +- 4 files changed, 67 insertions(+), 33 deletions(-) diff --git a/federationapi/routing/send.go b/federationapi/routing/send.go index 74b4c0144..a2120d81b 100644 --- a/federationapi/routing/send.go +++ b/federationapi/routing/send.go @@ -675,7 +675,7 @@ func (t *txnReq) lookupMissingStateViaState(roomID, eventID string, roomVersion return nil, err } // Check that the returned state is valid. - if err := state.Check(t.context, t.keys); err != nil { + if err := state.Check(t.context, t.keys, nil); err != nil { return nil, err } return &state, nil diff --git a/federationsender/internal/perform/join.go b/federationsender/internal/perform/join.go index 3c7ef0765..9a505d15b 100644 --- a/federationsender/internal/perform/join.go +++ b/federationsender/internal/perform/join.go @@ -33,38 +33,72 @@ func (r joinContext) CheckSendJoinResponse( ) error { // A list of events that we have retried, if they were not included in // the auth events supplied in the send_join. - retries := map[string]bool{} + retries := map[string][]gomatrixserverlib.Event{} + + // Define a function which we can pass to Check to retrieve missing + // auth events inline. This greatly increases our chances of not having + // to repeat the entire set of checks just for a missing event or two. + missingAuth := func(roomVersion gomatrixserverlib.RoomVersion, eventIDs []string) ([]gomatrixserverlib.Event, error) { + returning := []gomatrixserverlib.Event{} + + // See if we have retry entries for each of the supplied event IDs. + for _, eventID := range eventIDs { + // If we've already satisfied a request for this event ID before then + // just append the results. We won't retry the request. + if retry, ok := retries[eventID]; ok { + if retry == nil { + return nil, fmt.Errorf("missingAuth: not retrying failed event ID %q", eventID) + } + returning = append(returning, retry...) + continue + } + + // Make a note of the fact that we tried to do something with this + // event ID, even if we don't succeed. + retries[event.EventID()] = nil + + // Try to retrieve the event from the server that sent us the send + // join response. + tx, txerr := r.federation.GetEvent(ctx, server, eventID) + if txerr != nil { + return nil, fmt.Errorf("missingAuth r.federation.GetEvent: %w", txerr) + } + + // For each event returned, add it to the set of return events. We + // also will populate the retries, in case someone asks for this + // event ID again. + for _, pdu := range tx.PDUs { + // Try to parse the event. + ev, everr := gomatrixserverlib.NewEventFromUntrustedJSON(pdu, roomVersion) + if everr != nil { + return nil, fmt.Errorf("missingAuth gomatrixserverlib.NewEventFromUntrustedJSON: %w", everr) + } + + // Check the signatures of the event. + if res, err := gomatrixserverlib.VerifyEventSignatures(ctx, []gomatrixserverlib.Event{ev}, r.keyRing); err != nil { + return nil, fmt.Errorf("missingAuth VerifyEventSignatures: %w", err) + } else { + for _, err := range res { + if err != nil { + return nil, fmt.Errorf("missingAuth VerifyEventSignatures: %w", err) + } + } + } + + // If the event is OK then add it to the results and the retry map. + returning = append(returning, ev) + retries[event.EventID()] = append(retries[event.EventID()], ev) + retries[ev.EventID()] = append(retries[ev.EventID()], ev) + } + } + + return returning, nil + } -retryCheck: // TODO: Can we expand Check here to return a list of missing auth // events rather than failing one at a time? - if err := respSendJoin.Check(ctx, r.keyRing, event); err != nil { - switch e := err.(type) { - case gomatrixserverlib.MissingAuthEventError: - // Check that we haven't already retried for this event, prevents - // us from ending up in endless loops - if !retries[e.AuthEventID] { - // Ask the server that we're talking to right now for the event - tx, txerr := r.federation.GetEvent(ctx, server, e.AuthEventID) - if txerr != nil { - return fmt.Errorf("r.federation.GetEvent: %w", txerr) - } - // For each event returned, add it to the auth events. - for _, pdu := range tx.PDUs { - ev, everr := gomatrixserverlib.NewEventFromUntrustedJSON(pdu, respMakeJoin.RoomVersion) - if everr != nil { - return fmt.Errorf("gomatrixserverlib.NewEventFromUntrustedJSON: %w", everr) - } - respSendJoin.AuthEvents = append(respSendJoin.AuthEvents, ev) - } - // Mark the event as retried and then give the check another go. - retries[e.AuthEventID] = true - goto retryCheck - } - return fmt.Errorf("respSendJoin (after retries): %w", e) - default: - return fmt.Errorf("respSendJoin: %w", err) - } + if err := respSendJoin.Check(ctx, r.keyRing, event, missingAuth); err != nil { + return fmt.Errorf("respSendJoin: %w", err) } return nil } diff --git a/go.mod b/go.mod index a875ef7c9..61d7358de 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/matrix-org/go-http-js-libp2p v0.0.0-20200518170932-783164aeeda4 github.com/matrix-org/go-sqlite3-js v0.0.0-20200522092705-bc8506ccbcf3 github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26 - github.com/matrix-org/gomatrixserverlib v0.0.0-20200604122934-a06b83e7f324 + github.com/matrix-org/gomatrixserverlib v0.0.0-20200605101319-57093b526cb1 github.com/matrix-org/naffka v0.0.0-20200422140631-181f1ee7401f github.com/matrix-org/util v0.0.0-20190711121626-527ce5ddefc7 github.com/mattn/go-sqlite3 v2.0.2+incompatible diff --git a/go.sum b/go.sum index 94101251b..fa3a65431 100644 --- a/go.sum +++ b/go.sum @@ -356,8 +356,8 @@ github.com/matrix-org/go-sqlite3-js v0.0.0-20200522092705-bc8506ccbcf3 h1:Yb+Wlf github.com/matrix-org/go-sqlite3-js v0.0.0-20200522092705-bc8506ccbcf3/go.mod h1:e+cg2q7C7yE5QnAXgzo512tgFh1RbQLC0+jozuegKgo= github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26 h1:Hr3zjRsq2bhrnp3Ky1qgx/fzCtCALOoGYylh2tpS9K4= github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26/go.mod h1:3fxX6gUjWyI/2Bt7J1OLhpCzOfO/bB3AiX0cJtEKud0= -github.com/matrix-org/gomatrixserverlib v0.0.0-20200604122934-a06b83e7f324 h1:TjHTrOkX+G99F1NitCwNOPa62beQMAQklBuEBkDP8Hc= -github.com/matrix-org/gomatrixserverlib v0.0.0-20200604122934-a06b83e7f324/go.mod h1:JsAzE1Ll3+gDWS9JSUHPJiiyAksvOOnGWF2nXdg4ZzU= +github.com/matrix-org/gomatrixserverlib v0.0.0-20200605101319-57093b526cb1 h1:T9nY1X24uHDkC3uMLwoo2W+JE2o0t3k/lYwqORfKSUg= +github.com/matrix-org/gomatrixserverlib v0.0.0-20200605101319-57093b526cb1/go.mod h1:JsAzE1Ll3+gDWS9JSUHPJiiyAksvOOnGWF2nXdg4ZzU= github.com/matrix-org/naffka v0.0.0-20200422140631-181f1ee7401f h1:pRz4VTiRCO4zPlEMc3ESdUOcW4PXHH4Kj+YDz1XyE+Y= github.com/matrix-org/naffka v0.0.0-20200422140631-181f1ee7401f/go.mod h1:y0oDTjZDv5SM9a2rp3bl+CU+bvTRINQsdb7YlDql5Go= github.com/matrix-org/util v0.0.0-20190711121626-527ce5ddefc7 h1:ntrLa/8xVzeSs8vHFHK25k0C+NV74sYMJnNSg5NoSRo=