whisper: refactoring (#3411)
* whisper: refactored message processing * whisper: final polishing * whisper: logging updated * whisper: moved the check, changed the default PoW * whisper: refactoring of message queuing * whisper: refactored parameters
This commit is contained in:
		@@ -55,6 +55,22 @@ func APIs() []rpc.API {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Start starts the Whisper worker threads.
 | 
				
			||||||
 | 
					func (api *PublicWhisperAPI) Start() error {
 | 
				
			||||||
 | 
						if api.whisper == nil {
 | 
				
			||||||
 | 
							return whisperOffLineErr
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return api.whisper.Start(nil)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Stop stops the Whisper worker threads.
 | 
				
			||||||
 | 
					func (api *PublicWhisperAPI) Stop() error {
 | 
				
			||||||
 | 
						if api.whisper == nil {
 | 
				
			||||||
 | 
							return whisperOffLineErr
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return api.whisper.Stop()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Version returns the Whisper version this node offers.
 | 
					// Version returns the Whisper version this node offers.
 | 
				
			||||||
func (api *PublicWhisperAPI) Version() (*rpc.HexNumber, error) {
 | 
					func (api *PublicWhisperAPI) Version() (*rpc.HexNumber, error) {
 | 
				
			||||||
	if api.whisper == nil {
 | 
						if api.whisper == nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -277,6 +277,9 @@ func TestIntegrationAsym(t *testing.T) {
 | 
				
			|||||||
		t.Fatalf("failed to create API.")
 | 
							t.Fatalf("failed to create API.")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						api.Start()
 | 
				
			||||||
 | 
						defer api.Stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sig, err := api.NewIdentity()
 | 
						sig, err := api.NewIdentity()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatalf("failed NewIdentity: %s.", err)
 | 
							t.Fatalf("failed NewIdentity: %s.", err)
 | 
				
			||||||
@@ -375,6 +378,9 @@ func TestIntegrationSym(t *testing.T) {
 | 
				
			|||||||
		t.Fatalf("failed to create API.")
 | 
							t.Fatalf("failed to create API.")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						api.Start()
 | 
				
			||||||
 | 
						defer api.Stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	keyname := "schluessel"
 | 
						keyname := "schluessel"
 | 
				
			||||||
	err := api.GenerateSymKey(keyname)
 | 
						err := api.GenerateSymKey(keyname)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -471,6 +477,9 @@ func TestIntegrationSymWithFilter(t *testing.T) {
 | 
				
			|||||||
		t.Fatalf("failed to create API.")
 | 
							t.Fatalf("failed to create API.")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						api.Start()
 | 
				
			||||||
 | 
						defer api.Stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	keyname := "schluessel"
 | 
						keyname := "schluessel"
 | 
				
			||||||
	err := api.GenerateSymKey(keyname)
 | 
						err := api.GenerateSymKey(keyname)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,9 +15,7 @@
 | 
				
			|||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | 
					// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
Package whisper implements the Whisper PoC-1.
 | 
					Package whisper implements the Whisper protocol (version 5).
 | 
				
			||||||
 | 
					 | 
				
			||||||
(https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Whisper combines aspects of both DHTs and datagram messaging systems (e.g. UDP).
 | 
					Whisper combines aspects of both DHTs and datagram messaging systems (e.g. UDP).
 | 
				
			||||||
As such it may be likened and compared to both, not dissimilar to the
 | 
					As such it may be likened and compared to both, not dissimilar to the
 | 
				
			||||||
@@ -42,11 +40,11 @@ const (
 | 
				
			|||||||
	ProtocolVersionStr = "5.0"
 | 
						ProtocolVersionStr = "5.0"
 | 
				
			||||||
	ProtocolName       = "shh"
 | 
						ProtocolName       = "shh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	statusCode           = 0
 | 
						statusCode           = 0 // used by whisper protocol
 | 
				
			||||||
	messagesCode         = 1
 | 
						messagesCode         = 1 // normal whisper message
 | 
				
			||||||
	p2pCode              = 2
 | 
						p2pCode              = 2 // peer-to-peer message (to be consumed by the peer, but not forwarded any futher)
 | 
				
			||||||
	mailRequestCode      = 3
 | 
						p2pRequestCode       = 3 // peer-to-peer message, used by Dapp protocol
 | 
				
			||||||
	NumberOfMessageCodes = 32
 | 
						NumberOfMessageCodes = 64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	paddingMask   = byte(3)
 | 
						paddingMask   = byte(3)
 | 
				
			||||||
	signatureFlag = byte(4)
 | 
						signatureFlag = byte(4)
 | 
				
			||||||
@@ -57,11 +55,12 @@ const (
 | 
				
			|||||||
	saltLength        = 12
 | 
						saltLength        = 12
 | 
				
			||||||
	AESNonceMaxLength = 12
 | 
						AESNonceMaxLength = 12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	MaxMessageLength = 0xFFFF // todo: remove this restriction after testing in morden and analizing stats. this should be regulated by MinimumPoW.
 | 
						MaxMessageLength = 0xFFFF // todo: remove this restriction after testing. this should be regulated by PoW.
 | 
				
			||||||
	MinimumPoW       = 10.0   // todo: review
 | 
						MinimumPoW       = 1.0    // todo: review after testing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	padSizeLimitLower = 128 // it can not be less - we don't want to reveal the absence of signature
 | 
						padSizeLimitLower = 128 // it can not be less - we don't want to reveal the absence of signature
 | 
				
			||||||
	padSizeLimitUpper = 256 // just an arbitrary number, could be changed without losing compatibility
 | 
						padSizeLimitUpper = 256 // just an arbitrary number, could be changed without losing compatibility
 | 
				
			||||||
 | 
						messageQueueLimit = 1024
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	expirationCycle   = time.Second
 | 
						expirationCycle   = time.Second
 | 
				
			||||||
	transmissionCycle = 300 * time.Millisecond
 | 
						transmissionCycle = 300 * time.Millisecond
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,14 +14,14 @@
 | 
				
			|||||||
// You should have received a copy of the GNU Lesser General Public License
 | 
					// You should have received a copy of the GNU Lesser General Public License
 | 
				
			||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | 
					// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Contains the Whisper protocol Envelope element. For formal details please see
 | 
					// Contains the Whisper protocol Envelope element.
 | 
				
			||||||
// the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#envelopes.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
package whisperv5
 | 
					package whisperv5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"crypto/ecdsa"
 | 
						"crypto/ecdsa"
 | 
				
			||||||
	"encoding/binary"
 | 
						"encoding/binary"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"math"
 | 
						"math"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@@ -86,8 +86,8 @@ func (e *Envelope) Ver() uint64 {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Seal closes the envelope by spending the requested amount of time as a proof
 | 
					// Seal closes the envelope by spending the requested amount of time as a proof
 | 
				
			||||||
// of work on hashing the data.
 | 
					// of work on hashing the data.
 | 
				
			||||||
func (e *Envelope) Seal(options *MessageParams) {
 | 
					func (e *Envelope) Seal(options *MessageParams) error {
 | 
				
			||||||
	var target int
 | 
						var target, bestBit int
 | 
				
			||||||
	if options.PoW == 0 {
 | 
						if options.PoW == 0 {
 | 
				
			||||||
		// adjust for the duration of Seal() execution only if execution time is predefined unconditionally
 | 
							// adjust for the duration of Seal() execution only if execution time is predefined unconditionally
 | 
				
			||||||
		e.Expiry += options.WorkTime
 | 
							e.Expiry += options.WorkTime
 | 
				
			||||||
@@ -99,7 +99,7 @@ func (e *Envelope) Seal(options *MessageParams) {
 | 
				
			|||||||
	h := crypto.Keccak256(e.rlpWithoutNonce())
 | 
						h := crypto.Keccak256(e.rlpWithoutNonce())
 | 
				
			||||||
	copy(buf[:32], h)
 | 
						copy(buf[:32], h)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	finish, bestBit := time.Now().Add(time.Duration(options.WorkTime)*time.Second).UnixNano(), 0
 | 
						finish := time.Now().Add(time.Duration(options.WorkTime) * time.Second).UnixNano()
 | 
				
			||||||
	for nonce := uint64(0); time.Now().UnixNano() < finish; {
 | 
						for nonce := uint64(0); time.Now().UnixNano() < finish; {
 | 
				
			||||||
		for i := 0; i < 1024; i++ {
 | 
							for i := 0; i < 1024; i++ {
 | 
				
			||||||
			binary.BigEndian.PutUint64(buf[56:], nonce)
 | 
								binary.BigEndian.PutUint64(buf[56:], nonce)
 | 
				
			||||||
@@ -108,12 +108,18 @@ func (e *Envelope) Seal(options *MessageParams) {
 | 
				
			|||||||
			if firstBit > bestBit {
 | 
								if firstBit > bestBit {
 | 
				
			||||||
				e.EnvNonce, bestBit = nonce, firstBit
 | 
									e.EnvNonce, bestBit = nonce, firstBit
 | 
				
			||||||
				if target > 0 && bestBit >= target {
 | 
									if target > 0 && bestBit >= target {
 | 
				
			||||||
					return
 | 
										return nil
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			nonce++
 | 
								nonce++
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if target > 0 && bestBit < target {
 | 
				
			||||||
 | 
							return errors.New("Failed to reach the PoW target")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (e *Envelope) PoW() float64 {
 | 
					func (e *Envelope) PoW() float64 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,8 @@ import (
 | 
				
			|||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/ethereum/go-ethereum/common"
 | 
						"github.com/ethereum/go-ethereum/common"
 | 
				
			||||||
 | 
						"github.com/ethereum/go-ethereum/logger"
 | 
				
			||||||
 | 
						"github.com/ethereum/go-ethereum/logger/glog"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Filter struct {
 | 
					type Filter struct {
 | 
				
			||||||
@@ -75,11 +77,12 @@ func (fs *Filters) Get(i uint32) *Filter {
 | 
				
			|||||||
	return fs.watchers[i]
 | 
						return fs.watchers[i]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (fs *Filters) NotifyWatchers(env *Envelope, messageCode uint64) {
 | 
					func (fs *Filters) NotifyWatchers(env *Envelope, p2pMessage bool) {
 | 
				
			||||||
	fs.mutex.RLock()
 | 
						fs.mutex.RLock()
 | 
				
			||||||
	var msg *ReceivedMessage
 | 
						var msg *ReceivedMessage
 | 
				
			||||||
	for _, watcher := range fs.watchers {
 | 
						for j, watcher := range fs.watchers {
 | 
				
			||||||
		if messageCode == p2pCode && !watcher.AcceptP2P {
 | 
							if p2pMessage && !watcher.AcceptP2P {
 | 
				
			||||||
 | 
								glog.V(logger.Detail).Infof("msg [%x], filter [%d]: p2p messages are not allowed \n", env.Hash(), j)
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -90,6 +93,11 @@ func (fs *Filters) NotifyWatchers(env *Envelope, messageCode uint64) {
 | 
				
			|||||||
			match = watcher.MatchEnvelope(env)
 | 
								match = watcher.MatchEnvelope(env)
 | 
				
			||||||
			if match {
 | 
								if match {
 | 
				
			||||||
				msg = env.Open(watcher)
 | 
									msg = env.Open(watcher)
 | 
				
			||||||
 | 
									if msg == nil {
 | 
				
			||||||
 | 
										glog.V(logger.Detail).Infof("msg [%x], filter [%d]: failed to open \n", env.Hash(), j)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									glog.V(logger.Detail).Infof("msg [%x], filter [%d]: does not match \n", env.Hash(), j)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -137,12 +145,12 @@ func (f *Filter) MatchMessage(msg *ReceivedMessage) bool {
 | 
				
			|||||||
	if f.PoW > 0 && msg.PoW < f.PoW {
 | 
						if f.PoW > 0 && msg.PoW < f.PoW {
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if f.Src != nil && !isPubKeyEqual(msg.Src, f.Src) {
 | 
						if f.Src != nil && !IsPubKeyEqual(msg.Src, f.Src) {
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if f.expectsAsymmetricEncryption() && msg.isAsymmetricEncryption() {
 | 
						if f.expectsAsymmetricEncryption() && msg.isAsymmetricEncryption() {
 | 
				
			||||||
		return isPubKeyEqual(&f.KeyAsym.PublicKey, msg.Dst) && f.MatchTopic(msg.Topic)
 | 
							return IsPubKeyEqual(&f.KeyAsym.PublicKey, msg.Dst) && f.MatchTopic(msg.Topic)
 | 
				
			||||||
	} else if f.expectsSymmetricEncryption() && msg.isSymmetricEncryption() {
 | 
						} else if f.expectsSymmetricEncryption() && msg.isSymmetricEncryption() {
 | 
				
			||||||
		return f.SymKeyHash == msg.SymKeyHash && f.MatchTopic(msg.Topic)
 | 
							return f.SymKeyHash == msg.SymKeyHash && f.MatchTopic(msg.Topic)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -176,7 +184,7 @@ func (f *Filter) MatchTopic(topic TopicType) bool {
 | 
				
			|||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func isPubKeyEqual(a, b *ecdsa.PublicKey) bool {
 | 
					func IsPubKeyEqual(a, b *ecdsa.PublicKey) bool {
 | 
				
			||||||
	if !ValidatePublicKey(a) {
 | 
						if !ValidatePublicKey(a) {
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
	} else if !ValidatePublicKey(b) {
 | 
						} else if !ValidatePublicKey(b) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -139,7 +139,7 @@ func TestComparePubKey(t *testing.T) {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatalf("failed to generate second key with seed %d: %s.", seed, err)
 | 
							t.Fatalf("failed to generate second key with seed %d: %s.", seed, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if isPubKeyEqual(&key1.PublicKey, &key2.PublicKey) {
 | 
						if IsPubKeyEqual(&key1.PublicKey, &key2.PublicKey) {
 | 
				
			||||||
		t.Fatalf("public keys are equal, seed %d.", seed)
 | 
							t.Fatalf("public keys are equal, seed %d.", seed)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -149,7 +149,7 @@ func TestComparePubKey(t *testing.T) {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatalf("failed to generate third key with seed %d: %s.", seed, err)
 | 
							t.Fatalf("failed to generate third key with seed %d: %s.", seed, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if isPubKeyEqual(&key1.PublicKey, &key3.PublicKey) {
 | 
						if IsPubKeyEqual(&key1.PublicKey, &key3.PublicKey) {
 | 
				
			||||||
		t.Fatalf("key1 == key3, seed %d.", seed)
 | 
							t.Fatalf("key1 == key3, seed %d.", seed)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -540,7 +540,7 @@ func TestWatchers(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i = 0; i < NumMessages; i++ {
 | 
						for i = 0; i < NumMessages; i++ {
 | 
				
			||||||
		filters.NotifyWatchers(envelopes[i], messagesCode)
 | 
							filters.NotifyWatchers(envelopes[i], false)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var total int
 | 
						var total int
 | 
				
			||||||
@@ -593,7 +593,7 @@ func TestWatchers(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i = 0; i < NumMessages; i++ {
 | 
						for i = 0; i < NumMessages; i++ {
 | 
				
			||||||
		filters.NotifyWatchers(envelopes[i], messagesCode)
 | 
							filters.NotifyWatchers(envelopes[i], false)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i = 0; i < NumFilters; i++ {
 | 
						for i = 0; i < NumFilters; i++ {
 | 
				
			||||||
@@ -629,7 +629,7 @@ func TestWatchers(t *testing.T) {
 | 
				
			|||||||
	// test AcceptP2P
 | 
						// test AcceptP2P
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	total = 0
 | 
						total = 0
 | 
				
			||||||
	filters.NotifyWatchers(envelopes[0], p2pCode)
 | 
						filters.NotifyWatchers(envelopes[0], true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i = 0; i < NumFilters; i++ {
 | 
						for i = 0; i < NumFilters; i++ {
 | 
				
			||||||
		mail = tst[i].f.Retrieve()
 | 
							mail = tst[i].f.Retrieve()
 | 
				
			||||||
@@ -646,7 +646,7 @@ func TestWatchers(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	f.AcceptP2P = true
 | 
						f.AcceptP2P = true
 | 
				
			||||||
	total = 0
 | 
						total = 0
 | 
				
			||||||
	filters.NotifyWatchers(envelopes[0], p2pCode)
 | 
						filters.NotifyWatchers(envelopes[0], true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i = 0; i < NumFilters; i++ {
 | 
						for i = 0; i < NumFilters; i++ {
 | 
				
			||||||
		mail = tst[i].f.Retrieve()
 | 
							mail = tst[i].f.Retrieve()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,9 +14,7 @@
 | 
				
			|||||||
// You should have received a copy of the GNU Lesser General Public License
 | 
					// You should have received a copy of the GNU Lesser General Public License
 | 
				
			||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | 
					// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Contains the Whisper protocol Message element. For formal details please see
 | 
					// Contains the Whisper protocol Message element.
 | 
				
			||||||
// the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#messages.
 | 
					 | 
				
			||||||
// todo: fix the spec link, and move it to doc.go
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
package whisperv5
 | 
					package whisperv5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -256,7 +254,11 @@ func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	envelope = NewEnvelope(options.TTL, options.Topic, salt, nonce, msg)
 | 
						envelope = NewEnvelope(options.TTL, options.Topic, salt, nonce, msg)
 | 
				
			||||||
	envelope.Seal(options)
 | 
						err = envelope.Seal(options)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return envelope, nil
 | 
						return envelope, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,11 +30,15 @@ func copyFromBuf(dst []byte, src []byte, beg int) int {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func generateMessageParams() (*MessageParams, error) {
 | 
					func generateMessageParams() (*MessageParams, error) {
 | 
				
			||||||
 | 
						// set all the parameters except p.Dst
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buf := make([]byte, 1024)
 | 
						buf := make([]byte, 1024)
 | 
				
			||||||
	randomize(buf)
 | 
						randomize(buf)
 | 
				
			||||||
	sz := rand.Intn(400)
 | 
						sz := rand.Intn(400)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var p MessageParams
 | 
						var p MessageParams
 | 
				
			||||||
 | 
						p.PoW = 0.01
 | 
				
			||||||
 | 
						p.WorkTime = 1
 | 
				
			||||||
	p.TTL = uint32(rand.Intn(1024))
 | 
						p.TTL = uint32(rand.Intn(1024))
 | 
				
			||||||
	p.Payload = make([]byte, sz)
 | 
						p.Payload = make([]byte, sz)
 | 
				
			||||||
	p.Padding = make([]byte, padSizeLimitUpper)
 | 
						p.Padding = make([]byte, padSizeLimitUpper)
 | 
				
			||||||
@@ -52,8 +56,6 @@ func generateMessageParams() (*MessageParams, error) {
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// p.Dst, p.PoW, p.WorkTime are not set
 | 
					 | 
				
			||||||
	p.PoW = 0.01
 | 
					 | 
				
			||||||
	return &p, nil
 | 
						return &p, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -114,7 +116,7 @@ func singleMessageTest(t *testing.T, symmetric bool) {
 | 
				
			|||||||
	if len(decrypted.Signature) != signatureLength {
 | 
						if len(decrypted.Signature) != signatureLength {
 | 
				
			||||||
		t.Fatalf("failed with seed %d: signature len %d.", seed, len(decrypted.Signature))
 | 
							t.Fatalf("failed with seed %d: signature len %d.", seed, len(decrypted.Signature))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !isPubKeyEqual(decrypted.Src, ¶ms.Src.PublicKey) {
 | 
						if !IsPubKeyEqual(decrypted.Src, ¶ms.Src.PublicKey) {
 | 
				
			||||||
		t.Fatalf("failed with seed %d: signature mismatch.", seed)
 | 
							t.Fatalf("failed with seed %d: signature mismatch.", seed)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -152,6 +154,16 @@ func TestMessageWrap(t *testing.T) {
 | 
				
			|||||||
	if pow < target {
 | 
						if pow < target {
 | 
				
			||||||
		t.Fatalf("failed Wrap with seed %d: pow < target (%f vs. %f).", seed, pow, target)
 | 
							t.Fatalf("failed Wrap with seed %d: pow < target (%f vs. %f).", seed, pow, target)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// set PoW target too high, expect error
 | 
				
			||||||
 | 
						msg2 := NewSentMessage(params)
 | 
				
			||||||
 | 
						params.TTL = 1000000
 | 
				
			||||||
 | 
						params.WorkTime = 1
 | 
				
			||||||
 | 
						params.PoW = 10000000.0
 | 
				
			||||||
 | 
						env, err = msg2.Wrap(params)
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Fatalf("unexpectedly reached the PoW target with seed %d.", seed)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestMessageSeal(t *testing.T) {
 | 
					func TestMessageSeal(t *testing.T) {
 | 
				
			||||||
@@ -256,7 +268,7 @@ func singleEnvelopeOpenTest(t *testing.T, symmetric bool) {
 | 
				
			|||||||
	if len(decrypted.Signature) != signatureLength {
 | 
						if len(decrypted.Signature) != signatureLength {
 | 
				
			||||||
		t.Fatalf("failed with seed %d: signature len %d.", seed, len(decrypted.Signature))
 | 
							t.Fatalf("failed with seed %d: signature len %d.", seed, len(decrypted.Signature))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !isPubKeyEqual(decrypted.Src, ¶ms.Src.PublicKey) {
 | 
						if !IsPubKeyEqual(decrypted.Src, ¶ms.Src.PublicKey) {
 | 
				
			||||||
		t.Fatalf("failed with seed %d: signature mismatch.", seed)
 | 
							t.Fatalf("failed with seed %d: signature mismatch.", seed)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if decrypted.isAsymmetricEncryption() == symmetric {
 | 
						if decrypted.isAsymmetricEncryption() == symmetric {
 | 
				
			||||||
@@ -269,8 +281,37 @@ func singleEnvelopeOpenTest(t *testing.T, symmetric bool) {
 | 
				
			|||||||
		if decrypted.Dst == nil {
 | 
							if decrypted.Dst == nil {
 | 
				
			||||||
			t.Fatalf("failed with seed %d: dst is nil.", seed)
 | 
								t.Fatalf("failed with seed %d: dst is nil.", seed)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if !isPubKeyEqual(decrypted.Dst, &key.PublicKey) {
 | 
							if !IsPubKeyEqual(decrypted.Dst, &key.PublicKey) {
 | 
				
			||||||
			t.Fatalf("failed with seed %d: Dst.", seed)
 | 
								t.Fatalf("failed with seed %d: Dst.", seed)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestEncryptWithZeroKey(t *testing.T) {
 | 
				
			||||||
 | 
						InitSingleTest()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						params, err := generateMessageParams()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msg := NewSentMessage(params)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						params.KeySym = make([]byte, aesKeyLength)
 | 
				
			||||||
 | 
						_, err = msg.Wrap(params)
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Fatalf("wrapped with zero key, seed: %d.", seed)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						params.KeySym = make([]byte, 0)
 | 
				
			||||||
 | 
						_, err = msg.Wrap(params)
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Fatalf("wrapped with empty key, seed: %d.", seed)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						params.KeySym = nil
 | 
				
			||||||
 | 
						_, err = msg.Wrap(params)
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Fatalf("wrapped with nil key, seed: %d.", seed)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -118,6 +118,7 @@ func initialize(t *testing.T) {
 | 
				
			|||||||
		var node TestNode
 | 
							var node TestNode
 | 
				
			||||||
		node.shh = NewWhisper(nil)
 | 
							node.shh = NewWhisper(nil)
 | 
				
			||||||
		node.shh.test = true
 | 
							node.shh.test = true
 | 
				
			||||||
 | 
							node.shh.Start(nil)
 | 
				
			||||||
		topics := make([]TopicType, 0)
 | 
							topics := make([]TopicType, 0)
 | 
				
			||||||
		topics = append(topics, sharedTopic)
 | 
							topics = append(topics, sharedTopic)
 | 
				
			||||||
		f := Filter{KeySym: sharedKey, Topics: topics}
 | 
							f := Filter{KeySym: sharedKey, Topics: topics}
 | 
				
			||||||
@@ -166,6 +167,7 @@ func stopServers() {
 | 
				
			|||||||
		n := nodes[i]
 | 
							n := nodes[i]
 | 
				
			||||||
		if n != nil {
 | 
							if n != nil {
 | 
				
			||||||
			n.shh.Unwatch(n.filerId)
 | 
								n.shh.Unwatch(n.filerId)
 | 
				
			||||||
 | 
								n.shh.Stop()
 | 
				
			||||||
			n.server.Stop()
 | 
								n.server.Stop()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,8 +14,7 @@
 | 
				
			|||||||
// You should have received a copy of the GNU Lesser General Public License
 | 
					// You should have received a copy of the GNU Lesser General Public License
 | 
				
			||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | 
					// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Contains the Whisper protocol Topic element. For formal details please see
 | 
					// Contains the Whisper protocol Topic element.
 | 
				
			||||||
// the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#topics.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
package whisperv5
 | 
					package whisperv5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,7 @@ import (
 | 
				
			|||||||
	crand "crypto/rand"
 | 
						crand "crypto/rand"
 | 
				
			||||||
	"crypto/sha256"
 | 
						"crypto/sha256"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"runtime"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -45,7 +46,7 @@ type Whisper struct {
 | 
				
			|||||||
	symKeys     map[string][]byte
 | 
						symKeys     map[string][]byte
 | 
				
			||||||
	keyMu       sync.RWMutex
 | 
						keyMu       sync.RWMutex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	envelopes   map[common.Hash]*Envelope        // Pool of messages currently tracked by this node
 | 
						envelopes   map[common.Hash]*Envelope        // Pool of envelopes currently tracked by this node
 | 
				
			||||||
	messages    map[common.Hash]*ReceivedMessage // Pool of successfully decrypted messages, which are not expired yet
 | 
						messages    map[common.Hash]*ReceivedMessage // Pool of successfully decrypted messages, which are not expired yet
 | 
				
			||||||
	expirations map[uint32]*set.SetNonTS         // Message expiration pool
 | 
						expirations map[uint32]*set.SetNonTS         // Message expiration pool
 | 
				
			||||||
	poolMu      sync.RWMutex                     // Mutex to sync the message and expiration pools
 | 
						poolMu      sync.RWMutex                     // Mutex to sync the message and expiration pools
 | 
				
			||||||
@@ -55,22 +56,28 @@ type Whisper struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	mailServer MailServer
 | 
						mailServer MailServer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	quit chan struct{}
 | 
						messageQueue chan *Envelope
 | 
				
			||||||
	test bool
 | 
						p2pMsgQueue  chan *Envelope
 | 
				
			||||||
 | 
						quit         chan struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						overflow bool
 | 
				
			||||||
 | 
						test     bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// New creates a Whisper client ready to communicate through the Ethereum P2P network.
 | 
					// New creates a Whisper client ready to communicate through the Ethereum P2P network.
 | 
				
			||||||
// Param s should be passed if you want to implement mail server, otherwise nil.
 | 
					// Param s should be passed if you want to implement mail server, otherwise nil.
 | 
				
			||||||
func NewWhisper(server MailServer) *Whisper {
 | 
					func NewWhisper(server MailServer) *Whisper {
 | 
				
			||||||
	whisper := &Whisper{
 | 
						whisper := &Whisper{
 | 
				
			||||||
		privateKeys: make(map[string]*ecdsa.PrivateKey),
 | 
							privateKeys:  make(map[string]*ecdsa.PrivateKey),
 | 
				
			||||||
		symKeys:     make(map[string][]byte),
 | 
							symKeys:      make(map[string][]byte),
 | 
				
			||||||
		envelopes:   make(map[common.Hash]*Envelope),
 | 
							envelopes:    make(map[common.Hash]*Envelope),
 | 
				
			||||||
		messages:    make(map[common.Hash]*ReceivedMessage),
 | 
							messages:     make(map[common.Hash]*ReceivedMessage),
 | 
				
			||||||
		expirations: make(map[uint32]*set.SetNonTS),
 | 
							expirations:  make(map[uint32]*set.SetNonTS),
 | 
				
			||||||
		peers:       make(map[*Peer]struct{}),
 | 
							peers:        make(map[*Peer]struct{}),
 | 
				
			||||||
		mailServer:  server,
 | 
							mailServer:   server,
 | 
				
			||||||
		quit:        make(chan struct{}),
 | 
							messageQueue: make(chan *Envelope, messageQueueLimit),
 | 
				
			||||||
 | 
							p2pMsgQueue:  make(chan *Envelope, messageQueueLimit),
 | 
				
			||||||
 | 
							quit:         make(chan struct{}),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	whisper.filters = NewFilters(whisper)
 | 
						whisper.filters = NewFilters(whisper)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -124,7 +131,7 @@ func (w *Whisper) RequestHistoricMessages(peerID []byte, data []byte) error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	p.trusted = true
 | 
						p.trusted = true
 | 
				
			||||||
	return p2p.Send(p.ws, mailRequestCode, data)
 | 
						return p2p.Send(p.ws, p2pRequestCode, data)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (w *Whisper) SendP2PMessage(peerID []byte, envelope *Envelope) error {
 | 
					func (w *Whisper) SendP2PMessage(peerID []byte, envelope *Envelope) error {
 | 
				
			||||||
@@ -270,6 +277,12 @@ func (w *Whisper) Send(envelope *Envelope) error {
 | 
				
			|||||||
func (w *Whisper) Start(*p2p.Server) error {
 | 
					func (w *Whisper) Start(*p2p.Server) error {
 | 
				
			||||||
	glog.V(logger.Info).Infoln("Whisper started")
 | 
						glog.V(logger.Info).Infoln("Whisper started")
 | 
				
			||||||
	go w.update()
 | 
						go w.update()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						numCPU := runtime.NumCPU()
 | 
				
			||||||
 | 
						for i := 0; i < numCPU; i++ {
 | 
				
			||||||
 | 
							go w.processQueue()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -350,10 +363,10 @@ func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
 | 
				
			|||||||
					return fmt.Errorf("garbage received (directMessage)")
 | 
										return fmt.Errorf("garbage received (directMessage)")
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				for _, envelope := range envelopes {
 | 
									for _, envelope := range envelopes {
 | 
				
			||||||
					wh.postEvent(envelope, p2pCode)
 | 
										wh.postEvent(envelope, true)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		case mailRequestCode:
 | 
							case p2pRequestCode:
 | 
				
			||||||
			// Must be processed if mail server is implemented. Otherwise ignore.
 | 
								// Must be processed if mail server is implemented. Otherwise ignore.
 | 
				
			||||||
			if wh.mailServer != nil {
 | 
								if wh.mailServer != nil {
 | 
				
			||||||
				s := rlp.NewStream(packet.Payload, uint64(packet.Size))
 | 
									s := rlp.NewStream(packet.Payload, uint64(packet.Size))
 | 
				
			||||||
@@ -382,7 +395,7 @@ func (wh *Whisper) add(envelope *Envelope) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if sent > now {
 | 
						if sent > now {
 | 
				
			||||||
		if sent-SynchAllowance > now {
 | 
							if sent-SynchAllowance > now {
 | 
				
			||||||
			return fmt.Errorf("message created in the future")
 | 
								return fmt.Errorf("envelope created in the future [%x]", envelope.Hash())
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			// recalculate PoW, adjusted for the time difference, plus one second for latency
 | 
								// recalculate PoW, adjusted for the time difference, plus one second for latency
 | 
				
			||||||
			envelope.calculatePoW(sent - now + 1)
 | 
								envelope.calculatePoW(sent - now + 1)
 | 
				
			||||||
@@ -393,30 +406,31 @@ func (wh *Whisper) add(envelope *Envelope) error {
 | 
				
			|||||||
		if envelope.Expiry+SynchAllowance*2 < now {
 | 
							if envelope.Expiry+SynchAllowance*2 < now {
 | 
				
			||||||
			return fmt.Errorf("very old message")
 | 
								return fmt.Errorf("very old message")
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
 | 
								glog.V(logger.Debug).Infof("expired envelope dropped [%x]", envelope.Hash())
 | 
				
			||||||
			return nil // drop envelope without error
 | 
								return nil // drop envelope without error
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(envelope.Data) > MaxMessageLength {
 | 
						if len(envelope.Data) > MaxMessageLength {
 | 
				
			||||||
		return fmt.Errorf("huge messages are not allowed")
 | 
							return fmt.Errorf("huge messages are not allowed [%x]", envelope.Hash())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(envelope.Version) > 4 {
 | 
						if len(envelope.Version) > 4 {
 | 
				
			||||||
		return fmt.Errorf("oversized Version")
 | 
							return fmt.Errorf("oversized version [%x]", envelope.Hash())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(envelope.AESNonce) > AESNonceMaxLength {
 | 
						if len(envelope.AESNonce) > AESNonceMaxLength {
 | 
				
			||||||
		// the standard AES GSM nonce size is 12,
 | 
							// the standard AES GSM nonce size is 12,
 | 
				
			||||||
		// but const gcmStandardNonceSize cannot be accessed directly
 | 
							// but const gcmStandardNonceSize cannot be accessed directly
 | 
				
			||||||
		return fmt.Errorf("oversized AESNonce")
 | 
							return fmt.Errorf("oversized AESNonce [%x]", envelope.Hash())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(envelope.Salt) > saltLength {
 | 
						if len(envelope.Salt) > saltLength {
 | 
				
			||||||
		return fmt.Errorf("oversized Salt")
 | 
							return fmt.Errorf("oversized salt [%x]", envelope.Hash())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if envelope.PoW() < MinimumPoW && !wh.test {
 | 
						if envelope.PoW() < MinimumPoW && !wh.test {
 | 
				
			||||||
		glog.V(logger.Debug).Infof("envelope with low PoW dropped: %f", envelope.PoW())
 | 
							glog.V(logger.Debug).Infof("envelope with low PoW dropped: %f [%x]", envelope.PoW(), envelope.Hash())
 | 
				
			||||||
		return nil // drop envelope without error
 | 
							return nil // drop envelope without error
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -436,22 +450,59 @@ func (wh *Whisper) add(envelope *Envelope) error {
 | 
				
			|||||||
	wh.poolMu.Unlock()
 | 
						wh.poolMu.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if alreadyCached {
 | 
						if alreadyCached {
 | 
				
			||||||
		glog.V(logger.Detail).Infof("whisper envelope already cached: %x\n", envelope)
 | 
							glog.V(logger.Detail).Infof("whisper envelope already cached [%x]\n", envelope.Hash())
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		wh.postEvent(envelope, messagesCode) // notify the local node about the new message
 | 
							glog.V(logger.Detail).Infof("cached whisper envelope [%x]: %v\n", envelope.Hash(), envelope)
 | 
				
			||||||
		glog.V(logger.Detail).Infof("cached whisper envelope %v\n", envelope)
 | 
							wh.postEvent(envelope, false) // notify the local node about the new message
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// postEvent delivers the message to the watchers.
 | 
					// postEvent queues the message for further processing.
 | 
				
			||||||
func (w *Whisper) postEvent(envelope *Envelope, messageCode uint64) {
 | 
					func (w *Whisper) postEvent(envelope *Envelope, isP2P bool) {
 | 
				
			||||||
	// if the version of incoming message is higher than
 | 
						// if the version of incoming message is higher than
 | 
				
			||||||
	// currently supported version, we can not decrypt it,
 | 
						// currently supported version, we can not decrypt it,
 | 
				
			||||||
	// and therefore just ignore this message
 | 
						// and therefore just ignore this message
 | 
				
			||||||
	if envelope.Ver() <= EnvelopeVersion {
 | 
						if envelope.Ver() <= EnvelopeVersion {
 | 
				
			||||||
		// todo: review if you need an additional thread here
 | 
							if isP2P {
 | 
				
			||||||
		go w.filters.NotifyWatchers(envelope, messageCode)
 | 
								w.p2pMsgQueue <- envelope
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								w.checkOverflow()
 | 
				
			||||||
 | 
								w.messageQueue <- envelope
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// checkOverflow checks if message queue overflow occurs and reports it if necessary.
 | 
				
			||||||
 | 
					func (w *Whisper) checkOverflow() {
 | 
				
			||||||
 | 
						queueSize := len(w.messageQueue)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if queueSize == messageQueueLimit {
 | 
				
			||||||
 | 
							if !w.overflow {
 | 
				
			||||||
 | 
								w.overflow = true
 | 
				
			||||||
 | 
								glog.V(logger.Warn).Infoln("message queue overflow")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if queueSize <= messageQueueLimit/2 {
 | 
				
			||||||
 | 
							if w.overflow {
 | 
				
			||||||
 | 
								w.overflow = false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// processQueue delivers the messages to the watchers during the lifetime of the whisper node.
 | 
				
			||||||
 | 
					func (w *Whisper) processQueue() {
 | 
				
			||||||
 | 
						var e *Envelope
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							select {
 | 
				
			||||||
 | 
							case <-w.quit:
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case e = <-w.messageQueue:
 | 
				
			||||||
 | 
								w.filters.NotifyWatchers(e, false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case e = <-w.p2pMsgQueue:
 | 
				
			||||||
 | 
								w.filters.NotifyWatchers(e, true)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ package whisperv5
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/ethereum/go-ethereum/common"
 | 
						"github.com/ethereum/go-ethereum/common"
 | 
				
			||||||
	"github.com/ethereum/go-ethereum/crypto"
 | 
						"github.com/ethereum/go-ethereum/crypto"
 | 
				
			||||||
@@ -309,3 +310,56 @@ func TestWhisperSymKeyManagement(t *testing.T) {
 | 
				
			|||||||
		t.Fatalf("failed to delete second key: second key is not nil.")
 | 
							t.Fatalf("failed to delete second key: second key is not nil.")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestExpiry(t *testing.T) {
 | 
				
			||||||
 | 
						InitSingleTest()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						w := NewWhisper(nil)
 | 
				
			||||||
 | 
						w.test = true
 | 
				
			||||||
 | 
						w.Start(nil)
 | 
				
			||||||
 | 
						defer w.Stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						params, err := generateMessageParams()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						params.TTL = 1
 | 
				
			||||||
 | 
						msg := NewSentMessage(params)
 | 
				
			||||||
 | 
						env, err := msg.Wrap(params)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = w.Send(env)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("failed to send envelope with seed %d: %s.", seed, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// wait till received or timeout
 | 
				
			||||||
 | 
						var received, expired bool
 | 
				
			||||||
 | 
						for j := 0; j < 20; j++ {
 | 
				
			||||||
 | 
							time.Sleep(100 * time.Millisecond)
 | 
				
			||||||
 | 
							if len(w.Envelopes()) > 0 {
 | 
				
			||||||
 | 
								received = true
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !received {
 | 
				
			||||||
 | 
							t.Fatalf("did not receive the sent envelope, seed: %d.", seed)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// wait till expired or timeout
 | 
				
			||||||
 | 
						for j := 0; j < 20; j++ {
 | 
				
			||||||
 | 
							time.Sleep(100 * time.Millisecond)
 | 
				
			||||||
 | 
							if len(w.Envelopes()) == 0 {
 | 
				
			||||||
 | 
								expired = true
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !expired {
 | 
				
			||||||
 | 
							t.Fatalf("expire failed, seed: %d.", seed)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user