github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/whisper/whisperv5/api.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //
    10  //
    11  //
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  
    25  package whisperv5
    26  
    27  import (
    28  	"context"
    29  	"crypto/ecdsa"
    30  	"errors"
    31  	"fmt"
    32  	"sync"
    33  	"time"
    34  
    35  	"github.com/ethereum/go-ethereum/common"
    36  	"github.com/ethereum/go-ethereum/common/hexutil"
    37  	"github.com/ethereum/go-ethereum/crypto"
    38  	"github.com/ethereum/go-ethereum/log"
    39  	"github.com/ethereum/go-ethereum/p2p/discover"
    40  	"github.com/ethereum/go-ethereum/rpc"
    41  )
    42  
    43  var (
    44  	ErrSymAsym              = errors.New("specify either a symmetric or an asymmetric key")
    45  	ErrInvalidSymmetricKey  = errors.New("invalid symmetric key")
    46  	ErrInvalidPublicKey     = errors.New("invalid public key")
    47  	ErrInvalidSigningPubKey = errors.New("invalid signing public key")
    48  	ErrTooLowPoW            = errors.New("message rejected, PoW too low")
    49  	ErrNoTopics             = errors.New("missing topic(s)")
    50  )
    51  
    52  //
    53  //
    54  type PublicWhisperAPI struct {
    55  	w *Whisper
    56  
    57  	mu       sync.Mutex
    58  lastUsed map[string]time.Time //
    59  }
    60  
    61  //
    62  func NewPublicWhisperAPI(w *Whisper) *PublicWhisperAPI {
    63  	api := &PublicWhisperAPI{
    64  		w:        w,
    65  		lastUsed: make(map[string]time.Time),
    66  	}
    67  	return api
    68  }
    69  
    70  //
    71  func (api *PublicWhisperAPI) Version(ctx context.Context) string {
    72  	return ProtocolVersionStr
    73  }
    74  
    75  //
    76  type Info struct {
    77  Memory         int     `json:"memory"`         //
    78  Messages       int     `json:"messages"`       //
    79  MinPow         float64 `json:"minPow"`         //
    80  MaxMessageSize uint32  `json:"maxMessageSize"` //
    81  }
    82  
    83  //
    84  func (api *PublicWhisperAPI) Info(ctx context.Context) Info {
    85  	stats := api.w.Stats()
    86  	return Info{
    87  		Memory:         stats.memoryUsed,
    88  		Messages:       len(api.w.messageQueue) + len(api.w.p2pMsgQueue),
    89  		MinPow:         api.w.MinPow(),
    90  		MaxMessageSize: api.w.MaxMessageSize(),
    91  	}
    92  }
    93  
    94  //
    95  //
    96  func (api *PublicWhisperAPI) SetMaxMessageSize(ctx context.Context, size uint32) (bool, error) {
    97  	return true, api.w.SetMaxMessageSize(size)
    98  }
    99  
   100  //
   101  func (api *PublicWhisperAPI) SetMinPoW(ctx context.Context, pow float64) (bool, error) {
   102  	return true, api.w.SetMinimumPoW(pow)
   103  }
   104  
   105  //
   106  //
   107  func (api *PublicWhisperAPI) MarkTrustedPeer(ctx context.Context, enode string) (bool, error) {
   108  	n, err := discover.ParseNode(enode)
   109  	if err != nil {
   110  		return false, err
   111  	}
   112  	return true, api.w.AllowP2PMessagesFromPeer(n.ID[:])
   113  }
   114  
   115  //
   116  //
   117  func (api *PublicWhisperAPI) NewKeyPair(ctx context.Context) (string, error) {
   118  	return api.w.NewKeyPair()
   119  }
   120  
   121  //
   122  func (api *PublicWhisperAPI) AddPrivateKey(ctx context.Context, privateKey hexutil.Bytes) (string, error) {
   123  	key, err := crypto.ToECDSA(privateKey)
   124  	if err != nil {
   125  		return "", err
   126  	}
   127  	return api.w.AddKeyPair(key)
   128  }
   129  
   130  //
   131  func (api *PublicWhisperAPI) DeleteKeyPair(ctx context.Context, key string) (bool, error) {
   132  	if ok := api.w.DeleteKeyPair(key); ok {
   133  		return true, nil
   134  	}
   135  	return false, fmt.Errorf("key pair %s not found", key)
   136  }
   137  
   138  //
   139  func (api *PublicWhisperAPI) HasKeyPair(ctx context.Context, id string) bool {
   140  	return api.w.HasKeyPair(id)
   141  }
   142  
   143  //
   144  //
   145  func (api *PublicWhisperAPI) GetPublicKey(ctx context.Context, id string) (hexutil.Bytes, error) {
   146  	key, err := api.w.GetPrivateKey(id)
   147  	if err != nil {
   148  		return hexutil.Bytes{}, err
   149  	}
   150  	return crypto.FromECDSAPub(&key.PublicKey), nil
   151  }
   152  
   153  //
   154  //
   155  func (api *PublicWhisperAPI) GetPrivateKey(ctx context.Context, id string) (hexutil.Bytes, error) {
   156  	key, err := api.w.GetPrivateKey(id)
   157  	if err != nil {
   158  		return hexutil.Bytes{}, err
   159  	}
   160  	return crypto.FromECDSA(key), nil
   161  }
   162  
   163  //
   164  //
   165  //
   166  func (api *PublicWhisperAPI) NewSymKey(ctx context.Context) (string, error) {
   167  	return api.w.GenerateSymKey()
   168  }
   169  
   170  //
   171  //
   172  //
   173  func (api *PublicWhisperAPI) AddSymKey(ctx context.Context, key hexutil.Bytes) (string, error) {
   174  	return api.w.AddSymKeyDirect([]byte(key))
   175  }
   176  
   177  //
   178  func (api *PublicWhisperAPI) GenerateSymKeyFromPassword(ctx context.Context, passwd string) (string, error) {
   179  	return api.w.AddSymKeyFromPassword(passwd)
   180  }
   181  
   182  //
   183  func (api *PublicWhisperAPI) HasSymKey(ctx context.Context, id string) bool {
   184  	return api.w.HasSymKey(id)
   185  }
   186  
   187  //
   188  func (api *PublicWhisperAPI) GetSymKey(ctx context.Context, id string) (hexutil.Bytes, error) {
   189  	return api.w.GetSymKey(id)
   190  }
   191  
   192  //
   193  func (api *PublicWhisperAPI) DeleteSymKey(ctx context.Context, id string) bool {
   194  	return api.w.DeleteSymKey(id)
   195  }
   196  
   197  //
   198  
   199  //
   200  type NewMessage struct {
   201  	SymKeyID   string    `json:"symKeyID"`
   202  	PublicKey  []byte    `json:"pubKey"`
   203  	Sig        string    `json:"sig"`
   204  	TTL        uint32    `json:"ttl"`
   205  	Topic      TopicType `json:"topic"`
   206  	Payload    []byte    `json:"payload"`
   207  	Padding    []byte    `json:"padding"`
   208  	PowTime    uint32    `json:"powTime"`
   209  	PowTarget  float64   `json:"powTarget"`
   210  	TargetPeer string    `json:"targetPeer"`
   211  }
   212  
   213  type newMessageOverride struct {
   214  	PublicKey hexutil.Bytes
   215  	Payload   hexutil.Bytes
   216  	Padding   hexutil.Bytes
   217  }
   218  
   219  //
   220  func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, error) {
   221  	var (
   222  		symKeyGiven = len(req.SymKeyID) > 0
   223  		pubKeyGiven = len(req.PublicKey) > 0
   224  		err         error
   225  	)
   226  
   227  //
   228  	if (symKeyGiven && pubKeyGiven) || (!symKeyGiven && !pubKeyGiven) {
   229  		return false, ErrSymAsym
   230  	}
   231  
   232  	params := &MessageParams{
   233  		TTL:      req.TTL,
   234  		Payload:  req.Payload,
   235  		Padding:  req.Padding,
   236  		WorkTime: req.PowTime,
   237  		PoW:      req.PowTarget,
   238  		Topic:    req.Topic,
   239  	}
   240  
   241  //
   242  	if len(req.Sig) > 0 {
   243  		if params.Src, err = api.w.GetPrivateKey(req.Sig); err != nil {
   244  			return false, err
   245  		}
   246  	}
   247  
   248  //
   249  	if symKeyGiven {
   250  if params.Topic == (TopicType{}) { //
   251  			return false, ErrNoTopics
   252  		}
   253  		if params.KeySym, err = api.w.GetSymKey(req.SymKeyID); err != nil {
   254  			return false, err
   255  		}
   256  		if !validateSymmetricKey(params.KeySym) {
   257  			return false, ErrInvalidSymmetricKey
   258  		}
   259  	}
   260  
   261  //
   262  	if pubKeyGiven {
   263  		if params.Dst, err = crypto.UnmarshalPubkey(req.PublicKey); err != nil {
   264  			return false, ErrInvalidPublicKey
   265  		}
   266  	}
   267  
   268  //
   269  	whisperMsg, err := NewSentMessage(params)
   270  	if err != nil {
   271  		return false, err
   272  	}
   273  
   274  	env, err := whisperMsg.Wrap(params)
   275  	if err != nil {
   276  		return false, err
   277  	}
   278  
   279  //
   280  	if len(req.TargetPeer) > 0 {
   281  		n, err := discover.ParseNode(req.TargetPeer)
   282  		if err != nil {
   283  			return false, fmt.Errorf("failed to parse target peer: %s", err)
   284  		}
   285  		return true, api.w.SendP2PMessage(n.ID[:], env)
   286  	}
   287  
   288  //
   289  	if req.PowTarget < api.w.MinPow() {
   290  		return false, ErrTooLowPoW
   291  	}
   292  
   293  	return true, api.w.Send(env)
   294  }
   295  
   296  //
   297  
   298  //
   299  type Criteria struct {
   300  	SymKeyID     string      `json:"symKeyID"`
   301  	PrivateKeyID string      `json:"privateKeyID"`
   302  	Sig          []byte      `json:"sig"`
   303  	MinPow       float64     `json:"minPow"`
   304  	Topics       []TopicType `json:"topics"`
   305  	AllowP2P     bool        `json:"allowP2P"`
   306  }
   307  
   308  type criteriaOverride struct {
   309  	Sig hexutil.Bytes
   310  }
   311  
   312  //
   313  //
   314  func (api *PublicWhisperAPI) Messages(ctx context.Context, crit Criteria) (*rpc.Subscription, error) {
   315  	var (
   316  		symKeyGiven = len(crit.SymKeyID) > 0
   317  		pubKeyGiven = len(crit.PrivateKeyID) > 0
   318  		err         error
   319  	)
   320  
   321  //
   322  	notifier, supported := rpc.NotifierFromContext(ctx)
   323  	if !supported {
   324  		return nil, rpc.ErrNotificationsUnsupported
   325  	}
   326  
   327  //
   328  	if (symKeyGiven && pubKeyGiven) || (!symKeyGiven && !pubKeyGiven) {
   329  		return nil, ErrSymAsym
   330  	}
   331  
   332  	filter := Filter{
   333  		PoW:      crit.MinPow,
   334  		Messages: make(map[common.Hash]*ReceivedMessage),
   335  		AllowP2P: crit.AllowP2P,
   336  	}
   337  
   338  	if len(crit.Sig) > 0 {
   339  		if filter.Src, err = crypto.UnmarshalPubkey(crit.Sig); err != nil {
   340  			return nil, ErrInvalidSigningPubKey
   341  		}
   342  	}
   343  
   344  	for i, bt := range crit.Topics {
   345  		if len(bt) == 0 || len(bt) > 4 {
   346  			return nil, fmt.Errorf("subscribe: topic %d has wrong size: %d", i, len(bt))
   347  		}
   348  		filter.Topics = append(filter.Topics, bt[:])
   349  	}
   350  
   351  //
   352  	if symKeyGiven {
   353  		if len(filter.Topics) == 0 {
   354  			return nil, ErrNoTopics
   355  		}
   356  		key, err := api.w.GetSymKey(crit.SymKeyID)
   357  		if err != nil {
   358  			return nil, err
   359  		}
   360  		if !validateSymmetricKey(key) {
   361  			return nil, ErrInvalidSymmetricKey
   362  		}
   363  		filter.KeySym = key
   364  		filter.SymKeyHash = crypto.Keccak256Hash(filter.KeySym)
   365  	}
   366  
   367  //
   368  	if pubKeyGiven {
   369  		filter.KeyAsym, err = api.w.GetPrivateKey(crit.PrivateKeyID)
   370  		if err != nil || filter.KeyAsym == nil {
   371  			return nil, ErrInvalidPublicKey
   372  		}
   373  	}
   374  
   375  	id, err := api.w.Subscribe(&filter)
   376  	if err != nil {
   377  		return nil, err
   378  	}
   379  
   380  //
   381  	rpcSub := notifier.CreateSubscription()
   382  	go func() {
   383  //
   384  		ticker := time.NewTicker(250 * time.Millisecond)
   385  		defer ticker.Stop()
   386  
   387  		for {
   388  			select {
   389  			case <-ticker.C:
   390  				if filter := api.w.GetFilter(id); filter != nil {
   391  					for _, rpcMessage := range toMessage(filter.Retrieve()) {
   392  						if err := notifier.Notify(rpcSub.ID, rpcMessage); err != nil {
   393  							log.Error("Failed to send notification", "err", err)
   394  						}
   395  					}
   396  				}
   397  			case <-rpcSub.Err():
   398  				api.w.Unsubscribe(id)
   399  				return
   400  			case <-notifier.Closed():
   401  				api.w.Unsubscribe(id)
   402  				return
   403  			}
   404  		}
   405  	}()
   406  
   407  	return rpcSub, nil
   408  }
   409  
   410  //
   411  
   412  //
   413  type Message struct {
   414  	Sig       []byte    `json:"sig,omitempty"`
   415  	TTL       uint32    `json:"ttl"`
   416  	Timestamp uint32    `json:"timestamp"`
   417  	Topic     TopicType `json:"topic"`
   418  	Payload   []byte    `json:"payload"`
   419  	Padding   []byte    `json:"padding"`
   420  	PoW       float64   `json:"pow"`
   421  	Hash      []byte    `json:"hash"`
   422  	Dst       []byte    `json:"recipientPublicKey,omitempty"`
   423  }
   424  
   425  type messageOverride struct {
   426  	Sig     hexutil.Bytes
   427  	Payload hexutil.Bytes
   428  	Padding hexutil.Bytes
   429  	Hash    hexutil.Bytes
   430  	Dst     hexutil.Bytes
   431  }
   432  
   433  //
   434  func ToWhisperMessage(message *ReceivedMessage) *Message {
   435  	msg := Message{
   436  		Payload:   message.Payload,
   437  		Padding:   message.Padding,
   438  		Timestamp: message.Sent,
   439  		TTL:       message.TTL,
   440  		PoW:       message.PoW,
   441  		Hash:      message.EnvelopeHash.Bytes(),
   442  		Topic:     message.Topic,
   443  	}
   444  
   445  	if message.Dst != nil {
   446  		b := crypto.FromECDSAPub(message.Dst)
   447  		if b != nil {
   448  			msg.Dst = b
   449  		}
   450  	}
   451  
   452  	if isMessageSigned(message.Raw[0]) {
   453  		b := crypto.FromECDSAPub(message.SigToPubKey())
   454  		if b != nil {
   455  			msg.Sig = b
   456  		}
   457  	}
   458  
   459  	return &msg
   460  }
   461  
   462  //
   463  func toMessage(messages []*ReceivedMessage) []*Message {
   464  	msgs := make([]*Message, len(messages))
   465  	for i, msg := range messages {
   466  		msgs[i] = ToWhisperMessage(msg)
   467  	}
   468  	return msgs
   469  }
   470  
   471  //
   472  //
   473  func (api *PublicWhisperAPI) GetFilterMessages(id string) ([]*Message, error) {
   474  	api.mu.Lock()
   475  	f := api.w.GetFilter(id)
   476  	if f == nil {
   477  		api.mu.Unlock()
   478  		return nil, fmt.Errorf("filter not found")
   479  	}
   480  	api.lastUsed[id] = time.Now()
   481  	api.mu.Unlock()
   482  
   483  	receivedMessages := f.Retrieve()
   484  	messages := make([]*Message, 0, len(receivedMessages))
   485  	for _, msg := range receivedMessages {
   486  		messages = append(messages, ToWhisperMessage(msg))
   487  	}
   488  
   489  	return messages, nil
   490  }
   491  
   492  //
   493  func (api *PublicWhisperAPI) DeleteMessageFilter(id string) (bool, error) {
   494  	api.mu.Lock()
   495  	defer api.mu.Unlock()
   496  
   497  	delete(api.lastUsed, id)
   498  	return true, api.w.Unsubscribe(id)
   499  }
   500  
   501  //
   502  //
   503  func (api *PublicWhisperAPI) NewMessageFilter(req Criteria) (string, error) {
   504  	var (
   505  		src     *ecdsa.PublicKey
   506  		keySym  []byte
   507  		keyAsym *ecdsa.PrivateKey
   508  		topics  [][]byte
   509  
   510  		symKeyGiven  = len(req.SymKeyID) > 0
   511  		asymKeyGiven = len(req.PrivateKeyID) > 0
   512  
   513  		err error
   514  	)
   515  
   516  //
   517  	if (symKeyGiven && asymKeyGiven) || (!symKeyGiven && !asymKeyGiven) {
   518  		return "", ErrSymAsym
   519  	}
   520  
   521  	if len(req.Sig) > 0 {
   522  		if src, err = crypto.UnmarshalPubkey(req.Sig); err != nil {
   523  			return "", ErrInvalidSigningPubKey
   524  		}
   525  	}
   526  
   527  	if symKeyGiven {
   528  		if keySym, err = api.w.GetSymKey(req.SymKeyID); err != nil {
   529  			return "", err
   530  		}
   531  		if !validateSymmetricKey(keySym) {
   532  			return "", ErrInvalidSymmetricKey
   533  		}
   534  	}
   535  
   536  	if asymKeyGiven {
   537  		if keyAsym, err = api.w.GetPrivateKey(req.PrivateKeyID); err != nil {
   538  			return "", err
   539  		}
   540  	}
   541  
   542  	if len(req.Topics) > 0 {
   543  		topics = make([][]byte, 0, len(req.Topics))
   544  		for _, topic := range req.Topics {
   545  			topics = append(topics, topic[:])
   546  		}
   547  	}
   548  
   549  	f := &Filter{
   550  		Src:      src,
   551  		KeySym:   keySym,
   552  		KeyAsym:  keyAsym,
   553  		PoW:      req.MinPow,
   554  		AllowP2P: req.AllowP2P,
   555  		Topics:   topics,
   556  		Messages: make(map[common.Hash]*ReceivedMessage),
   557  	}
   558  
   559  	id, err := api.w.Subscribe(f)
   560  	if err != nil {
   561  		return "", err
   562  	}
   563  
   564  	api.mu.Lock()
   565  	api.lastUsed[id] = time.Now()
   566  	api.mu.Unlock()
   567  
   568  	return id, nil
   569  }