diff --git c/whisper/whisperv6/api.go w/whisper/whisperv6/api.go index 16db034e1..25c072355 100644 --- c/whisper/whisperv6/api.go +++ w/whisper/whisperv6/api.go @@ -246,6 +246,29 @@ type newMessageOverride struct { // Post a message on the Whisper network. func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, error) { + env, err := MakeEnvelope(api.w, req) + if err != nil { + return false, err + } + // send to specific node (skip PoW check) + if len(req.TargetPeer) > 0 { + n, err := discover.ParseNode(req.TargetPeer) + if err != nil { + return false, fmt.Errorf("failed to parse target peer: %s", err) + } + return true, api.w.SendP2PMessage(n.ID[:], env) + } + + // ensure that the message PoW meets the node's minimum accepted PoW + if req.PowTarget < api.w.MinPow() { + return false, ErrTooLowPoW + } + + return true, api.w.Send(env) +} + +// MakeEnvelope create envelopes from request. +func MakeEnvelope(w *Whisper, req NewMessage) (*Envelope, error) { var ( symKeyGiven = len(req.SymKeyID) > 0 pubKeyGiven = len(req.PublicKey) > 0 @@ -254,7 +277,7 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, er // user must specify either a symmetric or an asymmetric key if (symKeyGiven && pubKeyGiven) || (!symKeyGiven && !pubKeyGiven) { - return false, ErrSymAsym + return nil, ErrSymAsym } params := &MessageParams{ @@ -268,21 +291,21 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, er // Set key that is used to sign the message if len(req.Sig) > 0 { - if params.Src, err = api.w.GetPrivateKey(req.Sig); err != nil { - return false, err + if params.Src, err = w.GetPrivateKey(req.Sig); err != nil { + return nil, err } } // Set symmetric key that is used to encrypt the message if symKeyGiven { if params.Topic == (TopicType{}) { // topics are mandatory with symmetric encryption - return false, ErrNoTopics + return nil, ErrNoTopics } - if params.KeySym, err = api.w.GetSymKey(req.SymKeyID); err != nil { - return false, err + if params.KeySym, err = w.GetSymKey(req.SymKeyID); err != nil { + return nil, err } if !validateDataIntegrity(params.KeySym, aesKeyLength) { - return false, ErrInvalidSymmetricKey + return nil, ErrInvalidSymmetricKey } } @@ -290,36 +313,21 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, er if pubKeyGiven { params.Dst = crypto.ToECDSAPub(req.PublicKey) if !ValidatePublicKey(params.Dst) { - return false, ErrInvalidPublicKey + return nil, ErrInvalidPublicKey } } // encrypt and sent message whisperMsg, err := NewSentMessage(params) if err != nil { - return false, err + return nil, err } env, err := whisperMsg.Wrap(params) if err != nil { - return false, err + return nil, err } - - // send to specific node (skip PoW check) - if len(req.TargetPeer) > 0 { - n, err := discover.ParseNode(req.TargetPeer) - if err != nil { - return false, fmt.Errorf("failed to parse target peer: %s", err) - } - return true, api.w.SendP2PMessage(n.ID[:], env) - } - - // ensure that the message PoW meets the node's minimum accepted PoW - if req.PowTarget < api.w.MinPow() { - return false, ErrTooLowPoW - } - - return true, api.w.Send(env) + return env, nil } // UninstallFilter is alias for Unsubscribe diff --git c/whisper/whisperv6/events.go w/whisper/whisperv6/events.go new file mode 100644 index 000000000..4f204ab5d --- /dev/null +++ w/whisper/whisperv6/events.go @@ -0,0 +1,23 @@ +package whisperv6 + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/p2p/discover" +) + +// EventType used to define known envelope events. +type EventType string + +const ( + // EventEnvelopeSent fires when envelope was sent to a peer. + EventEnvelopeSent EventType = "envelope.sent" + // EventEnvelopeExpired fires when envelop expired + EventEnvelopeExpired EventType = "envelope.expired" +) + +// EnvelopeEvent used for envelopes events. +type EnvelopeEvent struct { + Event EventType + Hash common.Hash + Peer discover.NodeID +} diff --git c/whisper/whisperv6/peer.go w/whisper/whisperv6/peer.go index 6d75290fd..120767c33 100644 --- c/whisper/whisperv6/peer.go +++ w/whisper/whisperv6/peer.go @@ -204,6 +204,11 @@ func (peer *Peer) broadcast() error { // mark envelopes only if they were successfully sent for _, e := range bundle { peer.mark(e) + peer.host.envelopeFeed.Send(EnvelopeEvent{ + Event: EventEnvelopeSent, + Hash: e.Hash(), + Peer: peer.peer.ID(), // specifically discover.NodeID because it can be pretty printed + }) } log.Trace("broadcast", "num. messages", len(bundle)) diff --git c/whisper/whisperv6/whisper.go w/whisper/whisperv6/whisper.go index 8bd991a9b..98115b20f 100644 --- c/whisper/whisperv6/whisper.go +++ w/whisper/whisperv6/whisper.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rlp" @@ -85,8 +86,10 @@ type Whisper struct { statsMu sync.Mutex // guard stats stats Statistics // Statistics of whisper node - mailServer MailServer // MailServer interface - envelopeTracer EnvelopeTracer // Service collecting envelopes metadata + mailServer MailServer // MailServer interface + envelopeTracer EnvelopeTracer // Service collecting envelopes metadata + + envelopeFeed event.Feed } // New creates a Whisper client ready to communicate through the Ethereum P2P network. @@ -131,6 +134,12 @@ func New(cfg *Config) *Whisper { return whisper } +// SubscribeEnvelopeEvents subscribes to envelopes feed. +// In order to prevent blocking whisper producers events must be amply buffered. +func (whisper *Whisper) SubscribeEnvelopeEvents(events chan<- EnvelopeEvent) event.Subscription { + return whisper.envelopeFeed.Subscribe(events) +} + // MinPow returns the PoW value required by this node. func (whisper *Whisper) MinPow() float64 { val, exist := whisper.settings.Load(minPowIdx) @@ -986,6 +995,10 @@ func (whisper *Whisper) expire() { hashSet.Each(func(v interface{}) bool { sz := whisper.envelopes[v.(common.Hash)].size() delete(whisper.envelopes, v.(common.Hash)) + whisper.envelopeFeed.Send(EnvelopeEvent{ + Hash: v.(common.Hash), + Event: EventEnvelopeExpired, + }) whisper.stats.messagesCleared++ whisper.stats.memoryCleared += sz whisper.stats.memoryUsed -= sz