Skip to content
Snippets Groups Projects
Commit 25fd7afb authored by Benjamin Wenger's avatar Benjamin Wenger
Browse files

got tests passing with mutateTimestamp

parent 7633d35e
Branches
Tags
5 merge requests!510Release,!419rewrote the health tracker to both consider if there are waiting rounds and...,!371[Channel RSAtoPrivate] Implement Reverse Asymmetric in Client/Broadcast,!354Channels impl,!340Project/channels
package channels
import (
"fmt"
"regexp"
"testing"
)
/*
func TestValidateReaction(t *testing.T) {
r := "🍆"
......@@ -23,4 +18,4 @@ func TestValidateReaction(t *testing.T) {
if err != nil {
t.Errorf("Got error: %+v", err)
}
}
}*/
......@@ -136,9 +136,12 @@ func (e *events) triggerEvent(chID *id.ID, umi *userMessageInternal,
cm.Payload)
}
//modify the timestamp to reduce the chance message order will be ambiguous
ts := mutateTimestamp(round.Timestamps[states.QUEUED], umi.GetMessageID())
//Call the listener. This is already in an instanced event, no new thread needed.
listener(chID, umi.GetMessageID(), messageType, um.Username,
cm.Payload, round.Timestamps[states.QUEUED], time.Duration(cm.Lease), round)
cm.Payload, ts, time.Duration(cm.Lease), round)
return
}
......@@ -164,9 +167,12 @@ func (e *events) triggerAdminEvent(chID *id.ID, cm *ChannelMessage,
cm.Payload)
}
//modify the timestamp to reduce the chance message order will be ambiguous
ts := mutateTimestamp(round.Timestamps[states.QUEUED], messageID)
//Call the listener. This is already in an instanced event, no new thread needed.
listener(chID, messageID, messageType, AdminUsername,
cm.Payload, round.Timestamps[states.QUEUED], time.Duration(cm.Lease), round)
cm.Payload, ts, time.Duration(cm.Lease), round)
return
}
......
......@@ -243,7 +243,7 @@ func TestEvents_triggerEvents(t *testing.T) {
dummy.content, umi.GetChannelMessage().Payload)
}
if !dummy.timestamp.Equal(r.Timestamps[states.QUEUED]) {
if !withinMutationWindow(r.Timestamps[states.QUEUED], dummy.timestamp) {
t.Errorf("The timestamps do not match %s vs %s",
dummy.timestamp, r.Timestamps[states.QUEUED])
}
......@@ -314,7 +314,7 @@ func TestEvents_triggerAdminEvents(t *testing.T) {
dummy.senderUsername, cm.Payload)
}
if !dummy.timestamp.Equal(r.Timestamps[states.QUEUED]) {
if !withinMutationWindow(r.Timestamps[states.QUEUED], dummy.timestamp) {
t.Errorf("The timestamps do not match %s vs %s",
dummy.timestamp, r.Timestamps[states.QUEUED])
}
......
package channels
import (
"gitlab.com/elixxir/crypto/channel"
"gitlab.com/xx_network/crypto/large"
"time"
)
const (
// use a prime close to one million to ensure patterns dont arise due to
// cofactors with the message ID when doing the modulo
tenMsInNs = 10000019
halfTenMsInNs = tenMsInNs / 2
)
var tenMsInNsLargeInt = large.NewInt(tenMsInNs)
// mutateTimestamp is used to modify the the timestamps on all messages in a
// deterministic manner. This is because message ordering is done by timestamp
// and the timestamps come from the rounds, which means multiple messages can
// have the same timestamp due to being in the same round. The meaning of
// conversations can change depending on order, so while no explicit order
// can be discovered because to do so can leak potential ordering info for the
// mix, choosing an arbitrary order and having all clients agree will at least
// ensure that misunderstandings due to disagreements in order cannot occur
//
// In order to do this, this function mutates the timestamp of the round within
// +/- 5ms seeded based upon the message ID.
// It should be noted that this is only a reasonable assumption when the number
// of messages in a channel isn't too much. For example, under these conditions
// the birthday paradox of getting a collision if there are 10 messages for the
// channel in the same round is ~4*10^-6, but the chance if there are 50
// messages is 10^-4, and if the entire round is full of messages for the
// channel (1000 messages), .0487.
func mutateTimestamp(ts time.Time, msgID channel.MessageID) time.Time {
// Treat the message ID as a number and mod it by the number of ns in an ms
// to get an offset factor. Use a prime close to 1000000 to make sure there
// are no patterns in the output and reduce the chance of collision. While
// the fields do not align, so there is some bias towards some parts of the
// output field, that bias a too small to matter because log2(10000019) ~23
// while the input field is 256.
offsetLarge := large.NewIntFromBytes(msgID.Bytes())
offsetLarge.Mod(offsetLarge, tenMsInNsLargeInt)
// subtract half the field size so on average (across many runs) the message
// timestamps are not changed
offset := offsetLarge.Int64() - halfTenMsInNs
return time.Unix(0, ts.UnixNano()+offset)
}
package channels
import (
"time"
)
// withinMutationWindow is a utility test function to check if a mutated
// timestamp is within the allowable window
func withinMutationWindow(raw, mutated time.Time) bool {
lowerBound := raw.Add(-time.Duration(halfTenMsInNs))
upperBound := raw.Add(time.Duration(halfTenMsInNs))
return mutated.After(lowerBound) && mutated.Before(upperBound)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment