github.com/status-im/status-go@v1.1.0/mailserver/mailserver.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package mailserver 18 19 import ( 20 "crypto/ecdsa" 21 "encoding/binary" 22 "errors" 23 "fmt" 24 "math/rand" 25 "sync" 26 "time" 27 28 prom "github.com/prometheus/client_golang/prometheus" 29 30 "github.com/ethereum/go-ethereum/common" 31 "github.com/ethereum/go-ethereum/log" 32 "github.com/ethereum/go-ethereum/rlp" 33 gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" 34 "github.com/status-im/status-go/eth-node/crypto" 35 "github.com/status-im/status-go/eth-node/types" 36 "github.com/status-im/status-go/params" 37 "github.com/status-im/status-go/waku" 38 wakucommon "github.com/status-im/status-go/waku/common" 39 ) 40 41 const ( 42 maxQueryRange = 24 * time.Hour 43 maxQueryLimit = 1000 44 // When we default the upper limit, we want to extend the range a bit 45 // to accommodate for envelopes with slightly higher timestamp, in seconds 46 whisperTTLSafeThreshold = 60 47 ) 48 49 var ( 50 errDirectoryNotProvided = errors.New("data directory not provided") 51 errDecryptionMethodNotProvided = errors.New("decryption method is not provided") 52 ) 53 54 const ( 55 timestampLength = 4 56 requestLimitLength = 4 57 requestTimeRangeLength = timestampLength * 2 58 processRequestTimeout = time.Minute 59 ) 60 61 type Config struct { 62 // DataDir points to a directory where mailserver's data is stored. 63 DataDir string 64 // Password is used to create a symmetric key to decrypt requests. 65 Password string 66 // AsymKey is an asymmetric key to decrypt requests. 67 AsymKey string 68 // MininumPoW is a minimum PoW for requests. 69 MinimumPoW float64 70 // RateLimit is a maximum number of requests per second from a peer. 71 RateLimit int 72 // DataRetention specifies a number of days an envelope should be stored for. 73 DataRetention int 74 PostgresEnabled bool 75 PostgresURI string 76 } 77 78 // -------------- 79 // WakuMailServer 80 // -------------- 81 82 type WakuMailServer struct { 83 ms *mailServer 84 shh *waku.Waku 85 minRequestPoW float64 86 87 symFilter *wakucommon.Filter 88 asymFilter *wakucommon.Filter 89 } 90 91 func (s *WakuMailServer) Init(waku *waku.Waku, cfg *params.WakuConfig) error { 92 s.shh = waku 93 s.minRequestPoW = cfg.MinimumPoW 94 95 config := Config{ 96 DataDir: cfg.DataDir, 97 Password: cfg.MailServerPassword, 98 MinimumPoW: cfg.MinimumPoW, 99 DataRetention: cfg.MailServerDataRetention, 100 RateLimit: cfg.MailServerRateLimit, 101 PostgresEnabled: cfg.DatabaseConfig.PGConfig.Enabled, 102 PostgresURI: cfg.DatabaseConfig.PGConfig.URI, 103 } 104 var err error 105 s.ms, err = newMailServer( 106 config, 107 &wakuAdapter{}, 108 &wakuService{Waku: waku}, 109 ) 110 if err != nil { 111 return err 112 } 113 114 if err := s.setupDecryptor(config.Password, config.AsymKey); err != nil { 115 return err 116 } 117 118 return nil 119 } 120 121 func (s *WakuMailServer) Close() { 122 s.ms.Close() 123 } 124 125 func (s *WakuMailServer) Archive(env *wakucommon.Envelope) { 126 s.ms.Archive(gethbridge.NewWakuEnvelope(env)) 127 } 128 129 func (s *WakuMailServer) Deliver(peerID []byte, req wakucommon.MessagesRequest) { 130 s.ms.DeliverMail(types.BytesToHash(peerID), types.BytesToHash(req.ID), MessagesRequestPayload{ 131 Lower: req.From, 132 Upper: req.To, 133 Bloom: req.Bloom, 134 Topics: req.Topics, 135 Limit: req.Limit, 136 Cursor: req.Cursor, 137 Batch: true, 138 }) 139 } 140 141 // DEPRECATED; user Deliver instead 142 func (s *WakuMailServer) DeliverMail(peerID []byte, req *wakucommon.Envelope) { 143 payload, err := s.decodeRequest(peerID, req) 144 if err != nil { 145 deliveryFailuresCounter.WithLabelValues("validation").Inc() 146 log.Error( 147 "[mailserver:DeliverMail] request failed validaton", 148 "peerID", types.BytesToHash(peerID), 149 "requestID", req.Hash().String(), 150 "err", err, 151 ) 152 s.ms.sendHistoricMessageErrorResponse(types.BytesToHash(peerID), types.Hash(req.Hash()), err) 153 return 154 } 155 156 s.ms.DeliverMail(types.BytesToHash(peerID), types.Hash(req.Hash()), payload) 157 } 158 159 // bloomFromReceivedMessage for a given whisper.ReceivedMessage it extracts the 160 // used bloom filter. 161 func (s *WakuMailServer) bloomFromReceivedMessage(msg *wakucommon.ReceivedMessage) ([]byte, error) { 162 payloadSize := len(msg.Payload) 163 164 if payloadSize < 8 { 165 return nil, errors.New("Undersized p2p request") 166 } else if payloadSize == 8 { 167 return wakucommon.MakeFullNodeBloom(), nil 168 } else if payloadSize < 8+wakucommon.BloomFilterSize { 169 return nil, errors.New("Undersized bloom filter in p2p request") 170 } 171 172 return msg.Payload[8 : 8+wakucommon.BloomFilterSize], nil 173 } 174 175 func (s *WakuMailServer) decompositeRequest(peerID []byte, request *wakucommon.Envelope) (MessagesRequestPayload, error) { 176 var ( 177 payload MessagesRequestPayload 178 err error 179 ) 180 181 if s.minRequestPoW > 0.0 && request.PoW() < s.minRequestPoW { 182 return payload, fmt.Errorf("PoW() is too low") 183 } 184 185 decrypted := s.openEnvelope(request) 186 if decrypted == nil { 187 return payload, fmt.Errorf("failed to decrypt p2p request") 188 } 189 190 if err := checkMsgSignature(decrypted.Src, peerID); err != nil { 191 return payload, err 192 } 193 194 payload.Bloom, err = s.bloomFromReceivedMessage(decrypted) 195 if err != nil { 196 return payload, err 197 } 198 199 payload.Lower = binary.BigEndian.Uint32(decrypted.Payload[:4]) 200 payload.Upper = binary.BigEndian.Uint32(decrypted.Payload[4:8]) 201 202 if payload.Upper < payload.Lower { 203 err := fmt.Errorf("query range is invalid: from > to (%d > %d)", payload.Lower, payload.Upper) 204 return payload, err 205 } 206 207 lowerTime := time.Unix(int64(payload.Lower), 0) 208 upperTime := time.Unix(int64(payload.Upper), 0) 209 if upperTime.Sub(lowerTime) > maxQueryRange { 210 err := fmt.Errorf("query range too big for peer %s", string(peerID)) 211 return payload, err 212 } 213 214 if len(decrypted.Payload) >= requestTimeRangeLength+wakucommon.BloomFilterSize+requestLimitLength { 215 payload.Limit = binary.BigEndian.Uint32(decrypted.Payload[requestTimeRangeLength+wakucommon.BloomFilterSize:]) 216 } 217 218 if len(decrypted.Payload) == requestTimeRangeLength+wakucommon.BloomFilterSize+requestLimitLength+DBKeyLength { 219 payload.Cursor = decrypted.Payload[requestTimeRangeLength+wakucommon.BloomFilterSize+requestLimitLength:] 220 } 221 222 return payload, nil 223 } 224 225 func (s *WakuMailServer) setupDecryptor(password, asymKey string) error { 226 s.symFilter = nil 227 s.asymFilter = nil 228 229 if password != "" { 230 keyID, err := s.shh.AddSymKeyFromPassword(password) 231 if err != nil { 232 return fmt.Errorf("create symmetric key: %v", err) 233 } 234 235 symKey, err := s.shh.GetSymKey(keyID) 236 if err != nil { 237 return fmt.Errorf("save symmetric key: %v", err) 238 } 239 240 s.symFilter = &wakucommon.Filter{KeySym: symKey} 241 } 242 243 if asymKey != "" { 244 keyAsym, err := crypto.HexToECDSA(asymKey) 245 if err != nil { 246 return err 247 } 248 s.asymFilter = &wakucommon.Filter{KeyAsym: keyAsym} 249 } 250 251 return nil 252 } 253 254 // openEnvelope tries to decrypt an envelope, first based on asymetric key (if 255 // provided) and second on the symetric key (if provided) 256 func (s *WakuMailServer) openEnvelope(request *wakucommon.Envelope) *wakucommon.ReceivedMessage { 257 if s.asymFilter != nil { 258 if d := request.Open(s.asymFilter); d != nil { 259 return d 260 } 261 } 262 if s.symFilter != nil { 263 if d := request.Open(s.symFilter); d != nil { 264 return d 265 } 266 } 267 return nil 268 } 269 270 func (s *WakuMailServer) decodeRequest(peerID []byte, request *wakucommon.Envelope) (MessagesRequestPayload, error) { 271 var payload MessagesRequestPayload 272 273 if s.minRequestPoW > 0.0 && request.PoW() < s.minRequestPoW { 274 return payload, errors.New("PoW too low") 275 } 276 277 decrypted := s.openEnvelope(request) 278 if decrypted == nil { 279 log.Warn("Failed to decrypt p2p request") 280 return payload, errors.New("failed to decrypt p2p request") 281 } 282 283 if err := checkMsgSignature(decrypted.Src, peerID); err != nil { 284 log.Warn("Check message signature failed", "err", err.Error()) 285 return payload, fmt.Errorf("check message signature failed: %v", err) 286 } 287 288 if err := rlp.DecodeBytes(decrypted.Payload, &payload); err != nil { 289 return payload, fmt.Errorf("failed to decode data: %v", err) 290 } 291 292 if payload.Upper == 0 { 293 payload.Upper = uint32(time.Now().Unix() + whisperTTLSafeThreshold) 294 } 295 296 if payload.Upper < payload.Lower { 297 log.Error("Query range is invalid: lower > upper", "lower", payload.Lower, "upper", payload.Upper) 298 return payload, errors.New("query range is invalid: lower > upper") 299 } 300 301 return payload, nil 302 } 303 304 // ------- 305 // adapter 306 // ------- 307 308 type adapter interface { 309 CreateRequestFailedPayload(reqID types.Hash, err error) []byte 310 CreateRequestCompletedPayload(reqID, lastEnvelopeHash types.Hash, cursor []byte) []byte 311 CreateSyncResponse(envelopes []types.Envelope, cursor []byte, final bool, err string) interface{} 312 CreateRawSyncResponse(envelopes []rlp.RawValue, cursor []byte, final bool, err string) interface{} 313 } 314 315 // ----------- 316 // wakuAdapter 317 // ----------- 318 319 type wakuAdapter struct{} 320 321 var _ adapter = (*wakuAdapter)(nil) 322 323 func (wakuAdapter) CreateRequestFailedPayload(reqID types.Hash, err error) []byte { 324 return waku.CreateMailServerRequestFailedPayload(common.Hash(reqID), err) 325 } 326 327 func (wakuAdapter) CreateRequestCompletedPayload(reqID, lastEnvelopeHash types.Hash, cursor []byte) []byte { 328 return waku.CreateMailServerRequestCompletedPayload(common.Hash(reqID), common.Hash(lastEnvelopeHash), cursor) 329 } 330 331 func (wakuAdapter) CreateSyncResponse(_ []types.Envelope, _ []byte, _ bool, _ string) interface{} { 332 return nil 333 } 334 335 func (wakuAdapter) CreateRawSyncResponse(_ []rlp.RawValue, _ []byte, _ bool, _ string) interface{} { 336 return nil 337 } 338 339 // ------- 340 // service 341 // ------- 342 343 type service interface { 344 SendHistoricMessageResponse(peerID []byte, payload []byte) error 345 SendRawP2PDirect(peerID []byte, envelopes ...rlp.RawValue) error 346 MaxMessageSize() uint32 347 SendRawSyncResponse(peerID []byte, data interface{}) error // optional 348 SendSyncResponse(peerID []byte, data interface{}) error // optional 349 } 350 351 // ----------- 352 // wakuService 353 // ----------- 354 355 type wakuService struct { 356 *waku.Waku 357 } 358 359 func (s *wakuService) SendRawSyncResponse(peerID []byte, data interface{}) error { 360 return errors.New("syncing mailservers is not support by Waku") 361 } 362 363 func (s *wakuService) SendSyncResponse(peerID []byte, data interface{}) error { 364 return errors.New("syncing mailservers is not support by Waku") 365 } 366 367 // ---------- 368 // mailServer 369 // ---------- 370 371 type mailServer struct { 372 adapter adapter 373 service service 374 db DB 375 cleaner *dbCleaner // removes old envelopes 376 muRateLimiter sync.RWMutex 377 rateLimiter *rateLimiter 378 } 379 380 func newMailServer(cfg Config, adapter adapter, service service) (*mailServer, error) { 381 if len(cfg.DataDir) == 0 { 382 return nil, errDirectoryNotProvided 383 } 384 385 // TODO: move out 386 if len(cfg.Password) == 0 && len(cfg.AsymKey) == 0 { 387 return nil, errDecryptionMethodNotProvided 388 } 389 390 s := mailServer{ 391 adapter: adapter, 392 service: service, 393 } 394 395 if cfg.RateLimit > 0 { 396 s.setupRateLimiter(time.Duration(cfg.RateLimit) * time.Second) 397 } 398 399 // Open database in the last step in order not to init with error 400 // and leave the database open by accident. 401 if cfg.PostgresEnabled { 402 log.Info("Connecting to postgres database") 403 database, err := NewPostgresDB(cfg.PostgresURI) 404 if err != nil { 405 return nil, fmt.Errorf("open DB: %s", err) 406 } 407 s.db = database 408 log.Info("Connected to postgres database") 409 } else { 410 // Defaults to LevelDB 411 database, err := NewLevelDB(cfg.DataDir) 412 if err != nil { 413 return nil, fmt.Errorf("open DB: %s", err) 414 } 415 s.db = database 416 } 417 418 if cfg.DataRetention > 0 { 419 // MailServerDataRetention is a number of days. 420 s.setupCleaner(time.Duration(cfg.DataRetention) * time.Hour * 24) 421 } 422 423 return &s, nil 424 } 425 426 // setupRateLimiter in case limit is bigger than 0 it will setup an automated 427 // limit db cleanup. 428 func (s *mailServer) setupRateLimiter(limit time.Duration) { 429 s.rateLimiter = newRateLimiter(limit) 430 s.rateLimiter.Start() 431 } 432 433 func (s *mailServer) setupCleaner(retention time.Duration) { 434 s.cleaner = newDBCleaner(s.db, retention) 435 s.cleaner.Start() 436 } 437 438 func (s *mailServer) Archive(env types.Envelope) { 439 err := s.db.SaveEnvelope(env) 440 if err != nil { 441 log.Error("Could not save envelope", "hash", env.Hash().String()) 442 } 443 } 444 445 func (s *mailServer) DeliverMail(peerID, reqID types.Hash, req MessagesRequestPayload) { 446 timer := prom.NewTimer(mailDeliveryDuration) 447 defer timer.ObserveDuration() 448 449 deliveryAttemptsCounter.Inc() 450 log.Info( 451 "[mailserver:DeliverMail] delivering mail", 452 "peerID", peerID.String(), 453 "requestID", reqID.String(), 454 ) 455 456 req.SetDefaults() 457 458 log.Info( 459 "[mailserver:DeliverMail] processing request", 460 "peerID", peerID.String(), 461 "requestID", reqID.String(), 462 "lower", req.Lower, 463 "upper", req.Upper, 464 "bloom", req.Bloom, 465 "topics", req.Topics, 466 "limit", req.Limit, 467 "cursor", req.Cursor, 468 "batch", req.Batch, 469 ) 470 471 if err := req.Validate(); err != nil { 472 syncFailuresCounter.WithLabelValues("req_invalid").Inc() 473 log.Error( 474 "[mailserver:DeliverMail] request invalid", 475 "peerID", peerID.String(), 476 "requestID", reqID.String(), 477 "err", err, 478 ) 479 s.sendHistoricMessageErrorResponse(peerID, reqID, fmt.Errorf("request is invalid: %v", err)) 480 return 481 } 482 483 if s.exceedsPeerRequests(peerID) { 484 deliveryFailuresCounter.WithLabelValues("peer_req_limit").Inc() 485 log.Error( 486 "[mailserver:DeliverMail] peer exceeded the limit", 487 "peerID", peerID.String(), 488 "requestID", reqID.String(), 489 ) 490 s.sendHistoricMessageErrorResponse(peerID, reqID, fmt.Errorf("rate limit exceeded")) 491 return 492 } 493 494 if req.Batch { 495 requestsBatchedCounter.Inc() 496 } 497 498 iter, err := s.createIterator(req) 499 if err != nil { 500 log.Error( 501 "[mailserver:DeliverMail] request failed", 502 "peerID", peerID.String(), 503 "requestID", reqID.String(), 504 "err", err, 505 ) 506 return 507 } 508 defer func() { _ = iter.Release() }() 509 510 bundles := make(chan []rlp.RawValue, 5) 511 errCh := make(chan error) 512 cancelProcessing := make(chan struct{}) 513 514 go func() { 515 counter := 0 516 for bundle := range bundles { 517 if err := s.sendRawEnvelopes(peerID, bundle, req.Batch); err != nil { 518 close(cancelProcessing) 519 errCh <- err 520 break 521 } 522 counter++ 523 } 524 close(errCh) 525 log.Info( 526 "[mailserver:DeliverMail] finished sending bundles", 527 "peerID", peerID, 528 "requestID", reqID.String(), 529 "counter", counter, 530 ) 531 }() 532 533 nextPageCursor, lastEnvelopeHash := s.processRequestInBundles( 534 iter, 535 req.Bloom, 536 req.Topics, 537 int(req.Limit), 538 processRequestTimeout, 539 reqID.String(), 540 bundles, 541 cancelProcessing, 542 ) 543 544 // Wait for the goroutine to finish the work. It may return an error. 545 if err := <-errCh; err != nil { 546 deliveryFailuresCounter.WithLabelValues("process").Inc() 547 log.Error( 548 "[mailserver:DeliverMail] error while processing", 549 "err", err, 550 "peerID", peerID, 551 "requestID", reqID, 552 ) 553 s.sendHistoricMessageErrorResponse(peerID, reqID, err) 554 return 555 } 556 557 // Processing of the request could be finished earlier due to iterator error. 558 if err := iter.Error(); err != nil { 559 deliveryFailuresCounter.WithLabelValues("iterator").Inc() 560 log.Error( 561 "[mailserver:DeliverMail] iterator failed", 562 "err", err, 563 "peerID", peerID, 564 "requestID", reqID, 565 ) 566 s.sendHistoricMessageErrorResponse(peerID, reqID, err) 567 return 568 } 569 570 log.Info( 571 "[mailserver:DeliverMail] sending historic message response", 572 "peerID", peerID, 573 "requestID", reqID, 574 "last", lastEnvelopeHash, 575 "next", nextPageCursor, 576 ) 577 578 s.sendHistoricMessageResponse(peerID, reqID, lastEnvelopeHash, nextPageCursor) 579 } 580 581 func (s *mailServer) SyncMail(peerID types.Hash, req MessagesRequestPayload) error { 582 log.Info("Started syncing envelopes", "peer", peerID.String(), "req", req) 583 584 requestID := fmt.Sprintf("%d-%d", time.Now().UnixNano(), rand.Intn(1000)) // nolint: gosec 585 586 syncAttemptsCounter.Inc() 587 588 // Check rate limiting for a requesting peer. 589 if s.exceedsPeerRequests(peerID) { 590 syncFailuresCounter.WithLabelValues("req_per_sec_limit").Inc() 591 log.Error("Peer exceeded request per seconds limit", "peerID", peerID.String()) 592 return fmt.Errorf("requests per seconds limit exceeded") 593 } 594 595 req.SetDefaults() 596 597 if err := req.Validate(); err != nil { 598 syncFailuresCounter.WithLabelValues("req_invalid").Inc() 599 return fmt.Errorf("request is invalid: %v", err) 600 } 601 602 iter, err := s.createIterator(req) 603 if err != nil { 604 syncFailuresCounter.WithLabelValues("iterator").Inc() 605 return err 606 } 607 defer func() { _ = iter.Release() }() 608 609 bundles := make(chan []rlp.RawValue, 5) 610 errCh := make(chan error) 611 cancelProcessing := make(chan struct{}) 612 613 go func() { 614 for bundle := range bundles { 615 resp := s.adapter.CreateRawSyncResponse(bundle, nil, false, "") 616 if err := s.service.SendRawSyncResponse(peerID.Bytes(), resp); err != nil { 617 close(cancelProcessing) 618 errCh <- fmt.Errorf("failed to send sync response: %v", err) 619 break 620 } 621 } 622 close(errCh) 623 }() 624 625 nextCursor, _ := s.processRequestInBundles( 626 iter, 627 req.Bloom, 628 req.Topics, 629 int(req.Limit), 630 processRequestTimeout, 631 requestID, 632 bundles, 633 cancelProcessing, 634 ) 635 636 // Wait for the goroutine to finish the work. It may return an error. 637 if err := <-errCh; err != nil { 638 syncFailuresCounter.WithLabelValues("routine").Inc() 639 _ = s.service.SendSyncResponse( 640 peerID.Bytes(), 641 s.adapter.CreateSyncResponse(nil, nil, false, "failed to send a response"), 642 ) 643 return err 644 } 645 646 // Processing of the request could be finished earlier due to iterator error. 647 if err := iter.Error(); err != nil { 648 syncFailuresCounter.WithLabelValues("iterator").Inc() 649 _ = s.service.SendSyncResponse( 650 peerID.Bytes(), 651 s.adapter.CreateSyncResponse(nil, nil, false, "failed to process all envelopes"), 652 ) 653 return fmt.Errorf("LevelDB iterator failed: %v", err) 654 } 655 656 log.Info("Finished syncing envelopes", "peer", peerID.String()) 657 658 err = s.service.SendSyncResponse( 659 peerID.Bytes(), 660 s.adapter.CreateSyncResponse(nil, nextCursor, true, ""), 661 ) 662 if err != nil { 663 syncFailuresCounter.WithLabelValues("response_send").Inc() 664 return fmt.Errorf("failed to send the final sync response: %v", err) 665 } 666 667 return nil 668 } 669 670 // Close the mailserver and its associated db connection. 671 func (s *mailServer) Close() { 672 if s.db != nil { 673 if err := s.db.Close(); err != nil { 674 log.Error("closing database failed", "err", err) 675 } 676 } 677 if s.rateLimiter != nil { 678 s.rateLimiter.Stop() 679 } 680 if s.cleaner != nil { 681 s.cleaner.Stop() 682 } 683 } 684 685 func (s *mailServer) exceedsPeerRequests(peerID types.Hash) bool { 686 s.muRateLimiter.RLock() 687 defer s.muRateLimiter.RUnlock() 688 689 if s.rateLimiter == nil { 690 return false 691 } 692 693 if s.rateLimiter.IsAllowed(peerID.String()) { 694 s.rateLimiter.Add(peerID.String()) 695 return false 696 } 697 698 log.Info("peerID exceeded the number of requests per second", "peerID", peerID.String()) 699 return true 700 } 701 702 func (s *mailServer) createIterator(req MessagesRequestPayload) (Iterator, error) { 703 var ( 704 emptyHash types.Hash 705 emptyTopic types.TopicType 706 ku, kl *DBKey 707 ) 708 709 ku = NewDBKey(req.Upper+1, emptyTopic, emptyHash) 710 kl = NewDBKey(req.Lower, emptyTopic, emptyHash) 711 712 query := CursorQuery{ 713 start: kl.Bytes(), 714 end: ku.Bytes(), 715 cursor: req.Cursor, 716 topics: req.Topics, 717 bloom: req.Bloom, 718 limit: req.Limit, 719 } 720 return s.db.BuildIterator(query) 721 } 722 723 func (s *mailServer) processRequestInBundles( 724 iter Iterator, 725 bloom []byte, 726 topics [][]byte, 727 limit int, 728 timeout time.Duration, 729 requestID string, 730 output chan<- []rlp.RawValue, 731 cancel <-chan struct{}, 732 ) ([]byte, types.Hash) { 733 timer := prom.NewTimer(requestsInBundlesDuration) 734 defer timer.ObserveDuration() 735 736 var ( 737 bundle []rlp.RawValue 738 bundleSize uint32 739 batches [][]rlp.RawValue 740 processedEnvelopes int 741 processedEnvelopesSize int64 742 nextCursor []byte 743 lastEnvelopeHash types.Hash 744 ) 745 746 log.Info( 747 "[mailserver:processRequestInBundles] processing request", 748 "requestID", requestID, 749 "limit", limit, 750 ) 751 752 var topicsMap map[types.TopicType]bool 753 754 if len(topics) != 0 { 755 topicsMap = make(map[types.TopicType]bool) 756 for _, t := range topics { 757 topicsMap[types.BytesToTopic(t)] = true 758 } 759 } 760 761 // We iterate over the envelopes. 762 // We collect envelopes in batches. 763 // If there still room and we haven't reached the limit 764 // append and continue. 765 // Otherwise publish what you have so far, reset the bundle to the 766 // current envelope, and leave if we hit the limit 767 for iter.Next() { 768 var rawValue []byte 769 var err error 770 if len(topicsMap) != 0 { 771 rawValue, err = iter.GetEnvelopeByTopicsMap(topicsMap) 772 773 } else if len(bloom) != 0 { 774 rawValue, err = iter.GetEnvelopeByBloomFilter(bloom) 775 } else { 776 err = errors.New("either topics or bloom must be specified") 777 } 778 if err != nil { 779 log.Error( 780 "[mailserver:processRequestInBundles]Failed to get envelope from iterator", 781 "err", err, 782 "requestID", requestID, 783 ) 784 continue 785 } 786 787 if rawValue == nil { 788 continue 789 } 790 791 key, err := iter.DBKey() 792 if err != nil { 793 log.Error( 794 "[mailserver:processRequestInBundles] failed getting key", 795 "requestID", requestID, 796 ) 797 break 798 799 } 800 801 // TODO(adam): this is invalid code. If the limit is 1000, 802 // it will only send 999 items and send a cursor. 803 lastEnvelopeHash = key.EnvelopeHash() 804 processedEnvelopes++ 805 envelopeSize := uint32(len(rawValue)) 806 limitReached := processedEnvelopes >= limit 807 newSize := bundleSize + envelopeSize 808 809 // If we still have some room for messages, add and continue 810 if !limitReached && newSize < s.service.MaxMessageSize() { 811 bundle = append(bundle, rawValue) 812 bundleSize = newSize 813 continue 814 } 815 816 // Publish if anything is in the bundle (there should always be 817 // something unless limit = 1) 818 if len(bundle) != 0 { 819 batches = append(batches, bundle) 820 processedEnvelopesSize += int64(bundleSize) 821 } 822 823 // Reset the bundle with the current envelope 824 bundle = []rlp.RawValue{rawValue} 825 bundleSize = envelopeSize 826 827 // Leave if we reached the limit 828 if limitReached { 829 nextCursor = key.Cursor() 830 break 831 } 832 } 833 834 if len(bundle) > 0 { 835 batches = append(batches, bundle) 836 processedEnvelopesSize += int64(bundleSize) 837 } 838 839 log.Info( 840 "[mailserver:processRequestInBundles] publishing envelopes", 841 "requestID", requestID, 842 "batchesCount", len(batches), 843 "envelopeCount", processedEnvelopes, 844 "processedEnvelopesSize", processedEnvelopesSize, 845 "cursor", nextCursor, 846 ) 847 848 // Publish 849 batchLoop: 850 for _, batch := range batches { 851 select { 852 case output <- batch: 853 // It might happen that during producing the batches, 854 // the connection with the peer goes down and 855 // the consumer of `output` channel exits prematurely. 856 // In such a case, we should stop pushing batches and exit. 857 case <-cancel: 858 log.Info( 859 "[mailserver:processRequestInBundles] failed to push all batches", 860 "requestID", requestID, 861 ) 862 break batchLoop 863 case <-time.After(timeout): 864 log.Error( 865 "[mailserver:processRequestInBundles] timed out pushing a batch", 866 "requestID", requestID, 867 ) 868 break batchLoop 869 } 870 } 871 872 envelopesCounter.Inc() 873 sentEnvelopeBatchSizeMeter.Observe(float64(processedEnvelopesSize)) 874 875 log.Info( 876 "[mailserver:processRequestInBundles] envelopes published", 877 "requestID", requestID, 878 ) 879 close(output) 880 881 return nextCursor, lastEnvelopeHash 882 } 883 884 func (s *mailServer) sendRawEnvelopes(peerID types.Hash, envelopes []rlp.RawValue, batch bool) error { 885 timer := prom.NewTimer(sendRawEnvelopeDuration) 886 defer timer.ObserveDuration() 887 888 if batch { 889 return s.service.SendRawP2PDirect(peerID.Bytes(), envelopes...) 890 } 891 892 for _, env := range envelopes { 893 if err := s.service.SendRawP2PDirect(peerID.Bytes(), env); err != nil { 894 return err 895 } 896 } 897 898 return nil 899 } 900 901 func (s *mailServer) sendHistoricMessageResponse(peerID, reqID, lastEnvelopeHash types.Hash, cursor []byte) { 902 payload := s.adapter.CreateRequestCompletedPayload(reqID, lastEnvelopeHash, cursor) 903 err := s.service.SendHistoricMessageResponse(peerID.Bytes(), payload) 904 if err != nil { 905 deliveryFailuresCounter.WithLabelValues("historic_msg_resp").Inc() 906 log.Error( 907 "[mailserver:DeliverMail] error sending historic message response", 908 "err", err, 909 "peerID", peerID, 910 "requestID", reqID, 911 ) 912 } 913 } 914 915 func (s *mailServer) sendHistoricMessageErrorResponse(peerID, reqID types.Hash, errorToReport error) { 916 payload := s.adapter.CreateRequestFailedPayload(reqID, errorToReport) 917 err := s.service.SendHistoricMessageResponse(peerID.Bytes(), payload) 918 // if we can't report an error, probably something is wrong with p2p connection, 919 // so we just print a log entry to document this sad fact 920 if err != nil { 921 log.Error("Error while reporting error response", "err", err, "peerID", peerID.String()) 922 } 923 } 924 925 func extractBloomFromEncodedEnvelope(rawValue rlp.RawValue) ([]byte, error) { 926 var envelope wakucommon.Envelope 927 decodeErr := rlp.DecodeBytes(rawValue, &envelope) 928 if decodeErr != nil { 929 return nil, decodeErr 930 } 931 return envelope.Bloom(), nil 932 } 933 934 // checkMsgSignature returns an error in case the message is not correctly signed. 935 func checkMsgSignature(reqSrc *ecdsa.PublicKey, id []byte) error { 936 src := crypto.FromECDSAPub(reqSrc) 937 if len(src)-len(id) == 1 { 938 src = src[1:] 939 } 940 941 // if you want to check the signature, you can do it here. e.g.: 942 // if !bytes.Equal(peerID, src) { 943 if src == nil { 944 return errors.New("wrong signature of p2p request") 945 } 946 947 return nil 948 }