mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
whisper: refactoring (documenting mostly)
This commit is contained in:
parent
3b57070408
commit
b6b8488390
6 changed files with 163 additions and 157 deletions
|
|
@ -526,7 +526,7 @@ func messageLoop() {
|
|||
messages := f.Retrieve()
|
||||
for _, msg := range messages {
|
||||
if *fileExMode || len(msg.Payload) > 2048 {
|
||||
saveMessageInFile(msg)
|
||||
writeMessageToFile(*argSaveDir, msg)
|
||||
} else {
|
||||
printMessageInfo(msg)
|
||||
}
|
||||
|
|
@ -553,7 +553,7 @@ func printMessageInfo(msg *whisper.ReceivedMessage) {
|
|||
}
|
||||
}
|
||||
|
||||
func saveMessageInFile(msg *whisper.ReceivedMessage) {
|
||||
func writeMessageToFile(dir string, msg *whisper.ReceivedMessage) {
|
||||
timestamp := fmt.Sprintf("%d", msg.Sent)
|
||||
name := fmt.Sprintf("%x", msg.EnvelopeHash)
|
||||
|
||||
|
|
@ -565,8 +565,8 @@ func saveMessageInFile(msg *whisper.ReceivedMessage) {
|
|||
if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) {
|
||||
// message from myself: don't save, only report
|
||||
fmt.Printf("\n%s <%x>: message received: '%s'\n", timestamp, address, name)
|
||||
} else if len(*argSaveDir) > 0 {
|
||||
fullpath := filepath.Join(*argSaveDir, name)
|
||||
} else if len(dir) > 0 {
|
||||
fullpath := filepath.Join(dir, name)
|
||||
err := ioutil.WriteFile(fullpath, msg.Payload, 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err)
|
||||
|
|
|
|||
|
|
@ -24,11 +24,10 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
)
|
||||
|
||||
var whisperOffLineErr = errors.New("whisper is offline")
|
||||
var whisperOfflineErr = errors.New("whisper is offline")
|
||||
|
||||
// PublicWhisperAPI provides the whisper RPC service.
|
||||
type PublicWhisperAPI struct {
|
||||
|
|
@ -43,7 +42,7 @@ func NewPublicWhisperAPI(w *Whisper) *PublicWhisperAPI {
|
|||
// Start starts the Whisper worker threads.
|
||||
func (api *PublicWhisperAPI) Start() error {
|
||||
if api.whisper == nil {
|
||||
return whisperOffLineErr
|
||||
return whisperOfflineErr
|
||||
}
|
||||
return api.whisper.Start(nil)
|
||||
}
|
||||
|
|
@ -51,7 +50,7 @@ func (api *PublicWhisperAPI) Start() error {
|
|||
// Stop stops the Whisper worker threads.
|
||||
func (api *PublicWhisperAPI) Stop() error {
|
||||
if api.whisper == nil {
|
||||
return whisperOffLineErr
|
||||
return whisperOfflineErr
|
||||
}
|
||||
return api.whisper.Stop()
|
||||
}
|
||||
|
|
@ -59,29 +58,31 @@ func (api *PublicWhisperAPI) Stop() error {
|
|||
// Version returns the Whisper version this node offers.
|
||||
func (api *PublicWhisperAPI) Version() (hexutil.Uint, error) {
|
||||
if api.whisper == nil {
|
||||
return 0, whisperOffLineErr
|
||||
return 0, whisperOfflineErr
|
||||
}
|
||||
return hexutil.Uint(api.whisper.Version()), nil
|
||||
}
|
||||
|
||||
// Stats returns the Whisper statistics for diagnostics.
|
||||
// Info returns the Whisper statistics for diagnostics.
|
||||
func (api *PublicWhisperAPI) Info() (string, error) {
|
||||
if api.whisper == nil {
|
||||
return "", whisperOffLineErr
|
||||
return "", whisperOfflineErr
|
||||
}
|
||||
return api.whisper.Stats(), nil
|
||||
}
|
||||
|
||||
// SetMaxMessageLength sets the maximal message length allowed by this node
|
||||
func (api *PublicWhisperAPI) SetMaxMessageLength(val int) error {
|
||||
if api.whisper == nil {
|
||||
return whisperOffLineErr
|
||||
return whisperOfflineErr
|
||||
}
|
||||
return api.whisper.SetMaxMessageLength(val)
|
||||
}
|
||||
|
||||
// SetMinimumPoW sets the minimal PoW required by this node
|
||||
func (api *PublicWhisperAPI) SetMinimumPoW(val float64) error {
|
||||
if api.whisper == nil {
|
||||
return whisperOffLineErr
|
||||
return whisperOfflineErr
|
||||
}
|
||||
return api.whisper.SetMinimumPoW(val)
|
||||
}
|
||||
|
|
@ -90,71 +91,69 @@ func (api *PublicWhisperAPI) SetMinimumPoW(val float64) error {
|
|||
// to send historic (expired) messages.
|
||||
func (api *PublicWhisperAPI) AllowP2PMessagesFromPeer(enode string) error {
|
||||
if api.whisper == nil {
|
||||
return whisperOffLineErr
|
||||
return whisperOfflineErr
|
||||
}
|
||||
n, err := discover.ParseNode(enode)
|
||||
if err != nil {
|
||||
info := "Failed to parse enode of trusted peer: " + err.Error()
|
||||
log.Error(info)
|
||||
return errors.New(info)
|
||||
return errors.New("failed to parse enode of trusted peer: " + err.Error())
|
||||
}
|
||||
return api.whisper.AllowP2PMessagesFromPeer(n.ID[:])
|
||||
}
|
||||
|
||||
// RequestHistoricMessages requests the peer to deliver the old (expired) messages.
|
||||
// data contains parameters (time frame, payment details, etc.), required
|
||||
// by the remote email-like server. Whisper is not aware about the data format,
|
||||
// it will just forward the raw data to the server.
|
||||
//func (api *PublicWhisperAPI) RequestHistoricMessages(peerID hexutil.Bytes, data hexutil.Bytes) error {
|
||||
// if api.whisper == nil {
|
||||
// return whisperOffLineErr
|
||||
// }
|
||||
// return api.whisper.RequestHistoricMessages(peerID, data)
|
||||
//}
|
||||
|
||||
// HasIdentity checks if the whisper node is configured with the private key
|
||||
// HasKeyPair checks if the whisper node is configured with the private key
|
||||
// of the specified public pair.
|
||||
func (api *PublicWhisperAPI) HasKeyPair(id string) (bool, error) {
|
||||
if api.whisper == nil {
|
||||
return false, whisperOffLineErr
|
||||
return false, whisperOfflineErr
|
||||
}
|
||||
return api.whisper.HasKeyPair(id), nil
|
||||
}
|
||||
|
||||
// DeleteIdentity deletes the specifies key if it exists.
|
||||
// DeleteKeyPair deletes the specifies key if it exists.
|
||||
func (api *PublicWhisperAPI) DeleteKeyPair(id string) (bool, error) {
|
||||
if api.whisper == nil {
|
||||
return false, whisperOffLineErr
|
||||
return false, whisperOfflineErr
|
||||
}
|
||||
success := api.whisper.DeleteKeyPair(id)
|
||||
return success, nil
|
||||
return api.whisper.DeleteKeyPair(id), nil
|
||||
}
|
||||
|
||||
// NewKeyPair generates a new cryptographic identity for the client, and injects
|
||||
// it into the known identities for message decryption.
|
||||
func (api *PublicWhisperAPI) NewKeyPair() (string, error) {
|
||||
if api.whisper == nil {
|
||||
return "", whisperOffLineErr
|
||||
return "", whisperOfflineErr
|
||||
}
|
||||
return api.whisper.NewKeyPair()
|
||||
}
|
||||
|
||||
// GetPublicKey returns the public key for identity id
|
||||
func (api *PublicWhisperAPI) GetPublicKey(id string) (string, error) {
|
||||
func (api *PublicWhisperAPI) GetPublicKey(id string) (hexutil.Bytes, error) {
|
||||
if api.whisper == nil {
|
||||
return "", whisperOffLineErr
|
||||
return nil, whisperOfflineErr
|
||||
}
|
||||
key, err := api.whisper.GetPrivateKey(id)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
return common.ToHex(crypto.FromECDSAPub(&key.PublicKey)), nil
|
||||
return crypto.FromECDSAPub(&key.PublicKey), nil
|
||||
}
|
||||
|
||||
// todo: delete is tests pass
|
||||
//func (api *PublicWhisperAPI) GetPublicKey(id string) (string, error) {
|
||||
// if api.whisper == nil {
|
||||
// return "", whisperOffLineErr
|
||||
// }
|
||||
// key, err := api.whisper.GetPrivateKey(id)
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
// return common.ToHex(crypto.FromECDSAPub(&key.PublicKey)), nil
|
||||
//}
|
||||
|
||||
// GetPrivateKey returns the private key for identity id
|
||||
func (api *PublicWhisperAPI) GetPrivateKey(id string) (string, error) {
|
||||
if api.whisper == nil {
|
||||
return "", whisperOffLineErr
|
||||
return "", whisperOfflineErr
|
||||
}
|
||||
key, err := api.whisper.GetPrivateKey(id)
|
||||
if err != nil {
|
||||
|
|
@ -163,57 +162,71 @@ func (api *PublicWhisperAPI) GetPrivateKey(id string) (string, error) {
|
|||
return common.ToHex(crypto.FromECDSA(key)), nil
|
||||
}
|
||||
|
||||
// GenerateSymKey generates a random symmetric key and stores it under id,
|
||||
// GenerateSymmetricKey generates a random symmetric key and stores it under id,
|
||||
// which is then returned. Will be used in the future for session key exchange.
|
||||
func (api *PublicWhisperAPI) GenerateSymmetricKey() (string, error) {
|
||||
if api.whisper == nil {
|
||||
return "", whisperOffLineErr
|
||||
return "", whisperOfflineErr
|
||||
}
|
||||
return api.whisper.GenerateSymKey()
|
||||
}
|
||||
|
||||
// AddSymKeyDirect stores the key, and returns its id.
|
||||
// AddSymmetricKeyDirect stores the key, and returns its id.
|
||||
func (api *PublicWhisperAPI) AddSymmetricKeyDirect(key hexutil.Bytes) (string, error) {
|
||||
if api.whisper == nil {
|
||||
return "", whisperOffLineErr
|
||||
return "", whisperOfflineErr
|
||||
}
|
||||
return api.whisper.AddSymKeyDirect(key)
|
||||
}
|
||||
|
||||
// AddSymKeyFromPassword generates the key from password, stores it, and returns its id.
|
||||
// AddSymmetricKeyFromPassword generates the key from password, stores it, and returns its id.
|
||||
func (api *PublicWhisperAPI) AddSymmetricKeyFromPassword(password string) (string, error) {
|
||||
if api.whisper == nil {
|
||||
return "", whisperOffLineErr
|
||||
return "", whisperOfflineErr
|
||||
}
|
||||
return api.whisper.AddSymKeyFromPassword(password)
|
||||
}
|
||||
|
||||
// HasSymKey returns true if there is a key associated with the given id.
|
||||
// HasSymmetricKey returns true if there is a key associated with the given id.
|
||||
// Otherwise returns false.
|
||||
func (api *PublicWhisperAPI) HasSymmetricKey(id string) (bool, error) {
|
||||
if api.whisper == nil {
|
||||
return false, whisperOffLineErr
|
||||
return false, whisperOfflineErr
|
||||
}
|
||||
res := api.whisper.HasSymKey(id)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (api *PublicWhisperAPI) GetSymmetricKey(name string) (string, error) {
|
||||
// GetSymmetricKey returns the symmetric key associated with the given id.
|
||||
func (api *PublicWhisperAPI) GetSymmetricKey(name string) (hexutil.Bytes, error) {
|
||||
if api.whisper == nil {
|
||||
return "", whisperOffLineErr
|
||||
return nil, whisperOfflineErr
|
||||
}
|
||||
|
||||
b, err := api.whisper.GetSymKey(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
return fmt.Sprintf("%x", b), nil
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// DeleteSymKey deletes the key associated with the name string if it exists.
|
||||
// todo: delete if tests pass
|
||||
//func (api *PublicWhisperAPI) GetSymmetricKey(name string) (string, error) {
|
||||
// if api.whisper == nil {
|
||||
// return "", whisperOffLineErr
|
||||
// }
|
||||
//
|
||||
// b, err := api.whisper.GetSymKey(name)
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
// //return fmt.Sprintf("%x", b), nil // todo: delete if tests pass
|
||||
// return common.ToHex(b), nil
|
||||
//}
|
||||
|
||||
// DeleteSymmetricKey deletes the key associated with the name string if it exists.
|
||||
func (api *PublicWhisperAPI) DeleteSymmetricKey(name string) (bool, error) {
|
||||
if api.whisper == nil {
|
||||
return false, whisperOffLineErr
|
||||
return false, whisperOfflineErr
|
||||
}
|
||||
res := api.whisper.DeleteSymKey(name)
|
||||
return res, nil
|
||||
|
|
@ -223,7 +236,7 @@ func (api *PublicWhisperAPI) DeleteSymmetricKey(name string) (bool, error) {
|
|||
// Returns the ID of the newly created filter.
|
||||
func (api *PublicWhisperAPI) Subscribe(args WhisperFilterArgs) (string, error) {
|
||||
if api.whisper == nil {
|
||||
return "", whisperOffLineErr
|
||||
return "", whisperOfflineErr
|
||||
}
|
||||
|
||||
filter := Filter{
|
||||
|
|
@ -233,61 +246,44 @@ func (api *PublicWhisperAPI) Subscribe(args WhisperFilterArgs) (string, error) {
|
|||
AllowP2P: args.AllowP2P,
|
||||
}
|
||||
|
||||
var err error
|
||||
for i, bt := range args.Topics {
|
||||
if len(bt) == 0 || len(bt) > 4 {
|
||||
info := fmt.Sprintf("Subscribe: topic %d has wrong size: %d", i, len(bt))
|
||||
log.Error(info)
|
||||
return "", errors.New(info)
|
||||
return "", errors.New(fmt.Sprintf("subscribe: topic %d has wrong size: %d", i, len(bt)))
|
||||
}
|
||||
filter.Topics = append(filter.Topics, bt)
|
||||
}
|
||||
|
||||
err := ValidateKeyID(args.Key)
|
||||
if err != nil {
|
||||
info := "Subscribe: " + err.Error()
|
||||
log.Error(info)
|
||||
return "", errors.New(info)
|
||||
if err = ValidateKeyID(args.Key); err != nil {
|
||||
return "", errors.New("subscribe: " + err.Error())
|
||||
}
|
||||
|
||||
if len(args.SignedWith) > 0 {
|
||||
if !ValidatePublicKey(filter.Src) {
|
||||
info := "Subscribe: Invalid 'SignedWith' field"
|
||||
log.Error(info)
|
||||
return "", errors.New(info)
|
||||
return "", errors.New("subscribe: invalid 'SignedWith' field")
|
||||
}
|
||||
}
|
||||
|
||||
if args.Symmetric {
|
||||
if len(args.Topics) == 0 {
|
||||
info := "Subscribe: at least one topic must be specified with symmetric encryption"
|
||||
log.Error(info)
|
||||
return "", errors.New(info)
|
||||
return "", errors.New("subscribe: at least one topic must be specified with symmetric encryption")
|
||||
}
|
||||
symKey, err := api.whisper.GetSymKey(args.Key)
|
||||
if err != nil {
|
||||
info := "Subscribe: invalid key ID"
|
||||
log.Error(info)
|
||||
return "", errors.New(info)
|
||||
return "", errors.New("subscribe: invalid key ID")
|
||||
}
|
||||
if !validateSymmetricKey(symKey) {
|
||||
info := "Subscribe: retrieved key is invalid"
|
||||
log.Error(info)
|
||||
return "", errors.New(info)
|
||||
return "", errors.New("subscribe: retrieved key is invalid")
|
||||
}
|
||||
|
||||
filter.KeySym = symKey
|
||||
filter.SymKeyHash = crypto.Keccak256Hash(filter.KeySym)
|
||||
} else {
|
||||
filter.KeyAsym, err = api.whisper.GetPrivateKey(args.Key)
|
||||
if err != nil {
|
||||
info := "Subscribe: invalid key ID"
|
||||
log.Error(info)
|
||||
return "", errors.New(info)
|
||||
return "", errors.New("subscribe: invalid key ID")
|
||||
}
|
||||
if filter.KeyAsym == nil {
|
||||
info := "Subscribe: non-existent identity provided"
|
||||
log.Error(info)
|
||||
return "", errors.New(info)
|
||||
return "", errors.New("subscribe: non-existent identity provided")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -299,7 +295,7 @@ func (api *PublicWhisperAPI) Unsubscribe(id string) {
|
|||
api.whisper.Unsubscribe(id)
|
||||
}
|
||||
|
||||
// GetFilterChanges retrieves all the new messages matched by a filter since the last retrieval.
|
||||
// GetSubscriptionMessages retrieves all the new messages matched by a filter since the last retrieval.
|
||||
func (api *PublicWhisperAPI) GetSubscriptionMessages(filterId string) []*WhisperMessage {
|
||||
f := api.whisper.GetFilter(filterId)
|
||||
if f != nil {
|
||||
|
|
@ -309,7 +305,8 @@ func (api *PublicWhisperAPI) GetSubscriptionMessages(filterId string) []*Whisper
|
|||
return toWhisperMessages(nil)
|
||||
}
|
||||
|
||||
// GetMessages retrieves all the known messages that match a specific filter.
|
||||
// GetMessages retrieves all the floating messages that match a specific filter.
|
||||
// It is likely to be called once per session, right after Subscribe call.
|
||||
func (api *PublicWhisperAPI) GetMessages(filterId string) []*WhisperMessage {
|
||||
all := api.whisper.Messages(filterId)
|
||||
return toWhisperMessages(all)
|
||||
|
|
@ -327,7 +324,7 @@ func toWhisperMessages(messages []*ReceivedMessage) []*WhisperMessage {
|
|||
// Post creates a whisper message and injects it into the network for distribution.
|
||||
func (api *PublicWhisperAPI) Post(args PostArgs) error {
|
||||
if api.whisper == nil {
|
||||
return whisperOffLineErr
|
||||
return whisperOfflineErr
|
||||
}
|
||||
|
||||
var err error
|
||||
|
|
@ -340,96 +337,69 @@ func (api *PublicWhisperAPI) Post(args PostArgs) error {
|
|||
}
|
||||
|
||||
if len(args.Key) == 0 {
|
||||
info := "Post: key is missing"
|
||||
log.Error(info)
|
||||
return errors.New(info)
|
||||
return errors.New("post: key is missing")
|
||||
}
|
||||
|
||||
if len(args.SignWith) > 0 {
|
||||
params.Src, err = api.whisper.GetPrivateKey(args.SignWith)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
return err
|
||||
}
|
||||
if params.Src == nil {
|
||||
info := "Post: empty identity"
|
||||
log.Error(info)
|
||||
return errors.New(info)
|
||||
return errors.New("post: empty identity")
|
||||
}
|
||||
}
|
||||
|
||||
if len(args.Topic) == TopicLength {
|
||||
params.Topic = BytesToTopic(args.Topic)
|
||||
} else if len(args.Topic) != 0 {
|
||||
info := fmt.Sprintf("Post: wrong topic size %d", len(args.Topic))
|
||||
log.Error(info)
|
||||
return errors.New(info)
|
||||
return errors.New(fmt.Sprintf("post: wrong topic size %d", len(args.Topic)))
|
||||
}
|
||||
|
||||
if args.Type == "sym" {
|
||||
err = ValidateKeyID(args.Key)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
if err = ValidateKeyID(args.Key); err != nil {
|
||||
return err
|
||||
}
|
||||
params.KeySym, err = api.whisper.GetSymKey(args.Key)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
return err
|
||||
}
|
||||
if !validateSymmetricKey(params.KeySym) {
|
||||
info := "Post: key for symmetric encryption is invalid"
|
||||
log.Error(info)
|
||||
return errors.New(info)
|
||||
return errors.New("post: key for symmetric encryption is invalid")
|
||||
}
|
||||
if len(params.Topic) == 0 {
|
||||
info := "Post: topic is missing for symmetric encryption"
|
||||
log.Error(info)
|
||||
return errors.New(info)
|
||||
return errors.New("post: topic is missing for symmetric encryption")
|
||||
}
|
||||
} else if args.Type == "asym" {
|
||||
params.Dst = crypto.ToECDSAPub(common.FromHex(args.Key))
|
||||
if !ValidatePublicKey(params.Dst) {
|
||||
info := "Post: public key for asymmetric encryption is invalid"
|
||||
log.Error(info)
|
||||
return errors.New(info)
|
||||
return errors.New("post: public key for asymmetric encryption is invalid")
|
||||
}
|
||||
} else {
|
||||
info := "Post: wrong type (sym/asym)"
|
||||
log.Error(info)
|
||||
return errors.New(info)
|
||||
return errors.New("post: wrong type (sym/asym)")
|
||||
}
|
||||
|
||||
// encrypt and send
|
||||
message := NewSentMessage(¶ms)
|
||||
if message == nil {
|
||||
info := "Post: failed create new message, probably due to failed rand function (OS level)"
|
||||
log.Error(info)
|
||||
return errors.New(info)
|
||||
return errors.New("post: failed create new message, probably due to failed rand function (OS level)")
|
||||
}
|
||||
envelope, err := message.Wrap(¶ms)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
return err
|
||||
}
|
||||
if envelope.size() > api.whisper.maxMsgLength {
|
||||
info := "Post: message is too big"
|
||||
log.Error(info)
|
||||
return errors.New(info)
|
||||
return errors.New("post: message is too big")
|
||||
}
|
||||
|
||||
if len(args.TargetPeer) != 0 {
|
||||
n, err := discover.ParseNode(args.TargetPeer)
|
||||
if err != nil {
|
||||
info := "Post: failed to parse enode of target peer: " + err.Error()
|
||||
log.Error(info)
|
||||
return errors.New(info)
|
||||
return errors.New("post: failed to parse enode of target peer: " + err.Error())
|
||||
}
|
||||
return api.whisper.SendP2PMessage(n.ID[:], envelope)
|
||||
} else if args.PowTarget < api.whisper.minPoW {
|
||||
info := "Post: target PoW is less than minimum PoW, the message can not be sent"
|
||||
log.Error(info)
|
||||
return errors.New(info)
|
||||
return errors.New("post: target PoW is less than minimum PoW, the message can not be sent")
|
||||
}
|
||||
|
||||
return api.whisper.Send(envelope)
|
||||
|
|
@ -473,12 +443,13 @@ func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
if obj.Type == "sym" {
|
||||
switch obj.Type {
|
||||
case "sym":
|
||||
args.Symmetric = true
|
||||
} else if obj.Type == "asym" {
|
||||
case "asym":
|
||||
args.Symmetric = false
|
||||
} else {
|
||||
return fmt.Errorf("Wrong type (sym/asym")
|
||||
default:
|
||||
return errors.New("wrong type (sym/asym")
|
||||
}
|
||||
|
||||
args.Key = obj.Key
|
||||
|
|
|
|||
|
|
@ -94,11 +94,11 @@ func (fs *Filters) NotifyWatchers(env *Envelope, p2pMessage bool) {
|
|||
fs.mutex.RLock()
|
||||
defer fs.mutex.RUnlock()
|
||||
|
||||
j := -1
|
||||
i := -1 // only used for logging info
|
||||
for _, watcher := range fs.watchers {
|
||||
j++
|
||||
i++
|
||||
if p2pMessage && !watcher.AllowP2P {
|
||||
log.Trace(fmt.Sprintf("msg [%x], filter [%d]: p2p messages are not allowed", env.Hash(), j))
|
||||
log.Trace(fmt.Sprintf("msg [%x], filter [%d]: p2p messages are not allowed", env.Hash(), i))
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -110,10 +110,10 @@ func (fs *Filters) NotifyWatchers(env *Envelope, p2pMessage bool) {
|
|||
if match {
|
||||
msg = env.Open(watcher)
|
||||
if msg == nil {
|
||||
log.Trace(fmt.Sprintf("msg [%x], filter [%d]: failed to open", env.Hash(), j))
|
||||
log.Trace(fmt.Sprintf("msg [%x], filter [%d]: failed to open", env.Hash(), i))
|
||||
}
|
||||
} else {
|
||||
log.Trace(fmt.Sprintf("msg [%x], filter [%d]: does not match", env.Hash(), j))
|
||||
log.Trace(fmt.Sprintf("msg [%x], filter [%d]: does not match", env.Hash(), i))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -203,16 +203,16 @@ func (f *Filter) MatchTopic(topic TopicType) bool {
|
|||
}
|
||||
|
||||
for _, bt := range f.Topics {
|
||||
if MatchSingleTopic(topic, bt) {
|
||||
if matchSingleTopic(topic, bt) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func MatchSingleTopic(topic TopicType, bt []byte) bool {
|
||||
func matchSingleTopic(topic TopicType, bt []byte) bool {
|
||||
if len(bt) > 4 {
|
||||
bt = bt[0:4]
|
||||
bt = bt[:4]
|
||||
}
|
||||
|
||||
for j, b := range bt {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import (
|
|||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
mrand "math/rand"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
|
@ -132,7 +131,7 @@ func (msg *SentMessage) appendPadding(params *MessageParams) error {
|
|||
panic("please fix the padding algorithm before releasing new version")
|
||||
}
|
||||
buf := make([]byte, padSize)
|
||||
_, err := mrand.Read(buf[1:])
|
||||
_, err := crand.Read(buf[1:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,8 +119,10 @@ func initialize(t *testing.T) {
|
|||
topics := make([]TopicType, 0)
|
||||
topics = append(topics, sharedTopic)
|
||||
f := Filter{KeySym: sharedKey}
|
||||
f.Topics = make([][]byte, 1)
|
||||
f.Topics[0] = topics[0][:]
|
||||
f.Topics = [][]byte{topics[0][:]}
|
||||
// todo: delete if pass
|
||||
//f.Topics = make([][]byte, 1)
|
||||
//f.Topics[0] = topics[0][:]
|
||||
node.filerId, err = node.shh.Watch(&f)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to install the filter: %s.", err)
|
||||
|
|
|
|||
|
|
@ -46,12 +46,12 @@ type Statistics struct {
|
|||
// Whisper represents a dark communication interface through the Ethereum
|
||||
// network, using its very own P2P communication layer.
|
||||
type Whisper struct {
|
||||
protocol p2p.Protocol
|
||||
filters *Filters
|
||||
protocol p2p.Protocol // Protocol description and parameters
|
||||
filters *Filters // Message filters installed with Subscribe function
|
||||
|
||||
privateKeys map[string]*ecdsa.PrivateKey
|
||||
symKeys map[string][]byte
|
||||
keyMu sync.RWMutex
|
||||
privateKeys map[string]*ecdsa.PrivateKey // Private key storage
|
||||
symKeys map[string][]byte // Symmetric key storage
|
||||
keyMu sync.RWMutex // Mutex associated with key storages
|
||||
|
||||
envelopes map[common.Hash]*Envelope // Pool of envelopes currently tracked by this node
|
||||
expirations map[uint32]*set.SetNonTS // Message expiration pool
|
||||
|
|
@ -60,17 +60,17 @@ type Whisper struct {
|
|||
peers map[*Peer]struct{} // Set of currently active peers
|
||||
peerMu sync.RWMutex // Mutex to sync the active peer set
|
||||
|
||||
mailServer MailServer
|
||||
messageQueue chan *Envelope // Message queue for normal whisper messages
|
||||
p2pMsgQueue chan *Envelope // Message queue for peer-to-peer messages (not to be forwarded any further)
|
||||
quit chan struct{} // Channel used for graceful exit
|
||||
|
||||
messageQueue chan *Envelope
|
||||
p2pMsgQueue chan *Envelope
|
||||
quit chan struct{}
|
||||
minPoW float64 // Minimal PoW required by the whisper node
|
||||
maxMsgLength int // Maximal message length allowed by the whisper node
|
||||
overflow bool // Indicator of message queue overflow
|
||||
|
||||
stats Statistics
|
||||
stats Statistics // Statistics of whisper node
|
||||
|
||||
minPoW float64
|
||||
maxMsgLength int
|
||||
overflow bool
|
||||
mailServer MailServer // MailServer interface
|
||||
}
|
||||
|
||||
// New creates a Whisper client ready to communicate through the Ethereum P2P network.
|
||||
|
|
@ -113,6 +113,8 @@ func (w *Whisper) APIs() []rpc.API {
|
|||
}
|
||||
}
|
||||
|
||||
// RegisterServer registers MailServer interface.
|
||||
// MailServer will process all the incoming messages with p2pRequestCode.
|
||||
func (w *Whisper) RegisterServer(server MailServer) {
|
||||
w.mailServer = server
|
||||
}
|
||||
|
|
@ -127,6 +129,7 @@ func (w *Whisper) Version() uint {
|
|||
return w.protocol.Version
|
||||
}
|
||||
|
||||
// SetMaxMessageLength sets the maximal message length allowed by this node
|
||||
func (w *Whisper) SetMaxMessageLength(val int) error {
|
||||
if val <= 0 {
|
||||
return fmt.Errorf("Invalid message length: %d", val)
|
||||
|
|
@ -135,6 +138,7 @@ func (w *Whisper) SetMaxMessageLength(val int) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// SetMinimumPoW sets the minimal PoW required by this node
|
||||
func (w *Whisper) SetMinimumPoW(val float64) error {
|
||||
if val <= 0.0 {
|
||||
return fmt.Errorf("Invalid PoW: %f", val)
|
||||
|
|
@ -166,6 +170,11 @@ func (w *Whisper) AllowP2PMessagesFromPeer(peerID []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// RequestHistoricMessages sends a message with p2pRequestCode to a specific peer,
|
||||
// which is known to implement MailServer interface, and is supposed to process this
|
||||
// request and respond with a number of peer-to-peer messages (possibly expired),
|
||||
// which are not supposed to be forwarded any further.
|
||||
// The whisper protocol is agnostic of the format and contents of envelope.
|
||||
func (w *Whisper) RequestHistoricMessages(peerID []byte, envelope *Envelope) error {
|
||||
p, err := w.getPeer(peerID)
|
||||
if err != nil {
|
||||
|
|
@ -175,14 +184,17 @@ func (w *Whisper) RequestHistoricMessages(peerID []byte, envelope *Envelope) err
|
|||
return p2p.Send(p.ws, p2pRequestCode, envelope)
|
||||
}
|
||||
|
||||
// SendP2PMessage sends a peer-to-peer message to a specific peer.
|
||||
func (w *Whisper) SendP2PMessage(peerID []byte, envelope *Envelope) error {
|
||||
p, err := w.getPeer(peerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p2p.Send(p.ws, p2pCode, envelope)
|
||||
//return p2p.Send(p.ws, p2pCode, envelope) // todo: delete if tests pass
|
||||
return w.SendP2PDirect(p, envelope)
|
||||
}
|
||||
|
||||
// SendP2PDirect sends a peer-to-peer message to a specific peer.
|
||||
func (w *Whisper) SendP2PDirect(peer *Peer, envelope *Envelope) error {
|
||||
return p2p.Send(peer.ws, p2pCode, envelope)
|
||||
}
|
||||
|
|
@ -247,6 +259,8 @@ func (w *Whisper) GetPrivateKey(id string) (*ecdsa.PrivateKey, error) {
|
|||
return key, nil
|
||||
}
|
||||
|
||||
// GenerateSymKey generates a random symmetric key and stores it under id,
|
||||
// which is then returned. Will be used in the future for session key exchange.
|
||||
func (w *Whisper) GenerateSymKey() (string, error) {
|
||||
const size = aesKeyLength * 2
|
||||
buf := make([]byte, size)
|
||||
|
|
@ -281,6 +295,7 @@ func (w *Whisper) GenerateSymKey() (string, error) {
|
|||
return id, nil
|
||||
}
|
||||
|
||||
// AddSymKeyDirect stores the key, and returns its id.
|
||||
func (w *Whisper) AddSymKeyDirect(key []byte) (string, error) {
|
||||
if len(key) != aesKeyLength {
|
||||
return "", fmt.Errorf("Wrong key size: %d", len(key))
|
||||
|
|
@ -301,6 +316,7 @@ func (w *Whisper) AddSymKeyDirect(key []byte) (string, error) {
|
|||
return id, nil
|
||||
}
|
||||
|
||||
// AddSymKeyFromPassword generates the key from password, stores it, and returns its id.
|
||||
func (w *Whisper) AddSymKeyFromPassword(password string) (string, error) {
|
||||
id, err := GenerateRandomID()
|
||||
if err != nil {
|
||||
|
|
@ -326,12 +342,15 @@ func (w *Whisper) AddSymKeyFromPassword(password string) (string, error) {
|
|||
return id, nil
|
||||
}
|
||||
|
||||
// HasSymKey returns true if there is a key associated with the given id.
|
||||
// Otherwise returns false.
|
||||
func (w *Whisper) HasSymKey(id string) bool {
|
||||
w.keyMu.RLock()
|
||||
defer w.keyMu.RUnlock()
|
||||
return w.symKeys[id] != nil
|
||||
}
|
||||
|
||||
// DeleteSymKey deletes the key associated with the name string if it exists.
|
||||
func (w *Whisper) DeleteSymKey(id string) bool {
|
||||
w.keyMu.Lock()
|
||||
defer w.keyMu.Unlock()
|
||||
|
|
@ -342,6 +361,7 @@ func (w *Whisper) DeleteSymKey(id string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// GetSymKey returns the symmetric key associated with the given id.
|
||||
func (w *Whisper) GetSymKey(id string) ([]byte, error) {
|
||||
w.keyMu.RLock()
|
||||
defer w.keyMu.RUnlock()
|
||||
|
|
@ -351,12 +371,13 @@ func (w *Whisper) GetSymKey(id string) ([]byte, error) {
|
|||
return nil, fmt.Errorf("non-existent key ID")
|
||||
}
|
||||
|
||||
// Watch installs a new message handler to run in case a matching packet arrives
|
||||
// from the whisper network.
|
||||
// Watch installs a new message handler used for filtering, decrypting
|
||||
// and subsequent storing of incoming messages.
|
||||
func (w *Whisper) Watch(f *Filter) (string, error) {
|
||||
return w.filters.Install(f)
|
||||
}
|
||||
|
||||
// GetFilter returns the filter by id.
|
||||
func (w *Whisper) GetFilter(id string) *Filter {
|
||||
return w.filters.Get(id)
|
||||
}
|
||||
|
|
@ -662,6 +683,7 @@ func (w *Whisper) expire() {
|
|||
}
|
||||
}
|
||||
|
||||
// Stats returns the whisper node statistics.
|
||||
func (w *Whisper) Stats() string {
|
||||
result := fmt.Sprintf("Memory usage: %d bytes. Average messages cleared per expiry cycle: %d. Total messages cleared: %d.",
|
||||
w.stats.memoryUsed, w.stats.totalMessagesCleared/w.stats.cycles, w.stats.totalMessagesCleared)
|
||||
|
|
@ -669,6 +691,9 @@ func (w *Whisper) Stats() string {
|
|||
result += fmt.Sprintf(" Latest expiry cycle cleared %d messages (%d bytes).",
|
||||
w.stats.messagesCleared, w.stats.memoryCleared)
|
||||
}
|
||||
if w.overflow {
|
||||
result += " Message queue state: overflow."
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
@ -702,6 +727,7 @@ func (w *Whisper) Messages(id string) []*ReceivedMessage {
|
|||
return result
|
||||
}
|
||||
|
||||
// isEnvelopeCached checks if envelope with specific hash has already been received and cached.
|
||||
func (w *Whisper) isEnvelopeCached(hash common.Hash) bool {
|
||||
w.poolMu.Lock()
|
||||
defer w.poolMu.Unlock()
|
||||
|
|
@ -710,6 +736,7 @@ func (w *Whisper) isEnvelopeCached(hash common.Hash) bool {
|
|||
return exist
|
||||
}
|
||||
|
||||
// reset resets the node's statistics after each expiry cycle.
|
||||
func (s *Statistics) reset() {
|
||||
s.cycles++
|
||||
s.totalMessagesCleared += s.messagesCleared
|
||||
|
|
@ -718,6 +745,7 @@ func (s *Statistics) reset() {
|
|||
s.messagesCleared = 0
|
||||
}
|
||||
|
||||
// ValidateKeyID checks the format of key id.
|
||||
func ValidateKeyID(id string) error {
|
||||
const target = keyIdSize * 2
|
||||
if len(id) != target {
|
||||
|
|
@ -726,10 +754,12 @@ func ValidateKeyID(id string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ValidatePublicKey checks the format of the given public key.
|
||||
func ValidatePublicKey(k *ecdsa.PublicKey) bool {
|
||||
return k != nil && k.X != nil && k.Y != nil && k.X.Sign() != 0 && k.Y.Sign() != 0
|
||||
}
|
||||
|
||||
// validatePrivateKey checks the format of the given private key.
|
||||
func validatePrivateKey(k *ecdsa.PrivateKey) bool {
|
||||
if k == nil || k.D == nil || k.D.Sign() == 0 {
|
||||
return false
|
||||
|
|
@ -742,6 +772,7 @@ func validateSymmetricKey(k []byte) bool {
|
|||
return len(k) > 0 && !containsOnlyZeros(k)
|
||||
}
|
||||
|
||||
// containsOnlyZeros checks if the data contain only zeros.
|
||||
func containsOnlyZeros(data []byte) bool {
|
||||
for _, b := range data {
|
||||
if b != 0 {
|
||||
|
|
@ -751,6 +782,7 @@ func containsOnlyZeros(data []byte) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// bytesToIntLittleEndian converts the slice to 64-bit unsigned integer.
|
||||
func bytesToIntLittleEndian(b []byte) (res uint64) {
|
||||
mul := uint64(1)
|
||||
for i := 0; i < len(b); i++ {
|
||||
|
|
@ -760,6 +792,7 @@ func bytesToIntLittleEndian(b []byte) (res uint64) {
|
|||
return res
|
||||
}
|
||||
|
||||
// BytesToIntBigEndian converts the slice to 64-bit unsigned integer.
|
||||
func BytesToIntBigEndian(b []byte) (res uint64) {
|
||||
for i := 0; i < len(b); i++ {
|
||||
res *= 256
|
||||
|
|
@ -781,6 +814,7 @@ func deriveKeyMaterial(key []byte, version uint64) (derivedKey []byte, err error
|
|||
}
|
||||
}
|
||||
|
||||
// GenerateRandomID generates a random string, which is then returned to be used as a key id
|
||||
func GenerateRandomID() (id string, err error) {
|
||||
buf := make([]byte, keyIdSize)
|
||||
_, err = crand.Read(buf)
|
||||
|
|
|
|||
Loading…
Reference in a new issue