Skip to content

fix: do not sort received messages below the last seen one#8031

Open
link2xt wants to merge 8 commits intomainfrom
link2xt/no-sort-below-last-seen
Open

fix: do not sort received messages below the last seen one#8031
link2xt wants to merge 8 commits intomainfrom
link2xt/no-sort-below-last-seen

Conversation

@link2xt
Copy link
Copy Markdown
Collaborator

@link2xt link2xt commented Mar 25, 2026

Fixes #8030

  • test: remove test_old_message_5: see commit message, the test seems to check for the incorrect behavior

  • test: do not rely on loading newest chat in load_imf_email(): change helper function to avoid loading the wrong message if there is already a message with a newer timestamp

  • test: use load_imf_email() more: some test refactoring, since we have load_imf_email, can as well use it instead of copypasting

  • fix: always sort "Messages are end-to-end encrypted" notice to the beginning: see commit message, this ensures nothing can be added above this message for new chats (existing chats have non-zero timestamp so you can technically backdate something before "Messages are end-to-end encrypted", but this is not really a problem)

  • fix: never sort the message before chat joining timestamp: avoid adding "Member added" message before securejoin system messages

  • fix: do not sort received messages below the last seen one: the last change, see the code and comments in the code. I have reviewed "golden tests" breakage, this is where commits above come from, the rest of the breakage looks expected. I also left one comment myself on one of the tests.

  • There is a problem with "Messages are end-to-end encrypted." message. It has current timestamp, but incoming message from contact requests is from the past, so contact request chats start with the incoming message followed by "Messages are end-to-end encrypted.". Need to set the timestamp for the info message to the timestamp of incoming message or fix it the other way. (tests::verified_chats::test_outgoing_encrypted_msg)

  • Another problem is with "Member added" message in sync::tests::test_unpromoted_group_qr_sync, it did not end up at the end:

    ========== Chats of fiona: ==========
    Group#Chat#6002: the chat [2 member(s)]
    --------------------------------------------------------------------------------
    Msg#6003: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO]
    Msg#6004: info (Contact#Contact#Info): alice@example.org invited you to join this group.

    Waiting for the device of alice@example.org to reply… [NOTICED][INFO]
    Msg#6008🔒:  (Contact#Contact#6001): Member Me added by alice@example.org. [FRESH][INFO]
    Msg#6006: info (Contact#Contact#Info): alice@example.org replied, waiting for being added to the group… [NOTICED][INFO]
    --------------------------------------------------------------------------------

@link2xt link2xt force-pushed the link2xt/no-sort-below-last-seen branch from 61fde0e to eb93663 Compare March 25, 2026 05:10
@link2xt link2xt force-pushed the link2xt/no-sort-below-last-seen branch 9 times, most recently from d3e5b60 to 58aafef Compare March 28, 2026 10:25
OutBroadcast#Chat#1001: Channel [0 member(s)]
--------------------------------------------------------------------------------
Msg#1001: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO]
Msg#1006🔒: Me (Contact#Contact#Self): Member bob@example.net added. [INFO] √
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is some reordering of Alice's own messages in chat::chat_tests::test_sync_broadcast_and_send_message which results in one device showing as if Alice has sent a message to own channel before adding Bob while in fact it was after Alice added Bob. This seems to work as expected, if Alice backdates some message in the channel then it is not possible for the second device to know that it was not actually sent before Bob was added.

Essentially the problem boils down to "smeared timestamps" that cause these problems to golden tests that are not real problems. In practice devices may simply have slightly desynchronized clocks. Maybe we should not add too many golden tests as they are much easier to write than tell whether the breakage is important or not when they break.

@link2xt link2xt marked this pull request as ready for review March 28, 2026 10:32
@link2xt link2xt requested a review from Hocuri March 28, 2026 10:39
@link2xt
Copy link
Copy Markdown
Collaborator Author

link2xt commented Mar 28, 2026

Two things still needed:

  • Adding a test for the issue Message reordering with multi-relay #8030, something demonstrating the problem.
  • If we think that backdating the message too far in the past is bad, can add logic to sort the message to the end if it appears to be from more than a week ago. But it will again break some golden tests in places where dates are hardcoded in test messages, they are definitely more than a week old. I am not sure it is an issue if we mark the message as unread and scroll to it (desktop already does this). Someone maliciously backdating their message is not something to protect against IMO, there are worse things to happen if you are chatting with adversaries.

link2xt added 4 commits March 28, 2026 15:52
It is not clear now what this is testing.
Golden test shows messages ordered
incorrectly according to the timestamps,
they should be ordered the other way round.

Comment talks about fetching from mvbox and inbox
in paralell which is a rare case that
could have happened if one message is left in the inbox
and the other message is a chat message moved to mvbox.
We never download anything that is not moved to the target folder.

The test also resides in "verified chats" tests
which are all legacy tests we kept after
replacing the concept of verified/protected chats
with key contacts in 2.x.
We know which message was added from the return value
of receive_imf(). It may be that the first chat
in the chatlist is not the one where the message was received
if there is a pinned chat or if
just received message is old.
…ginning

We set timestamp of this info message to 0
to make it always appear in the beginning of the chat.
To avoid new chats being sorted to the end of the chatlist,
we ignore such 0 and use chat creation timestamp
when sorting the chatlist.
@link2xt link2xt force-pushed the link2xt/no-sort-below-last-seen branch from f5f626f to f2f532f Compare March 28, 2026 14:52
Hocuri and others added 4 commits March 28, 2026 19:38
This is to avoid sorting incoming messages that
are slightly in the past above system messages
about SecureJoin. SecureJoin messages are
timed according to smeared timestamp,
so even in the local tests they are in the future
by a few seconds.
@link2xt link2xt force-pushed the link2xt/no-sort-below-last-seen branch from 95a347e to 3671857 Compare March 28, 2026 18:39
Copy link
Copy Markdown
Collaborator

@iequidoo iequidoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do other messengers, when a chat is open, insert new delayed messages not at the bottom, but somewhere, maybe even outside the screen?

Have you considered an approach that changes the current behavior less (particularly, for a chat being open): when an MDN for an InFresh message is received, recalculate its sort timestamp as if received was false?

received: bool,
incoming: bool,
) -> Result<i64> {
let mut sort_timestamp = cmp::min(message_timestamp, smeared_time(context));
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So messages may still be ordered differently on devices if some chat members have clocks in the future and devices e.g. come online at different time.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this prevents the message from someone with such clock set into the future from sticking at the end of the chat, even after outgoing messages.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this ceiling is good, i just want to say that receiver-side reordering (and different order on user's devices) still may happen if sender's clock is in the future.

Also, sender- or server-side reordering could happen even before multi-relay, e.g. for messages sent while being offline or using a bad network, but this has never been considered as a problem, instead, messages inserted at the bottom always was a "feature".

We could guarantee the same message order on devices, but then we need to know the minimum "received" smeared time on devices...

Copy link
Copy Markdown
Collaborator

@Hocuri Hocuri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing! Let's hope that this improves things 🤞

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Message reordering with multi-relay

3 participants