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