Skip to content
This repository was archived by the owner on Sep 6, 2022. It is now read-only.

Commit ef6e277

Browse files
fix: make timestamps strictly increasing (#201)
* fix: make timestamps strictly increasing On Linux, this is almost always the case. Windows, however, doesn't have nanosecond accuracy. We make the timestamp sequence numbers strictly increasing by returning the last timestamp + 1 where necessary. * apply code review Co-authored-by: Marten Seemann <[email protected]> * use a lock Co-authored-by: Marten Seemann <[email protected]>
1 parent e5b6740 commit ef6e277

File tree

2 files changed

+29
-1
lines changed

2 files changed

+29
-1
lines changed

peer/record.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package peer
22

33
import (
44
"fmt"
5+
"sync"
56
"time"
67

78
pb "github.com/libp2p/go-libp2p-core/peer/pb"
@@ -125,9 +126,23 @@ func PeerRecordFromProtobuf(msg *pb.PeerRecord) (*PeerRecord, error) {
125126
return record, nil
126127
}
127128

129+
var (
130+
lastTimestampMu sync.Mutex
131+
lastTimestamp uint64
132+
)
133+
128134
// TimestampSeq is a helper to generate a timestamp-based sequence number for a PeerRecord.
129135
func TimestampSeq() uint64 {
130-
return uint64(time.Now().UnixNano())
136+
now := uint64(time.Now().UnixNano())
137+
lastTimestampMu.Lock()
138+
defer lastTimestampMu.Unlock()
139+
// Not all clocks are strictly increasing, but we need these sequence numbers to be strictly
140+
// increasing.
141+
if now <= lastTimestamp {
142+
now = lastTimestamp + 1
143+
}
144+
lastTimestamp = now
145+
return now
131146
}
132147

133148
// Domain is used when signing and validating PeerRecords contained in Envelopes.

peer/record_test.go

+13
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,16 @@ func TestSignedPeerRecordFromEnvelope(t *testing.T) {
5252
}
5353
})
5454
}
55+
56+
// This is pretty much guaranteed to pass on Linux no matter how we implement it, but Windows has
57+
// low clock precision. This makes sure we never get a duplicate.
58+
func TestTimestampSeq(t *testing.T) {
59+
var last uint64
60+
for i := 0; i < 1000; i++ {
61+
next := TimestampSeq()
62+
if next <= last {
63+
t.Errorf("non-increasing timestamp found: %d <= %d", next, last)
64+
}
65+
last = next
66+
}
67+
}

0 commit comments

Comments
 (0)