mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
whisper: expiry refactoring
This commit is contained in:
parent
e026f53ab5
commit
5e5b2b1300
3 changed files with 65 additions and 32 deletions
|
|
@ -65,6 +65,14 @@ func (api *PublicWhisperAPI) Version() (hexutil.Uint, error) {
|
||||||
return hexutil.Uint(api.whisper.Version()), nil
|
return hexutil.Uint(api.whisper.Version()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stats returns the Whisper statistics for diagnostics.
|
||||||
|
func (api *PublicWhisperAPI) Stats() (string, error) {
|
||||||
|
if api.whisper == nil {
|
||||||
|
return "", whisperOffLineErr
|
||||||
|
}
|
||||||
|
return api.whisper.Stats(), nil
|
||||||
|
}
|
||||||
|
|
||||||
// MarkPeerTrusted marks specific peer trusted, which will allow it
|
// MarkPeerTrusted marks specific peer trusted, which will allow it
|
||||||
// to send historic (expired) messages.
|
// to send historic (expired) messages.
|
||||||
func (api *PublicWhisperAPI) MarkPeerTrusted(peerID hexutil.Bytes) error {
|
func (api *PublicWhisperAPI) MarkPeerTrusted(peerID hexutil.Bytes) error {
|
||||||
|
|
|
||||||
|
|
@ -134,20 +134,14 @@ func (peer *Peer) marked(envelope *Envelope) bool {
|
||||||
// expire iterates over all the known envelopes in the host and removes all
|
// expire iterates over all the known envelopes in the host and removes all
|
||||||
// expired (unknown) ones from the known list.
|
// expired (unknown) ones from the known list.
|
||||||
func (peer *Peer) expire() {
|
func (peer *Peer) expire() {
|
||||||
// Assemble the list of available envelopes
|
|
||||||
available := set.NewNonTS()
|
|
||||||
for _, envelope := range peer.host.Envelopes() {
|
|
||||||
available.Add(envelope.Hash())
|
|
||||||
}
|
|
||||||
// Cross reference availability with known status
|
|
||||||
unmark := make(map[common.Hash]struct{})
|
unmark := make(map[common.Hash]struct{})
|
||||||
peer.known.Each(func(v interface{}) bool {
|
peer.known.Each(func(v interface{}) bool {
|
||||||
if !available.Has(v.(common.Hash)) {
|
if !peer.host.isEnvelopeCached(v.(common.Hash)) {
|
||||||
unmark[v.(common.Hash)] = struct{}{}
|
unmark[v.(common.Hash)] = struct{}{}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
// Dump all known but unavailable
|
// Dump all known but no longer cached
|
||||||
for hash := range unmark {
|
for hash := range unmark {
|
||||||
peer.known.Remove(hash)
|
peer.known.Remove(hash)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,11 @@ import (
|
||||||
set "gopkg.in/fatih/set.v0"
|
set "gopkg.in/fatih/set.v0"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Statistics struct {
|
||||||
|
messages int
|
||||||
|
memory int
|
||||||
|
}
|
||||||
|
|
||||||
// Whisper represents a dark communication interface through the Ethereum
|
// Whisper represents a dark communication interface through the Ethereum
|
||||||
// network, using its very own P2P communication layer.
|
// network, using its very own P2P communication layer.
|
||||||
type Whisper struct {
|
type Whisper struct {
|
||||||
|
|
@ -60,6 +65,8 @@ type Whisper struct {
|
||||||
p2pMsgQueue chan *Envelope
|
p2pMsgQueue chan *Envelope
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
|
|
||||||
|
stats Statistics
|
||||||
|
|
||||||
overflow bool
|
overflow bool
|
||||||
test bool
|
test bool
|
||||||
}
|
}
|
||||||
|
|
@ -288,7 +295,8 @@ func (w *Whisper) Unwatch(id string) {
|
||||||
// Send injects a message into the whisper send queue, to be distributed in the
|
// Send injects a message into the whisper send queue, to be distributed in the
|
||||||
// network in the coming cycles.
|
// network in the coming cycles.
|
||||||
func (w *Whisper) Send(envelope *Envelope) error {
|
func (w *Whisper) Send(envelope *Envelope) error {
|
||||||
return w.add(envelope)
|
_, err := w.add(envelope)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start implements node.Service, starting the background data propagation thread
|
// Start implements node.Service, starting the background data propagation thread
|
||||||
|
|
@ -361,11 +369,14 @@ func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
|
||||||
}
|
}
|
||||||
// inject all envelopes into the internal pool
|
// inject all envelopes into the internal pool
|
||||||
for _, envelope := range envelopes {
|
for _, envelope := range envelopes {
|
||||||
if err := wh.add(envelope); err != nil {
|
cached, err := wh.add(envelope)
|
||||||
|
if err != nil {
|
||||||
glog.V(logger.Warn).Infof("%v: bad envelope received: [%v], peer will be disconnected", p.peer, err)
|
glog.V(logger.Warn).Infof("%v: bad envelope received: [%v], peer will be disconnected", p.peer, err)
|
||||||
return fmt.Errorf("invalid envelope")
|
return fmt.Errorf("invalid envelope")
|
||||||
}
|
}
|
||||||
p.mark(envelope)
|
if cached {
|
||||||
|
p.mark(envelope)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case p2pCode:
|
case p2pCode:
|
||||||
// peer-to-peer message, sent directly to peer bypassing PoW checks, etc.
|
// peer-to-peer message, sent directly to peer bypassing PoW checks, etc.
|
||||||
|
|
@ -402,13 +413,13 @@ func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
|
||||||
// add inserts a new envelope into the message pool to be distributed within the
|
// add inserts a new envelope into the message pool to be distributed within the
|
||||||
// whisper network. It also inserts the envelope into the expiration pool at the
|
// whisper network. It also inserts the envelope into the expiration pool at the
|
||||||
// appropriate time-stamp. In case of error, connection should be dropped.
|
// appropriate time-stamp. In case of error, connection should be dropped.
|
||||||
func (wh *Whisper) add(envelope *Envelope) error {
|
func (wh *Whisper) add(envelope *Envelope) (bool, error) {
|
||||||
now := uint32(time.Now().Unix())
|
now := uint32(time.Now().Unix())
|
||||||
sent := envelope.Expiry - envelope.TTL
|
sent := envelope.Expiry - envelope.TTL
|
||||||
|
|
||||||
if sent > now {
|
if sent > now {
|
||||||
if sent-SynchAllowance > now {
|
if sent-SynchAllowance > now {
|
||||||
return fmt.Errorf("envelope created in the future [%x]", envelope.Hash())
|
return false, 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)
|
||||||
|
|
@ -417,34 +428,34 @@ func (wh *Whisper) add(envelope *Envelope) error {
|
||||||
|
|
||||||
if envelope.Expiry < now {
|
if envelope.Expiry < now {
|
||||||
if envelope.Expiry+SynchAllowance*2 < now {
|
if envelope.Expiry+SynchAllowance*2 < now {
|
||||||
return fmt.Errorf("very old message")
|
return false, fmt.Errorf("very old message")
|
||||||
} else {
|
} else {
|
||||||
glog.V(logger.Debug).Infof("expired envelope dropped [%x]", envelope.Hash())
|
glog.V(logger.Debug).Infof("expired envelope dropped [%x]", envelope.Hash())
|
||||||
return nil // drop envelope without error
|
return false, nil // drop envelope without error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(envelope.Data) > MaxMessageLength {
|
if len(envelope.Data) > MaxMessageLength {
|
||||||
return fmt.Errorf("huge messages are not allowed [%x]", envelope.Hash())
|
return false, 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 [%x]", envelope.Hash())
|
return false, 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 [%x]", envelope.Hash())
|
return false, fmt.Errorf("oversized AESNonce [%x]", envelope.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(envelope.Salt) > saltLength {
|
if len(envelope.Salt) > saltLength {
|
||||||
return fmt.Errorf("oversized salt [%x]", envelope.Hash())
|
return false, 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 [%x]", envelope.PoW(), envelope.Hash())
|
glog.V(logger.Debug).Infof("envelope with low PoW dropped: %f [%x]", envelope.PoW(), envelope.Hash())
|
||||||
return nil // drop envelope without error
|
return false, nil // drop envelope without error
|
||||||
}
|
}
|
||||||
|
|
||||||
hash := envelope.Hash()
|
hash := envelope.Hash()
|
||||||
|
|
@ -471,7 +482,7 @@ func (wh *Whisper) add(envelope *Envelope) error {
|
||||||
wh.mailServer.Archive(envelope)
|
wh.mailServer.Archive(envelope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// postEvent queues the message for further processing.
|
// postEvent queues the message for further processing.
|
||||||
|
|
@ -546,22 +557,29 @@ func (w *Whisper) expire() {
|
||||||
w.poolMu.Lock()
|
w.poolMu.Lock()
|
||||||
defer w.poolMu.Unlock()
|
defer w.poolMu.Unlock()
|
||||||
|
|
||||||
|
w.stats.clear()
|
||||||
now := uint32(time.Now().Unix())
|
now := uint32(time.Now().Unix())
|
||||||
for then, hashSet := range w.expirations {
|
for expiry, hashSet := range w.expirations {
|
||||||
// Short circuit if a future time
|
if expiry < now {
|
||||||
if then > now {
|
w.stats.messages++
|
||||||
continue
|
|
||||||
|
// Dump all expired messages and remove timestamp
|
||||||
|
hashSet.Each(func(v interface{}) bool {
|
||||||
|
w.stats.memory += w.envelopes[v.(common.Hash)].size()
|
||||||
|
delete(w.envelopes, v.(common.Hash))
|
||||||
|
delete(w.messages, v.(common.Hash))
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
w.expirations[expiry].Clear()
|
||||||
|
delete(w.expirations, expiry)
|
||||||
}
|
}
|
||||||
// Dump all expired messages and remove timestamp
|
|
||||||
hashSet.Each(func(v interface{}) bool {
|
|
||||||
delete(w.envelopes, v.(common.Hash))
|
|
||||||
delete(w.messages, v.(common.Hash))
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
w.expirations[then].Clear()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *Whisper) Stats() string {
|
||||||
|
return fmt.Sprintf("Latest expiry cycle cleared %d messages (%d bytes)", w.stats.messages, w.stats.memory)
|
||||||
|
}
|
||||||
|
|
||||||
// envelopes retrieves all the messages currently pooled by the node.
|
// envelopes retrieves all the messages currently pooled by the node.
|
||||||
func (w *Whisper) Envelopes() []*Envelope {
|
func (w *Whisper) Envelopes() []*Envelope {
|
||||||
w.poolMu.RLock()
|
w.poolMu.RLock()
|
||||||
|
|
@ -590,6 +608,14 @@ func (w *Whisper) Messages(id string) []*ReceivedMessage {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *Whisper) isEnvelopeCached(hash common.Hash) bool {
|
||||||
|
w.poolMu.Lock()
|
||||||
|
defer w.poolMu.Unlock()
|
||||||
|
|
||||||
|
_, exist := w.envelopes[hash]
|
||||||
|
return exist
|
||||||
|
}
|
||||||
|
|
||||||
func (w *Whisper) addDecryptedMessage(msg *ReceivedMessage) {
|
func (w *Whisper) addDecryptedMessage(msg *ReceivedMessage) {
|
||||||
w.poolMu.Lock()
|
w.poolMu.Lock()
|
||||||
defer w.poolMu.Unlock()
|
defer w.poolMu.Unlock()
|
||||||
|
|
@ -597,6 +623,11 @@ func (w *Whisper) addDecryptedMessage(msg *ReceivedMessage) {
|
||||||
w.messages[msg.EnvelopeHash] = msg
|
w.messages[msg.EnvelopeHash] = msg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Statistics) clear() {
|
||||||
|
s.memory = 0
|
||||||
|
s.messages = 0
|
||||||
|
}
|
||||||
|
|
||||||
func ValidatePublicKey(k *ecdsa.PublicKey) bool {
|
func ValidatePublicKey(k *ecdsa.PublicKey) bool {
|
||||||
return k != nil && k.X != nil && k.Y != nil && k.X.Sign() != 0 && k.Y.Sign() != 0
|
return k != nil && k.X != nil && k.Y != nil && k.X.Sign() != 0 && k.Y.Sign() != 0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue