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 }