github.com/status-im/status-go@v1.1.0/waku/v0/peer.go (about) 1 package v0 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "math" 10 "net" 11 "sync" 12 "time" 13 14 "go.uber.org/zap" 15 16 mapset "github.com/deckarep/golang-set" 17 18 gethcommon "github.com/ethereum/go-ethereum/common" 19 "github.com/ethereum/go-ethereum/crypto" 20 "github.com/ethereum/go-ethereum/p2p" 21 "github.com/ethereum/go-ethereum/p2p/enode" 22 "github.com/ethereum/go-ethereum/rlp" 23 "github.com/status-im/status-go/eth-node/types" 24 25 "github.com/status-im/status-go/waku/common" 26 ) 27 28 // Peer is the implementation of the Peer interface and represents a remote Waku client with which the local host Waku 29 // instance exchanges data / messages. 30 type Peer struct { 31 host common.WakuHost 32 rw p2p.MsgReadWriter 33 p2pPeer *p2p.Peer 34 logger *zap.Logger 35 36 quit chan struct{} 37 38 trusted bool 39 powRequirement float64 40 // bloomMu is to allow thread safe access to 41 // the bloom filter 42 bloomMu sync.Mutex 43 bloomFilter []byte 44 // topicInterestMu is to allow thread safe access to 45 // the map of topic interests 46 topicInterestMu sync.Mutex 47 topicInterest map[common.TopicType]bool 48 // fullNode is used to indicate that the node will be accepting any 49 // envelope. The opposite is an "empty node" , which is when 50 // a bloom filter is all 0s or topic interest is an empty map (not nil). 51 // In that case no envelope is accepted. 52 fullNode bool 53 confirmationsEnabled bool 54 rateLimitsMu sync.Mutex 55 rateLimits common.RateLimits 56 57 stats *common.StatsTracker 58 59 known mapset.Set // Messages already known by the peer to avoid wasting bandwidth 60 } 61 62 func NewPeer(host common.WakuHost, p2pPeer *p2p.Peer, rw p2p.MsgReadWriter, logger *zap.Logger, stats *common.StatsTracker) common.Peer { 63 if logger == nil { 64 logger = zap.NewNop() 65 } 66 67 return &Peer{ 68 host: host, 69 p2pPeer: p2pPeer, 70 logger: logger, 71 rw: rw, 72 trusted: false, 73 powRequirement: 0.0, 74 known: mapset.NewSet(), 75 quit: make(chan struct{}), 76 bloomFilter: common.MakeFullNodeBloom(), 77 fullNode: true, 78 stats: stats, 79 } 80 } 81 82 func (p *Peer) Start() error { 83 if err := p.handshake(); err != nil { 84 return err 85 } 86 go p.update() 87 p.logger.Debug("starting peer", zap.String("peerID", types.EncodeHex(p.ID()))) 88 return nil 89 } 90 91 func (p *Peer) Stop() { 92 close(p.quit) 93 p.logger.Debug("stopping peer", zap.String("peerID", types.EncodeHex(p.ID()))) 94 } 95 96 func (p *Peer) NotifyAboutPowRequirementChange(pow float64) error { 97 i := math.Float64bits(pow) 98 return p2p.Send(p.rw, statusUpdateCode, StatusOptions{PoWRequirement: &i}) 99 } 100 101 func (p *Peer) NotifyAboutBloomFilterChange(bloom []byte) error { 102 return p2p.Send(p.rw, statusUpdateCode, StatusOptions{BloomFilter: bloom}) 103 } 104 105 func (p *Peer) NotifyAboutTopicInterestChange(topics []common.TopicType) error { 106 return p2p.Send(p.rw, statusUpdateCode, StatusOptions{TopicInterest: topics}) 107 } 108 109 func (p *Peer) SetPeerTrusted(trusted bool) { 110 p.trusted = trusted 111 } 112 113 func (p *Peer) RequestHistoricMessages(envelope *common.Envelope) error { 114 return p2p.Send(p.rw, p2pRequestCode, envelope) 115 } 116 117 func (p *Peer) SendHistoricMessageResponse(payload []byte) error { 118 size, r, err := rlp.EncodeToReader(payload) 119 if err != nil { 120 return err 121 } 122 123 return p.rw.WriteMsg(p2p.Msg{Code: p2pRequestCompleteCode, Size: uint32(size), Payload: r}) 124 125 } 126 127 func (p *Peer) SendP2PMessages(envelopes []*common.Envelope) error { 128 return p2p.Send(p.rw, p2pMessageCode, envelopes) 129 } 130 131 func (p *Peer) SendRawP2PDirect(envelopes []rlp.RawValue) error { 132 return p2p.Send(p.rw, p2pMessageCode, envelopes) 133 } 134 135 func (p *Peer) SetRWWriter(rw p2p.MsgReadWriter) { 136 p.rw = rw 137 } 138 139 // Mark marks an envelope known to the peer so that it won't be sent back. 140 func (p *Peer) Mark(envelope *common.Envelope) { 141 p.known.Add(envelope.Hash()) 142 } 143 144 // Marked checks if an envelope is already known to the remote peer. 145 func (p *Peer) Marked(envelope *common.Envelope) bool { 146 return p.known.Contains(envelope.Hash()) 147 } 148 149 func (p *Peer) BloomFilter() []byte { 150 p.bloomMu.Lock() 151 defer p.bloomMu.Unlock() 152 153 bloomFilterCopy := make([]byte, len(p.bloomFilter)) 154 copy(bloomFilterCopy, p.bloomFilter) 155 return bloomFilterCopy 156 } 157 158 func (p *Peer) PoWRequirement() float64 { 159 return p.powRequirement 160 } 161 162 func (p *Peer) ConfirmationsEnabled() bool { 163 return p.confirmationsEnabled 164 } 165 166 // ID returns a peer's id 167 func (p *Peer) ID() []byte { 168 id := p.p2pPeer.ID() 169 return id[:] 170 } 171 172 func (p *Peer) EnodeID() enode.ID { 173 return p.p2pPeer.ID() 174 } 175 176 func (p *Peer) IP() net.IP { 177 return p.p2pPeer.Node().IP() 178 } 179 180 func (p *Peer) Run() error { 181 logger := p.logger.Named("Run") 182 183 for { 184 // fetch the next packet 185 packet, err := p.rw.ReadMsg() 186 if err != nil { 187 logger.Info("failed to read a message", zap.String("peerID", types.EncodeHex(p.ID())), zap.Error(err)) 188 return err 189 } 190 191 if packet.Size > p.host.MaxMessageSize() { 192 logger.Warn("oversize message received", zap.String("peerID", types.EncodeHex(p.ID())), zap.Uint32("size", packet.Size)) 193 return errors.New("oversize message received") 194 } 195 196 if err := p.handlePacket(packet); err != nil { 197 logger.Warn("failed to handle packet message, peer will be disconnected", zap.String("peerID", types.EncodeHex(p.ID())), zap.Error(err)) 198 } 199 _ = packet.Discard() 200 } 201 } 202 203 func (p *Peer) handlePacket(packet p2p.Msg) error { 204 switch packet.Code { 205 case messagesCode: 206 if err := p.handleMessagesCode(packet); err != nil { 207 p.logger.Warn("failed to handle messagesCode message, peer will be disconnected", zap.String("peerID", types.EncodeHex(p.ID())), zap.Error(err)) 208 return err 209 } 210 case messageResponseCode: 211 if err := p.handleMessageResponseCode(packet); err != nil { 212 p.logger.Warn("failed to handle messageResponseCode message, peer will be disconnected", zap.String("peerID", types.EncodeHex(p.ID())), zap.Error(err)) 213 return err 214 } 215 case batchAcknowledgedCode: 216 if err := p.handleBatchAcknowledgeCode(packet); err != nil { 217 p.logger.Warn("failed to handle batchAcknowledgedCode message, peer will be disconnected", zap.String("peerID", types.EncodeHex(p.ID())), zap.Error(err)) 218 return err 219 } 220 case statusUpdateCode: 221 if err := p.handleStatusUpdateCode(packet); err != nil { 222 p.logger.Warn("failed to decode status update message, peer will be disconnected", zap.String("peerID", types.EncodeHex(p.ID())), zap.Error(err)) 223 return err 224 } 225 case p2pMessageCode: 226 if err := p.handleP2PMessageCode(packet); err != nil { 227 p.logger.Warn("failed to decode direct message, peer will be disconnected", zap.String("peerID", types.EncodeHex(p.ID())), zap.Error(err)) 228 return err 229 } 230 case p2pRequestCode: 231 if err := p.handleP2PRequestCode(packet); err != nil { 232 p.logger.Warn("failed to decode p2p request message, peer will be disconnected", zap.String("peerID", types.EncodeHex(p.ID())), zap.Error(err)) 233 return err 234 } 235 case p2pRequestCompleteCode: 236 if err := p.handleP2PRequestCompleteCode(packet); err != nil { 237 p.logger.Warn("failed to decode p2p request complete message, peer will be disconnected", zap.String("peerID", types.EncodeHex(p.ID())), zap.Error(err)) 238 return err 239 } 240 default: 241 // New message common might be implemented in the future versions of Waku. 242 // For forward compatibility, just ignore. 243 p.logger.Debug("ignored packet with message code", zap.Uint64("code", packet.Code)) 244 } 245 246 return nil 247 } 248 249 func (p *Peer) handleMessagesCode(packet p2p.Msg) error { 250 // decode the contained envelopes 251 data, err := ioutil.ReadAll(packet.Payload) 252 if err != nil { 253 common.EnvelopesRejectedCounter.WithLabelValues("failed_read").Inc() 254 return fmt.Errorf("failed to read packet payload: %v", err) 255 } 256 257 var envelopes []*common.Envelope 258 if err := rlp.DecodeBytes(data, &envelopes); err != nil { 259 common.EnvelopesRejectedCounter.WithLabelValues("invalid_data").Inc() 260 return fmt.Errorf("invalid payload: %v", err) 261 } 262 263 envelopeErrors, err := p.host.OnNewEnvelopes(envelopes, p) 264 265 if p.host.ConfirmationsEnabled() { 266 go p.sendConfirmation(data, envelopeErrors) // nolint: errcheck 267 } 268 269 return err 270 } 271 272 func (p *Peer) handleMessageResponseCode(packet p2p.Msg) error { 273 var resp MultiVersionResponse 274 if err := packet.Decode(&resp); err != nil { 275 common.EnvelopesRejectedCounter.WithLabelValues("failed_read").Inc() 276 return fmt.Errorf("invalid response message: %v", err) 277 } 278 if resp.Version != 1 { 279 p.logger.Info("received unsupported version of MultiVersionResponse for messageResponseCode packet", zap.Uint("version", resp.Version)) 280 return nil 281 } 282 283 response, err := resp.DecodeResponse1() 284 if err != nil { 285 common.EnvelopesRejectedCounter.WithLabelValues("invalid_data").Inc() 286 return fmt.Errorf("failed to decode response message: %v", err) 287 } 288 289 return p.host.OnMessagesResponse(response, p) 290 } 291 292 func (p *Peer) handleP2PRequestCode(packet p2p.Msg) error { 293 // Must be processed if mail server is implemented. Otherwise ignore. 294 if !p.host.Mailserver() { 295 return nil 296 } 297 298 // Read all data as we will try to decode it possibly twice. 299 data, err := ioutil.ReadAll(packet.Payload) 300 if err != nil { 301 return fmt.Errorf("invalid p2p request messages: %v", err) 302 } 303 r := bytes.NewReader(data) 304 packet.Payload = r 305 306 var requestDeprecated common.Envelope 307 errDepReq := packet.Decode(&requestDeprecated) 308 if errDepReq == nil { 309 return p.host.OnDeprecatedMessagesRequest(&requestDeprecated, p) 310 } 311 p.logger.Info("failed to decode p2p request message (deprecated)", zap.String("peerID", types.EncodeHex(p.ID())), zap.Error(errDepReq)) 312 313 // As we failed to decode the request, let's set the offset 314 // to the beginning and try decode it again. 315 if _, err := r.Seek(0, io.SeekStart); err != nil { 316 return fmt.Errorf("invalid p2p request message: %v", err) 317 } 318 319 var request common.MessagesRequest 320 errReq := packet.Decode(&request) 321 if errReq == nil { 322 return p.host.OnMessagesRequest(request, p) 323 } 324 p.logger.Info("failed to decode p2p request message", zap.String("peerID", types.EncodeHex(p.ID())), zap.Error(errReq)) 325 326 return errors.New("invalid p2p request message") 327 } 328 329 func (p *Peer) handleBatchAcknowledgeCode(packet p2p.Msg) error { 330 var batchHash gethcommon.Hash 331 if err := packet.Decode(&batchHash); err != nil { 332 return fmt.Errorf("invalid batch ack message: %v", err) 333 } 334 return p.host.OnBatchAcknowledged(batchHash, p) 335 } 336 337 func (p *Peer) handleStatusUpdateCode(packet p2p.Msg) error { 338 var StatusOptions StatusOptions 339 err := packet.Decode(&StatusOptions) 340 if err != nil { 341 p.logger.Error("failed to decode status-options", zap.Error(err)) 342 common.EnvelopesRejectedCounter.WithLabelValues("invalid_settings_changed").Inc() 343 return err 344 } 345 346 return p.setOptions(StatusOptions) 347 348 } 349 350 func (p *Peer) handleP2PMessageCode(packet p2p.Msg) error { 351 // peer-to-peer message, sent directly to peer bypassing PoW checks, etc. 352 // this message is not supposed to be forwarded to other peers, and 353 // therefore might not satisfy the PoW, expiry and other requirements. 354 // these messages are only accepted from the trusted peer. 355 if !p.trusted { 356 return nil 357 } 358 359 var ( 360 envelopes []*common.Envelope 361 err error 362 ) 363 364 if err = packet.Decode(&envelopes); err != nil { 365 return fmt.Errorf("invalid direct message payload: %v", err) 366 } 367 368 return p.host.OnNewP2PEnvelopes(envelopes) 369 } 370 371 func (p *Peer) handleP2PRequestCompleteCode(packet p2p.Msg) error { 372 if !p.trusted { 373 return nil 374 } 375 376 var payload []byte 377 if err := packet.Decode(&payload); err != nil { 378 return fmt.Errorf("invalid p2p request complete message: %v", err) 379 } 380 return p.host.OnP2PRequestCompleted(payload, p) 381 } 382 383 // sendConfirmation sends messageResponseCode and batchAcknowledgedCode messages. 384 func (p *Peer) sendConfirmation(data []byte, envelopeErrors []common.EnvelopeError) (err error) { 385 batchHash := crypto.Keccak256Hash(data) 386 err = p2p.Send(p.rw, messageResponseCode, NewMessagesResponse(batchHash, envelopeErrors)) 387 if err != nil { 388 return 389 } 390 err = p2p.Send(p.rw, batchAcknowledgedCode, batchHash) // DEPRECATED 391 return 392 } 393 394 // handshake sends the protocol initiation status message to the remote peer and 395 // verifies the remote status too. 396 func (p *Peer) handshake() error { 397 // Send the handshake status message asynchronously 398 errc := make(chan error, 1) 399 opts := StatusOptionsFromHost(p.host) 400 go func() { 401 errc <- p2p.SendItems(p.rw, statusCode, Version, opts) 402 }() 403 404 // Fetch the remote status packet and verify protocol match 405 packet, err := p.rw.ReadMsg() 406 if err != nil { 407 return err 408 } 409 if packet.Code != statusCode { 410 return fmt.Errorf("p [%x] sent packet %x before status packet", p.ID(), packet.Code) 411 } 412 413 var ( 414 peerProtocolVersion uint64 415 peerOptions StatusOptions 416 ) 417 s := rlp.NewStream(packet.Payload, uint64(packet.Size)) 418 if _, err := s.List(); err != nil { 419 return fmt.Errorf("p [%x]: failed to decode status packet: %v", p.ID(), err) 420 } 421 // Validate protocol version. 422 if err := s.Decode(&peerProtocolVersion); err != nil { 423 return fmt.Errorf("p [%x]: failed to decode peer protocol version: %v", p.ID(), err) 424 } 425 if peerProtocolVersion != Version { 426 return fmt.Errorf("p [%x]: protocol version mismatch %d != %d", p.ID(), peerProtocolVersion, Version) 427 } 428 // Decode and validate other status packet options. 429 if err := s.Decode(&peerOptions); err != nil { 430 return fmt.Errorf("p [%x]: failed to decode status options: %v", p.ID(), err) 431 } 432 if err := s.ListEnd(); err != nil { 433 return fmt.Errorf("p [%x]: failed to decode status packet: %v", p.ID(), err) 434 } 435 if err := p.setOptions(peerOptions.WithDefaults()); err != nil { 436 return fmt.Errorf("p [%x]: failed to set options: %v", p.ID(), err) 437 } 438 if err := <-errc; err != nil { 439 return fmt.Errorf("p [%x] failed to send status packet: %v", p.ID(), err) 440 } 441 return nil 442 } 443 444 // update executes periodic operations on the peer, including message transmission 445 // and expiration. 446 func (p *Peer) update() { 447 // Start the tickers for the updates 448 expire := time.NewTicker(common.ExpirationCycle) 449 transmit := time.NewTicker(common.TransmissionCycle) 450 451 // Loop and transmit until termination is requested 452 for { 453 select { 454 case <-expire.C: 455 p.expire() 456 457 case <-transmit.C: 458 if err := p.broadcast(); err != nil { 459 p.logger.Debug("broadcasting failed", zap.String("peerID", types.EncodeHex(p.ID())), zap.Error(err)) 460 return 461 } 462 463 case <-p.quit: 464 return 465 } 466 } 467 } 468 469 func (p *Peer) setOptions(peerOptions StatusOptions) error { 470 471 p.logger.Debug("settings options", zap.String("peerID", types.EncodeHex(p.ID())), zap.Any("Options", peerOptions)) 472 473 if err := peerOptions.Validate(); err != nil { 474 return fmt.Errorf("p [%x]: sent invalid options: %v", p.ID(), err) 475 } 476 // Validate and save peer's PoW. 477 pow := peerOptions.PoWRequirementF() 478 if pow != nil { 479 if math.IsInf(*pow, 0) || math.IsNaN(*pow) || *pow < 0.0 { 480 return fmt.Errorf("p [%x]: sent bad status message: invalid pow", p.ID()) 481 } 482 p.powRequirement = *pow 483 } 484 485 if peerOptions.TopicInterest != nil { 486 p.setTopicInterest(peerOptions.TopicInterest) 487 } else if peerOptions.BloomFilter != nil { 488 // Validate and save peer's bloom filters. 489 bloom := peerOptions.BloomFilter 490 bloomSize := len(bloom) 491 if bloomSize != 0 && bloomSize != common.BloomFilterSize { 492 return fmt.Errorf("p [%x] sent bad status message: wrong bloom filter size %d", p.ID(), bloomSize) 493 } 494 p.setBloomFilter(bloom) 495 } 496 497 if peerOptions.LightNodeEnabled != nil { 498 // Validate and save other peer's options. 499 if *peerOptions.LightNodeEnabled && p.host.LightClientMode() && p.host.LightClientModeConnectionRestricted() { 500 return fmt.Errorf("p [%x] is useless: two light client communication restricted", p.ID()) 501 } 502 } 503 if peerOptions.ConfirmationsEnabled != nil { 504 p.confirmationsEnabled = *peerOptions.ConfirmationsEnabled 505 } 506 if peerOptions.RateLimits != nil { 507 p.setRateLimits(*peerOptions.RateLimits) 508 } 509 510 return nil 511 } 512 513 // expire iterates over all the known envelopes in the host and removes all 514 // expired (unknown) ones from the known list. 515 func (p *Peer) expire() { 516 unmark := make(map[gethcommon.Hash]struct{}) 517 p.known.Each(func(v interface{}) bool { 518 if !p.host.IsEnvelopeCached(v.(gethcommon.Hash)) { 519 unmark[v.(gethcommon.Hash)] = struct{}{} 520 } 521 return true 522 }) 523 // Dump all known but no longer cached 524 for hash := range unmark { 525 p.known.Remove(hash) 526 } 527 } 528 529 // broadcast iterates over the collection of envelopes and transmits yet unknown 530 // ones over the network. 531 func (p *Peer) broadcast() error { 532 envelopes := p.host.Envelopes() 533 bundle := make([]*common.Envelope, 0, len(envelopes)) 534 for _, envelope := range envelopes { 535 if !p.Marked(envelope) && envelope.PoW() >= p.powRequirement && p.topicOrBloomMatch(envelope) { 536 bundle = append(bundle, envelope) 537 } 538 } 539 540 if len(bundle) == 0 { 541 return nil 542 } 543 544 batchHash, err := p.SendBundle(bundle) 545 if err != nil { 546 p.logger.Debug("failed to deliver envelopes", zap.String("peerID", types.EncodeHex(p.ID())), zap.Error(err)) 547 return err 548 } 549 550 // mark envelopes only if they were successfully sent 551 for _, e := range bundle { 552 p.Mark(e) 553 event := common.EnvelopeEvent{ 554 Event: common.EventEnvelopeSent, 555 Hash: e.Hash(), 556 Peer: p.EnodeID(), 557 } 558 if p.confirmationsEnabled { 559 event.Batch = batchHash 560 } 561 p.host.SendEnvelopeEvent(event) 562 } 563 p.logger.Debug("broadcasted bundles successfully", zap.String("peerID", types.EncodeHex(p.ID())), zap.Int("count", len(bundle))) 564 return nil 565 } 566 567 func (p *Peer) SendBundle(bundle []*common.Envelope) (rst gethcommon.Hash, err error) { 568 data, err := rlp.EncodeToBytes(bundle) 569 if err != nil { 570 return 571 } 572 err = p.rw.WriteMsg(p2p.Msg{ 573 Code: messagesCode, 574 Size: uint32(len(data)), 575 Payload: bytes.NewBuffer(data), 576 }) 577 if err != nil { 578 return 579 } 580 return crypto.Keccak256Hash(data), nil 581 } 582 583 func (p *Peer) setBloomFilter(bloom []byte) { 584 p.bloomMu.Lock() 585 defer p.bloomMu.Unlock() 586 p.bloomFilter = bloom 587 p.fullNode = common.IsFullNode(bloom) 588 if p.fullNode && p.bloomFilter == nil { 589 p.bloomFilter = common.MakeFullNodeBloom() 590 } 591 p.topicInterest = nil 592 } 593 594 func (p *Peer) setTopicInterest(topicInterest []common.TopicType) { 595 p.topicInterestMu.Lock() 596 defer p.topicInterestMu.Unlock() 597 if topicInterest == nil { 598 p.topicInterest = nil 599 return 600 } 601 p.topicInterest = make(map[common.TopicType]bool) 602 for _, topic := range topicInterest { 603 p.topicInterest[topic] = true 604 } 605 p.fullNode = false 606 p.bloomFilter = nil 607 } 608 609 func (p *Peer) setRateLimits(r common.RateLimits) { 610 p.rateLimitsMu.Lock() 611 p.rateLimits = r 612 p.rateLimitsMu.Unlock() 613 } 614 615 // topicOrBloomMatch matches against topic-interest if topic interest 616 // is not nil. Otherwise it will match against the bloom-filter. 617 // If the bloom-filter is nil, or full, the node is considered a full-node 618 // and any envelope will be accepted. An empty topic-interest (but not nil) 619 // signals that we are not interested in any envelope. 620 func (p *Peer) topicOrBloomMatch(env *common.Envelope) bool { 621 p.topicInterestMu.Lock() 622 topicInterestMode := p.topicInterest != nil 623 p.topicInterestMu.Unlock() 624 625 if topicInterestMode { 626 return p.topicInterestMatch(env) 627 } 628 return p.bloomMatch(env) 629 } 630 631 func (p *Peer) topicInterestMatch(env *common.Envelope) bool { 632 p.topicInterestMu.Lock() 633 defer p.topicInterestMu.Unlock() 634 635 if p.topicInterest == nil { 636 return false 637 } 638 639 return p.topicInterest[env.Topic] 640 } 641 642 func (p *Peer) bloomMatch(env *common.Envelope) bool { 643 p.bloomMu.Lock() 644 defer p.bloomMu.Unlock() 645 return p.fullNode || common.BloomFilterMatch(p.bloomFilter, env.Bloom()) 646 }