2014-12-08 03:43:33 -08:00
|
|
|
package whisper
|
|
|
|
|
|
|
|
import (
|
2014-12-10 05:17:32 -08:00
|
|
|
"crypto/ecdsa"
|
2014-12-09 15:03:50 -08:00
|
|
|
"errors"
|
2014-12-08 03:43:33 -08:00
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
2015-03-20 16:57:18 -07:00
|
|
|
"github.com/ethereum/go-ethereum/common"
|
2014-12-10 05:17:32 -08:00
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
2015-02-13 15:25:47 -08:00
|
|
|
"github.com/ethereum/go-ethereum/crypto/ecies"
|
2014-12-12 13:23:42 -08:00
|
|
|
"github.com/ethereum/go-ethereum/event/filter"
|
2014-12-15 03:01:55 -08:00
|
|
|
"github.com/ethereum/go-ethereum/logger"
|
2015-04-07 05:57:04 -07:00
|
|
|
"github.com/ethereum/go-ethereum/logger/glog"
|
2014-12-08 03:43:33 -08:00
|
|
|
"github.com/ethereum/go-ethereum/p2p"
|
|
|
|
"gopkg.in/fatih/set.v0"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2015-03-25 04:08:48 -07:00
|
|
|
statusMsg = 0x0
|
|
|
|
envelopesMsg = 0x01
|
|
|
|
whisperVersion = 0x02
|
2015-04-13 01:31:51 -07:00
|
|
|
|
|
|
|
signatureFlag = byte(1 << 7)
|
|
|
|
signatureLength = 65
|
2014-12-08 03:43:33 -08:00
|
|
|
)
|
|
|
|
|
2015-04-13 06:19:34 -07:00
|
|
|
const (
|
|
|
|
DefaultTimeToLive = 50 * time.Second
|
|
|
|
DefaultProofOfWork = 50 * time.Millisecond
|
|
|
|
)
|
|
|
|
|
2014-12-12 13:23:42 -08:00
|
|
|
type MessageEvent struct {
|
|
|
|
To *ecdsa.PrivateKey
|
|
|
|
From *ecdsa.PublicKey
|
|
|
|
Message *Message
|
|
|
|
}
|
|
|
|
|
2015-04-13 06:19:34 -07:00
|
|
|
// Whisper represents a dark communication interface through the Ethereum
|
|
|
|
// network, using its very own P2P communication layer.
|
2014-12-08 03:43:33 -08:00
|
|
|
type Whisper struct {
|
|
|
|
protocol p2p.Protocol
|
2014-12-12 13:23:42 -08:00
|
|
|
filters *filter.Filters
|
2014-12-08 03:43:33 -08:00
|
|
|
|
|
|
|
mmu sync.RWMutex
|
2015-03-20 16:57:18 -07:00
|
|
|
messages map[common.Hash]*Envelope
|
2014-12-09 15:03:50 -08:00
|
|
|
expiry map[uint32]*set.SetNonTS
|
2014-12-08 03:43:33 -08:00
|
|
|
|
|
|
|
quit chan struct{}
|
2014-12-12 13:23:42 -08:00
|
|
|
|
2015-01-14 09:12:18 -08:00
|
|
|
keys map[string]*ecdsa.PrivateKey
|
2014-12-08 03:43:33 -08:00
|
|
|
}
|
|
|
|
|
2014-12-12 13:23:42 -08:00
|
|
|
func New() *Whisper {
|
2014-12-08 03:43:33 -08:00
|
|
|
whisper := &Whisper{
|
2015-03-20 16:57:18 -07:00
|
|
|
messages: make(map[common.Hash]*Envelope),
|
2014-12-12 13:23:42 -08:00
|
|
|
filters: filter.New(),
|
2014-12-09 15:03:50 -08:00
|
|
|
expiry: make(map[uint32]*set.SetNonTS),
|
2014-12-08 03:43:33 -08:00
|
|
|
quit: make(chan struct{}),
|
2015-01-14 09:12:18 -08:00
|
|
|
keys: make(map[string]*ecdsa.PrivateKey),
|
2014-12-08 03:43:33 -08:00
|
|
|
}
|
2014-12-12 13:23:42 -08:00
|
|
|
whisper.filters.Start()
|
2014-12-08 03:43:33 -08:00
|
|
|
|
|
|
|
// p2p whisper sub protocol handler
|
|
|
|
whisper.protocol = p2p.Protocol{
|
|
|
|
Name: "shh",
|
2015-03-25 04:08:48 -07:00
|
|
|
Version: uint(whisperVersion),
|
2014-12-08 03:43:33 -08:00
|
|
|
Length: 2,
|
|
|
|
Run: whisper.msgHandler,
|
|
|
|
}
|
|
|
|
|
|
|
|
return whisper
|
|
|
|
}
|
|
|
|
|
2015-03-25 04:08:48 -07:00
|
|
|
func (self *Whisper) Version() uint {
|
|
|
|
return self.protocol.Version
|
|
|
|
}
|
|
|
|
|
2014-12-15 03:01:55 -08:00
|
|
|
func (self *Whisper) Start() {
|
2015-04-07 05:57:04 -07:00
|
|
|
glog.V(logger.Info).Infoln("Whisper started")
|
2014-12-15 03:01:55 -08:00
|
|
|
go self.update()
|
|
|
|
}
|
|
|
|
|
2014-12-08 03:43:33 -08:00
|
|
|
func (self *Whisper) Stop() {
|
|
|
|
close(self.quit)
|
|
|
|
}
|
|
|
|
|
2014-12-09 15:03:50 -08:00
|
|
|
func (self *Whisper) Send(envelope *Envelope) error {
|
|
|
|
return self.add(envelope)
|
2014-12-08 03:43:33 -08:00
|
|
|
}
|
|
|
|
|
2014-12-12 13:23:42 -08:00
|
|
|
func (self *Whisper) NewIdentity() *ecdsa.PrivateKey {
|
|
|
|
key, err := crypto.GenerateKey()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2015-01-14 09:12:18 -08:00
|
|
|
|
|
|
|
self.keys[string(crypto.FromECDSAPub(&key.PublicKey))] = key
|
2014-12-12 13:23:42 -08:00
|
|
|
|
|
|
|
return key
|
|
|
|
}
|
|
|
|
|
2015-01-14 09:12:18 -08:00
|
|
|
func (self *Whisper) HasIdentity(key *ecdsa.PublicKey) bool {
|
|
|
|
return self.keys[string(crypto.FromECDSAPub(key))] != nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *Whisper) GetIdentity(key *ecdsa.PublicKey) *ecdsa.PrivateKey {
|
|
|
|
return self.keys[string(crypto.FromECDSAPub(key))]
|
2014-12-12 13:23:42 -08:00
|
|
|
}
|
|
|
|
|
2015-03-17 06:11:01 -07:00
|
|
|
// func (self *Whisper) RemoveIdentity(key *ecdsa.PublicKey) bool {
|
|
|
|
// k := string(crypto.FromECDSAPub(key))
|
|
|
|
// if _, ok := self.keys[k]; ok {
|
|
|
|
// delete(self.keys, k)
|
|
|
|
// return true
|
|
|
|
// }
|
|
|
|
// return false
|
|
|
|
// }
|
2015-03-16 11:46:46 -07:00
|
|
|
|
2014-12-12 13:23:42 -08:00
|
|
|
func (self *Whisper) Watch(opts Filter) int {
|
|
|
|
return self.filters.Install(filter.Generic{
|
2015-02-05 15:00:59 -08:00
|
|
|
Str1: string(crypto.FromECDSAPub(opts.To)),
|
2014-12-12 13:23:42 -08:00
|
|
|
Str2: string(crypto.FromECDSAPub(opts.From)),
|
2015-04-13 02:16:51 -07:00
|
|
|
Data: NewTopicSet(opts.Topics),
|
2014-12-12 13:23:42 -08:00
|
|
|
Fn: func(data interface{}) {
|
|
|
|
opts.Fn(data.(*Message))
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-02-23 06:43:41 -08:00
|
|
|
func (self *Whisper) Unwatch(id int) {
|
|
|
|
self.filters.Uninstall(id)
|
|
|
|
}
|
|
|
|
|
2015-01-13 04:36:44 -08:00
|
|
|
func (self *Whisper) Messages(id int) (messages []*Message) {
|
2015-01-12 11:36:45 -08:00
|
|
|
filter := self.filters.Get(id)
|
|
|
|
if filter != nil {
|
|
|
|
for _, e := range self.messages {
|
2015-04-14 02:12:47 -07:00
|
|
|
if msg := self.open(e); msg != nil {
|
|
|
|
f := createFilter(msg, e.Topics)
|
2015-01-12 11:36:45 -08:00
|
|
|
if self.filters.Match(filter, f) {
|
2015-01-13 04:36:44 -08:00
|
|
|
messages = append(messages, msg)
|
2015-01-12 11:36:45 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-01-13 04:36:44 -08:00
|
|
|
|
|
|
|
return
|
2015-01-12 11:36:45 -08:00
|
|
|
}
|
|
|
|
|
2014-12-08 04:16:50 -08:00
|
|
|
// Main handler for passing whisper messages to whisper peer objects
|
2014-12-08 03:43:33 -08:00
|
|
|
func (self *Whisper) msgHandler(peer *p2p.Peer, ws p2p.MsgReadWriter) error {
|
|
|
|
wpeer := NewPeer(self, peer, ws)
|
2014-12-09 15:03:50 -08:00
|
|
|
// initialise whisper peer (handshake/status)
|
2014-12-08 03:43:33 -08:00
|
|
|
if err := wpeer.init(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2014-12-08 04:16:50 -08:00
|
|
|
// kick of the main handler for broadcasting/managing envelopes
|
2014-12-08 03:43:33 -08:00
|
|
|
go wpeer.start()
|
2014-12-08 04:16:50 -08:00
|
|
|
defer wpeer.stop()
|
2014-12-08 03:43:33 -08:00
|
|
|
|
2014-12-08 04:16:50 -08:00
|
|
|
// Main *read* loop. Writing is done by the peer it self.
|
2014-12-08 03:43:33 -08:00
|
|
|
for {
|
|
|
|
msg, err := ws.ReadMsg()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-01-13 04:36:44 -08:00
|
|
|
var envelopes []*Envelope
|
|
|
|
if err := msg.Decode(&envelopes); err != nil {
|
2014-12-08 03:43:33 -08:00
|
|
|
peer.Infoln(err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2015-01-13 04:36:44 -08:00
|
|
|
for _, envelope := range envelopes {
|
|
|
|
if err := self.add(envelope); err != nil {
|
|
|
|
// TODO Punish peer here. Invalid envelope.
|
2015-04-04 04:24:01 -07:00
|
|
|
peer.Debugln(err)
|
2015-01-13 04:36:44 -08:00
|
|
|
}
|
|
|
|
wpeer.addKnown(envelope)
|
2014-12-09 15:03:50 -08:00
|
|
|
}
|
2014-12-08 03:43:33 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-08 04:16:50 -08:00
|
|
|
// takes care of adding envelopes to the messages pool. At this moment no sanity checks are being performed.
|
2014-12-09 15:03:50 -08:00
|
|
|
func (self *Whisper) add(envelope *Envelope) error {
|
|
|
|
if !envelope.valid() {
|
2014-12-12 13:23:42 -08:00
|
|
|
return errors.New("invalid pow provided for envelope")
|
2014-12-09 15:03:50 -08:00
|
|
|
}
|
|
|
|
|
2014-12-08 03:43:33 -08:00
|
|
|
self.mmu.Lock()
|
|
|
|
defer self.mmu.Unlock()
|
|
|
|
|
2014-12-09 15:03:50 -08:00
|
|
|
hash := envelope.Hash()
|
|
|
|
self.messages[hash] = envelope
|
2014-12-08 03:43:33 -08:00
|
|
|
if self.expiry[envelope.Expiry] == nil {
|
|
|
|
self.expiry[envelope.Expiry] = set.NewNonTS()
|
|
|
|
}
|
2014-12-09 15:03:50 -08:00
|
|
|
|
|
|
|
if !self.expiry[envelope.Expiry].Has(hash) {
|
|
|
|
self.expiry[envelope.Expiry].Add(hash)
|
2014-12-22 04:23:11 -08:00
|
|
|
go self.postEvent(envelope)
|
2014-12-09 15:03:50 -08:00
|
|
|
}
|
2015-04-07 05:57:04 -07:00
|
|
|
glog.V(logger.Detail).Infof("added whisper envelope %x\n", envelope)
|
2015-01-13 04:36:44 -08:00
|
|
|
|
2014-12-09 15:03:50 -08:00
|
|
|
return nil
|
2014-12-08 03:43:33 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (self *Whisper) update() {
|
|
|
|
expire := time.NewTicker(800 * time.Millisecond)
|
|
|
|
out:
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-expire.C:
|
|
|
|
self.expire()
|
|
|
|
case <-self.quit:
|
|
|
|
break out
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-12-08 04:16:50 -08:00
|
|
|
|
2014-12-08 03:43:33 -08:00
|
|
|
func (self *Whisper) expire() {
|
|
|
|
self.mmu.Lock()
|
|
|
|
defer self.mmu.Unlock()
|
|
|
|
|
2014-12-09 15:03:50 -08:00
|
|
|
now := uint32(time.Now().Unix())
|
2014-12-08 03:43:33 -08:00
|
|
|
for then, hashSet := range self.expiry {
|
|
|
|
if then > now {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
hashSet.Each(func(v interface{}) bool {
|
2015-03-20 16:57:18 -07:00
|
|
|
delete(self.messages, v.(common.Hash))
|
2014-12-08 03:43:33 -08:00
|
|
|
return true
|
|
|
|
})
|
|
|
|
self.expiry[then].Clear()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *Whisper) envelopes() (envelopes []*Envelope) {
|
|
|
|
self.mmu.RLock()
|
|
|
|
defer self.mmu.RUnlock()
|
|
|
|
|
|
|
|
envelopes = make([]*Envelope, len(self.messages))
|
|
|
|
i := 0
|
|
|
|
for _, envelope := range self.messages {
|
|
|
|
envelopes[i] = envelope
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-04-14 02:12:47 -07:00
|
|
|
func (self *Whisper) Protocol() p2p.Protocol {
|
|
|
|
return self.protocol
|
|
|
|
}
|
|
|
|
|
|
|
|
// postEvent opens an envelope with the configured identities and delivers the
|
|
|
|
// message upstream from application processing.
|
2014-12-12 13:23:42 -08:00
|
|
|
func (self *Whisper) postEvent(envelope *Envelope) {
|
2015-04-14 02:12:47 -07:00
|
|
|
if message := self.open(envelope); message != nil {
|
|
|
|
self.filters.Notify(createFilter(message, envelope.Topics), message)
|
2015-01-12 11:36:45 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-14 02:12:47 -07:00
|
|
|
// open tries to decrypt a whisper envelope with all the configured identities,
|
|
|
|
// returning the decrypted message and the key used to achieve it. If not keys
|
|
|
|
// are configured, open will return the payload as if non encrypted.
|
|
|
|
func (self *Whisper) open(envelope *Envelope) *Message {
|
|
|
|
// Short circuit if no identity is set, and assume clear-text
|
|
|
|
if len(self.keys) == 0 {
|
|
|
|
if message, err := envelope.Open(nil); err == nil {
|
|
|
|
return message
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Iterate over the keys and try to decrypt the message
|
2014-12-12 13:23:42 -08:00
|
|
|
for _, key := range self.keys {
|
2015-04-14 02:12:47 -07:00
|
|
|
message, err := envelope.Open(key)
|
|
|
|
if err == nil || err == ecies.ErrInvalidPublicKey {
|
2015-02-10 04:20:06 -08:00
|
|
|
message.To = &key.PublicKey
|
2015-04-14 02:12:47 -07:00
|
|
|
return message
|
2014-12-12 13:23:42 -08:00
|
|
|
}
|
|
|
|
}
|
2015-04-14 02:12:47 -07:00
|
|
|
// Failed to decrypt, don't return anything
|
|
|
|
return nil
|
2014-12-08 03:43:33 -08:00
|
|
|
}
|
2015-01-12 11:36:45 -08:00
|
|
|
|
2015-04-14 02:12:47 -07:00
|
|
|
// createFilter creates a message filter to check against installed handlers.
|
|
|
|
func createFilter(message *Message, topics []Topic) filter.Filter {
|
2015-01-12 11:36:45 -08:00
|
|
|
return filter.Generic{
|
2015-04-14 02:12:47 -07:00
|
|
|
Str1: string(crypto.FromECDSAPub(message.To)),
|
|
|
|
Str2: string(crypto.FromECDSAPub(message.Recover())),
|
2015-04-13 02:16:51 -07:00
|
|
|
Data: NewTopicSet(topics),
|
2015-01-12 11:36:45 -08:00
|
|
|
}
|
|
|
|
}
|