Skip to content
Snippets Groups Projects
Commit 12f3c10e authored by benjamin's avatar benjamin
Browse files

adjusted timestamp handling - they are added to messages and will be used if...

adjusted timestamp handling - they are added to messages and will be used if they are within -5/+2 seconds of the round they are carried in, otherwise the old mutateTimestamp system is used
parent 73696112
No related branches found
No related tags found
3 merge requests!510Release,!419rewrote the health tracker to both consider if there are waiting rounds and...,!340Project/channels
...@@ -15,6 +15,7 @@ import ( ...@@ -15,6 +15,7 @@ import (
"gitlab.com/elixxir/crypto/channel" "gitlab.com/elixxir/crypto/channel"
"gitlab.com/elixxir/primitives/states" "gitlab.com/elixxir/primitives/states"
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
"time"
) )
// adminListener adheres to the [broadcast.ListenerFunc] interface and is used // adminListener adheres to the [broadcast.ListenerFunc] interface and is used
...@@ -54,8 +55,10 @@ func (al *adminListener) Listen(payload []byte, ...@@ -54,8 +55,10 @@ func (al *adminListener) Listen(payload []byte,
return return
} }
// Modify the timestamp to reduce the chance message order will be ambiguous // Replace the timestamp on the message if it is outside of the
ts := mutateTimestamp(round.Timestamps[states.QUEUED], msgID) // allowable range
ts := vetTimestamp(time.Unix(0, cm.LocalTimestamp),
round.Timestamps[states.QUEUED], msgID)
// Submit the message to the event model for listening // Submit the message to the event model for listening
if uuid, err := al.trigger(al.chID, cm, ts, msgID, receptionID, if uuid, err := al.trigger(al.chID, cm, ts, msgID, receptionID,
......
...@@ -18,10 +18,28 @@ const ( ...@@ -18,10 +18,28 @@ const (
// arise due to cofactors with the message ID when doing the modulo // arise due to cofactors with the message ID when doing the modulo
tenMsInNs = 10000019 tenMsInNs = 10000019
halfTenMsInNs = tenMsInNs / 2 halfTenMsInNs = tenMsInNs / 2
beforeGrace = 5 * time.Second
afterGrace = 2 * time.Second
) )
var tenMsInNsLargeInt = large.NewInt(tenMsInNs) var tenMsInNsLargeInt = large.NewInt(tenMsInNs)
// vetTimestamp determines which timestamp to use for a message. It will
// use the local timestamp provided in the message as long as it is within 5
// seconds before the round and 2 second after the round. Otherwise, it will
// use the round timestamp via mutateTimestamp
func vetTimestamp(localTS, ts time.Time, msgID channel.MessageID) time.Time {
before := ts.Add(-beforeGrace)
after := ts.Add(afterGrace)
if localTS.Before(before) || localTS.After(after) {
return mutateTimestamp(ts, msgID)
}
return localTS
}
// mutateTimestamp is used to modify the the timestamps on all messages in a // mutateTimestamp is used to modify the the timestamps on all messages in a
// deterministic manner. This is because message ordering is done by timestamp // deterministic manner. This is because message ordering is done by timestamp
// and the timestamps come from the rounds, which means multiple messages can // and the timestamps come from the rounds, which means multiple messages can
......
...@@ -53,3 +53,77 @@ func TestMutateTimestampDeltaAverage(t *testing.T) { ...@@ -53,3 +53,77 @@ func TestMutateTimestampDeltaAverage(t *testing.T) {
t.Fatal() t.Fatal()
} }
} }
const generationRange = beforeGrace + afterGrace
// TestVetTimestamp_Happy tests that when the localTS is within
// the allowed range, it is unmodified
func TestVetTimestamp_Happy(t *testing.T) {
samples := 10000
rng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
for i := 0; i < samples; i++ {
now := time.Now()
tested := now.Add(-beforeGrace).Add(time.Duration(rng.Int63()) % generationRange)
var msgID channel.MessageID
rng.Read(msgID[:])
result := vetTimestamp(tested, now, msgID)
if !tested.Equal(result) {
t.Errorf("Timestamp was molested unexpectedly")
}
}
}
// TestVetTimestamp_Happy tests that when the localTS is less than
// the allowed time period it is replaced
func TestVetTimestamp_BeforePeriod(t *testing.T) {
samples := 10000
rng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
for i := 0; i < samples; i++ {
now := time.Now()
tested := now.Add(-beforeGrace).Add(-time.Duration(rng.Int63()) % (100000 * time.Hour))
var msgID channel.MessageID
rng.Read(msgID[:])
result := vetTimestamp(tested, now, msgID)
if tested.Equal(result) {
t.Errorf("Timestamp was unmolested unexpectedly")
}
}
}
// TestVetTimestamp_Happy tests that when the localTS is greater than
// the allowed time period it is replaced
func TestVetTimestamp_AfterPeriod(t *testing.T) {
samples := 10000
rng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
for i := 0; i < samples; i++ {
now := time.Now()
tested := now.Add(afterGrace).Add(-time.Duration(rng.Int63()) % (100000 * time.Hour))
var msgID channel.MessageID
rng.Read(msgID[:])
result := vetTimestamp(tested, now, msgID)
if tested.Equal(result) {
t.Errorf("Timestamp was unmolested unexpectedly")
}
}
}
...@@ -17,6 +17,7 @@ import ( ...@@ -17,6 +17,7 @@ import (
"gitlab.com/elixxir/crypto/rsa" "gitlab.com/elixxir/crypto/rsa"
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
"gitlab.com/xx_network/primitives/id/ephemeral" "gitlab.com/xx_network/primitives/id/ephemeral"
"gitlab.com/xx_network/primitives/netTime"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"time" "time"
) )
...@@ -50,11 +51,12 @@ func (m *manager) SendGeneric(channelID *id.ID, messageType MessageType, ...@@ -50,11 +51,12 @@ func (m *manager) SendGeneric(channelID *id.ID, messageType MessageType,
var msgId cryptoChannel.MessageID var msgId cryptoChannel.MessageID
chMsg := &ChannelMessage{ chMsg := &ChannelMessage{
Lease: validUntil.Nanoseconds(), Lease: validUntil.Nanoseconds(),
PayloadType: uint32(messageType), PayloadType: uint32(messageType),
Payload: msg, Payload: msg,
Nickname: nickname, Nickname: nickname,
Nonce: make([]byte, messageNonceSize), Nonce: make([]byte, messageNonceSize),
LocalTimestamp: netTime.Now().UnixNano(),
} }
// Generate random nonce to be used for message ID generation. This makes it // Generate random nonce to be used for message ID generation. This makes it
...@@ -75,7 +77,7 @@ func (m *manager) SendGeneric(channelID *id.ID, messageType MessageType, ...@@ -75,7 +77,7 @@ func (m *manager) SendGeneric(channelID *id.ID, messageType MessageType,
ECCPublicKey: m.me.PubKey, ECCPublicKey: m.me.PubKey,
} }
//Note: we are not checking check if message is too long before trying to //Note: we are not checking if message is too long before trying to
//find a round //find a round
//Build the function pointer that will build the message //Build the function pointer that will build the message
...@@ -145,11 +147,12 @@ func (m *manager) SendAdminGeneric(privKey rsa.PrivateKey, channelID *id.ID, ...@@ -145,11 +147,12 @@ func (m *manager) SendAdminGeneric(privKey rsa.PrivateKey, channelID *id.ID,
var msgId cryptoChannel.MessageID var msgId cryptoChannel.MessageID
chMsg := &ChannelMessage{ chMsg := &ChannelMessage{
Lease: validUntil.Nanoseconds(), Lease: validUntil.Nanoseconds(),
PayloadType: uint32(messageType), PayloadType: uint32(messageType),
Payload: msg, Payload: msg,
Nickname: AdminUsername, Nickname: AdminUsername,
Nonce: make([]byte, messageNonceSize), Nonce: make([]byte, messageNonceSize),
LocalTimestamp: netTime.Now().UnixNano(),
} }
// Generate random nonce to be used for message ID generation. This makes it // Generate random nonce to be used for message ID generation. This makes it
......
...@@ -14,6 +14,7 @@ import ( ...@@ -14,6 +14,7 @@ import (
"gitlab.com/elixxir/client/cmix/rounds" "gitlab.com/elixxir/client/cmix/rounds"
"gitlab.com/elixxir/primitives/states" "gitlab.com/elixxir/primitives/states"
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
"time"
) )
// the userListener adheres to the [broadcast.ListenerFunc] interface and is // the userListener adheres to the [broadcast.ListenerFunc] interface and is
...@@ -64,8 +65,9 @@ func (ul *userListener) Listen(payload []byte, ...@@ -64,8 +65,9 @@ func (ul *userListener) Listen(payload []byte,
return return
} }
// Modify the timestamp to reduce the chance message order will be ambiguous // Replace the timestamp on the message if it is outside of the
ts := mutateTimestamp(round.Timestamps[states.QUEUED], msgID) // allowable range
ts := vetTimestamp(time.Unix(0, cm.LocalTimestamp), round.Timestamps[states.QUEUED], msgID)
//TODO: Processing of the message relative to admin commands will be here //TODO: Processing of the message relative to admin commands will be here
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment