aboutsummaryrefslogtreecommitdiffstats
path: root/whisper
diff options
context:
space:
mode:
authorJeffrey Wilcke <geffobscura@gmail.com>2015-11-21 02:23:55 +0800
committerJeffrey Wilcke <geffobscura@gmail.com>2015-11-25 19:10:47 +0800
commit5f0a4416db4339176e31fab5f4b7b79f4e7cf20b (patch)
tree828d36e96530feb48f310a0acd07cef372f0dc27 /whisper
parent4c2933ad825aa11ce118abddfe6eeafc0422b2b6 (diff)
downloaddexon-5f0a4416db4339176e31fab5f4b7b79f4e7cf20b.tar.gz
dexon-5f0a4416db4339176e31fab5f4b7b79f4e7cf20b.tar.zst
dexon-5f0a4416db4339176e31fab5f4b7b79f4e7cf20b.zip
whisper: fixed broadcast race
Whisper's expire and broadcast loops happen in two separate go routines. Whenever an envelope is being expired it's removed from the set of envelopes and it looses all information about the envelope, including the "known hash". After the envelope has been removed it can be re-accepted by a broadcasting peer putting back the envelope in the set of envelopes. Since the envelope broadcast loop is separate of the expire loop expired messages may be broadcast to other peer, resulting in messages **never** being dropped. This PR includes an expire check before adding new messages to the set of envelopes.
Diffstat (limited to 'whisper')
-rw-r--r--whisper/peer_test.go7
-rw-r--r--whisper/whisper.go5
-rw-r--r--whisper/whisper_test.go9
3 files changed, 19 insertions, 2 deletions
diff --git a/whisper/peer_test.go b/whisper/peer_test.go
index 594671ee1..b3d2031c1 100644
--- a/whisper/peer_test.go
+++ b/whisper/peer_test.go
@@ -239,14 +239,17 @@ func TestPeerMessageExpiration(t *testing.T) {
}
payload := []interface{}{envelope}
if err := p2p.ExpectMsg(tester.stream, messagesCode, payload); err != nil {
- t.Fatalf("message mismatch: %v", err)
+ // A premature empty message may have been broadcast, check the next too
+ if err := p2p.ExpectMsg(tester.stream, messagesCode, payload); err != nil {
+ t.Fatalf("message mismatch: %v", err)
+ }
}
// Check that the message is inside the cache
if !peer.known.Has(envelope.Hash()) {
t.Fatalf("message not found in cache")
}
// Discard messages until expiration and check cache again
- exp := time.Now().Add(time.Second + expirationCycle)
+ exp := time.Now().Add(time.Second + 2*expirationCycle + 100*time.Millisecond)
for time.Now().Before(exp) {
if err := p2p.ExpectMsg(tester.stream, messagesCode, []interface{}{}); err != nil {
t.Fatalf("message mismatch: %v", err)
diff --git a/whisper/whisper.go b/whisper/whisper.go
index 676d8ae7a..a341f23e4 100644
--- a/whisper/whisper.go
+++ b/whisper/whisper.go
@@ -234,6 +234,11 @@ func (self *Whisper) add(envelope *Envelope) error {
self.poolMu.Lock()
defer self.poolMu.Unlock()
+ // short circuit when a received envelope has already expired
+ if envelope.Expiry <= uint32(time.Now().Unix()) {
+ return nil
+ }
+
// Insert the message into the tracked pool
hash := envelope.Hash()
if _, ok := self.messages[hash]; ok {
diff --git a/whisper/whisper_test.go b/whisper/whisper_test.go
index 1a9a8667a..b83ce0fe7 100644
--- a/whisper/whisper_test.go
+++ b/whisper/whisper_test.go
@@ -207,4 +207,13 @@ func TestMessageExpiration(t *testing.T) {
if found {
t.Fatalf("message not expired from cache")
}
+
+ node.add(envelope)
+ node.poolMu.RLock()
+ _, found = node.messages[envelope.Hash()]
+ node.poolMu.RUnlock()
+ if found {
+ t.Fatalf("message was added to cache")
+ }
+
}