github.com/klaytn/klaytn@v1.12.1/node/cn/peer_set.go (about) 1 // Modifications Copyright 2019 The klaytn Authors 2 // Copyright 2015 The go-ethereum Authors 3 // This file is part of go-ethereum. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from eth/peer.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package cn 22 23 import ( 24 "errors" 25 "fmt" 26 "math/big" 27 "sync" 28 "time" 29 30 "github.com/klaytn/klaytn/blockchain/types" 31 "github.com/klaytn/klaytn/common" 32 "github.com/klaytn/klaytn/consensus/istanbul/backend" 33 "github.com/klaytn/klaytn/networks/p2p" 34 "github.com/klaytn/klaytn/node/cn/snap" 35 ) 36 37 var ( 38 // errPeerAlreadyRegistered is returned if a peer is attempted to be added 39 // to the peer set, but one with the same id already exists. 40 errPeerAlreadyRegistered = errors.New("peer already registered") 41 42 // errSnapWithoutIstanbul is returned if a peer attempts to connect only on the 43 // snap protocol without advertizing the istanbul main protocol. 44 errSnapWithoutIstanbul = errors.New("peer connected on snap without compatible istanbul support") 45 ) 46 47 //go:generate mockgen -destination=node/cn/peer_set_mock_test.go -package=cn github.com/klaytn/klaytn/node/cn PeerSet 48 type PeerSet interface { 49 Register(p Peer, ext *snap.Peer) error 50 Unregister(id string) error 51 52 Peers() map[string]Peer 53 CNPeers() map[common.Address]Peer 54 ENPeers() map[common.Address]Peer 55 PNPeers() map[common.Address]Peer 56 Peer(id string) Peer 57 Len() int 58 SnapLen() int 59 60 PeersWithoutBlock(hash common.Hash) []Peer 61 62 SamplePeersToSendBlock(block *types.Block, nodeType common.ConnType) []Peer 63 SampleResendPeersByType(nodeType common.ConnType) []Peer 64 65 PeersWithoutTx(hash common.Hash) []Peer 66 TypePeersWithoutTx(hash common.Hash, nodetype common.ConnType) []Peer 67 CNWithoutTx(hash common.Hash) []Peer 68 UpdateTypePeersWithoutTxs(tx *types.Transaction, nodeType common.ConnType, peersWithoutTxsMap map[Peer]types.Transactions) 69 70 RegisterSnapExtension(peer *snap.Peer) error 71 WaitSnapExtension(peer Peer) (*snap.Peer, error) 72 73 BestPeer() Peer 74 RegisterValidator(connType common.ConnType, validator p2p.PeerTypeValidator) 75 Close() 76 } 77 78 // peerSet represents the collection of active peers currently participating in 79 // the Klaytn sub-protocol. 80 type peerSet struct { 81 peers map[string]Peer 82 cnpeers map[common.Address]Peer 83 pnpeers map[common.Address]Peer 84 enpeers map[common.Address]Peer 85 86 snapPeers int // Number of `snap` compatible peers for connection prioritization 87 snapWait map[string]chan *snap.Peer // Peers connected on `eth` waiting for their snap extension 88 snapPend map[string]*snap.Peer // Peers connected on the `snap` protocol, but not yet on `eth` 89 90 lock sync.RWMutex 91 closed bool 92 93 validator map[common.ConnType]p2p.PeerTypeValidator 94 } 95 96 // newPeerSet creates a new peer set to track the active participants. 97 func newPeerSet() *peerSet { 98 peerSet := &peerSet{ 99 peers: make(map[string]Peer), 100 cnpeers: make(map[common.Address]Peer), 101 pnpeers: make(map[common.Address]Peer), 102 enpeers: make(map[common.Address]Peer), 103 snapWait: make(map[string]chan *snap.Peer), 104 snapPend: make(map[string]*snap.Peer), 105 validator: make(map[common.ConnType]p2p.PeerTypeValidator), 106 } 107 108 peerSet.validator[common.CONSENSUSNODE] = ByPassValidator{} 109 peerSet.validator[common.PROXYNODE] = ByPassValidator{} 110 peerSet.validator[common.ENDPOINTNODE] = ByPassValidator{} 111 112 return peerSet 113 } 114 115 // Register injects a new peer into the working set, or returns an error if the 116 // peer is already known. 117 func (ps *peerSet) Register(p Peer, ext *snap.Peer) error { 118 ps.lock.Lock() 119 defer ps.lock.Unlock() 120 121 if ps.closed { 122 return errClosed 123 } 124 if _, ok := ps.peers[p.GetID()]; ok { 125 return errAlreadyRegistered 126 } 127 128 var peersByNodeType map[common.Address]Peer 129 var peerTypeValidator p2p.PeerTypeValidator 130 131 switch p.ConnType() { 132 case common.CONSENSUSNODE: 133 peersByNodeType = ps.cnpeers 134 peerTypeValidator = ps.validator[common.CONSENSUSNODE] 135 case common.PROXYNODE: 136 peersByNodeType = ps.pnpeers 137 peerTypeValidator = ps.validator[common.PROXYNODE] 138 case common.ENDPOINTNODE: 139 peersByNodeType = ps.enpeers 140 peerTypeValidator = ps.validator[common.ENDPOINTNODE] 141 default: 142 return fmt.Errorf("undefined peer type entered, p.ConnType(): %v", p.ConnType()) 143 } 144 145 if _, ok := peersByNodeType[p.GetAddr()]; ok { 146 return errAlreadyRegistered 147 } 148 149 if err := peerTypeValidator.ValidatePeerType(p.GetAddr()); err != nil { 150 return fmt.Errorf("fail to validate peer type: %s", err) 151 } 152 153 if ext != nil { 154 p.AddSnapExtension(ext) 155 ps.snapPeers++ 156 } 157 158 peersByNodeType[p.GetAddr()] = p // add peer to its node type peer map. 159 ps.peers[p.GetID()] = p // add peer to entire peer map. 160 161 cnPeerCountGauge.Update(int64(len(ps.cnpeers))) 162 pnPeerCountGauge.Update(int64(len(ps.pnpeers))) 163 enPeerCountGauge.Update(int64(len(ps.enpeers))) 164 go p.Broadcast() 165 166 return nil 167 } 168 169 // Unregister removes a remote peer from the active set, disabling any further 170 // actions to/from that particular entity. 171 func (ps *peerSet) Unregister(id string) error { 172 ps.lock.Lock() 173 defer ps.lock.Unlock() 174 175 p, ok := ps.peers[id] 176 if !ok { 177 return errNotRegistered 178 } 179 delete(ps.peers, id) 180 p.Close() 181 182 switch p.ConnType() { 183 case common.CONSENSUSNODE: 184 delete(ps.cnpeers, p.GetAddr()) 185 case common.PROXYNODE: 186 delete(ps.pnpeers, p.GetAddr()) 187 case common.ENDPOINTNODE: 188 delete(ps.enpeers, p.GetAddr()) 189 default: 190 return errUnexpectedNodeType 191 } 192 193 if p.ExistSnapExtension() { 194 ps.snapPeers-- 195 } 196 197 cnPeerCountGauge.Update(int64(len(ps.cnpeers))) 198 pnPeerCountGauge.Update(int64(len(ps.pnpeers))) 199 enPeerCountGauge.Update(int64(len(ps.enpeers))) 200 return nil 201 } 202 203 func (ps *peerSet) Peers() map[string]Peer { 204 ps.lock.RLock() 205 defer ps.lock.RUnlock() 206 207 set := make(map[string]Peer) 208 for id, p := range ps.peers { 209 set[id] = p 210 } 211 return set 212 } 213 214 func (ps *peerSet) CNPeers() map[common.Address]Peer { 215 ps.lock.RLock() 216 defer ps.lock.RUnlock() 217 218 set := make(map[common.Address]Peer) 219 for addr, p := range ps.cnpeers { 220 set[addr] = p 221 } 222 return set 223 } 224 225 func (ps *peerSet) ENPeers() map[common.Address]Peer { 226 ps.lock.RLock() 227 defer ps.lock.RUnlock() 228 229 set := make(map[common.Address]Peer) 230 for addr, p := range ps.enpeers { 231 set[addr] = p 232 } 233 return set 234 } 235 236 func (ps *peerSet) PNPeers() map[common.Address]Peer { 237 ps.lock.RLock() 238 defer ps.lock.RUnlock() 239 240 set := make(map[common.Address]Peer) 241 for addr, p := range ps.pnpeers { 242 set[addr] = p 243 } 244 return set 245 } 246 247 // Peer retrieves the registered peer with the given id. 248 func (ps *peerSet) Peer(id string) Peer { 249 ps.lock.RLock() 250 defer ps.lock.RUnlock() 251 252 return ps.peers[id] 253 } 254 255 // Len returns if the current number of peers in the set. 256 func (ps *peerSet) Len() int { 257 ps.lock.RLock() 258 defer ps.lock.RUnlock() 259 260 return len(ps.peers) 261 } 262 263 // SnapLen returns if the current number of `snap` peers in the set. 264 func (ps *peerSet) SnapLen() int { 265 ps.lock.RLock() 266 defer ps.lock.RUnlock() 267 268 return ps.snapPeers 269 } 270 271 // PeersWithoutBlock retrieves a list of peers that do not have a given block in 272 // their set of known hashes. 273 func (ps *peerSet) PeersWithoutBlock(hash common.Hash) []Peer { 274 ps.lock.RLock() 275 defer ps.lock.RUnlock() 276 277 list := make([]Peer, 0, len(ps.peers)) 278 for _, p := range ps.peers { 279 if !p.KnowsBlock(hash) { 280 list = append(list, p) 281 } 282 } 283 return list 284 } 285 286 func (ps *peerSet) typePeersWithoutBlock(hash common.Hash, nodetype common.ConnType) []Peer { 287 ps.lock.RLock() 288 defer ps.lock.RUnlock() 289 290 list := make([]Peer, 0, len(ps.peers)) 291 for _, p := range ps.peers { 292 if p.ConnType() == nodetype && !p.KnowsBlock(hash) { 293 list = append(list, p) 294 } 295 } 296 return list 297 } 298 299 func (ps *peerSet) PeersWithoutBlockExceptCN(hash common.Hash) []Peer { 300 ps.lock.RLock() 301 defer ps.lock.RUnlock() 302 303 list := make([]Peer, 0, len(ps.peers)) 304 for _, p := range ps.peers { 305 if p.ConnType() != common.CONSENSUSNODE && !p.KnowsBlock(hash) { 306 list = append(list, p) 307 } 308 } 309 return list 310 } 311 312 func (ps *peerSet) CNWithoutBlock(hash common.Hash) []Peer { 313 ps.lock.RLock() 314 defer ps.lock.RUnlock() 315 316 list := make([]Peer, 0, len(ps.cnpeers)) 317 for _, p := range ps.cnpeers { 318 if !p.KnowsBlock(hash) { 319 list = append(list, p) 320 } 321 } 322 return list 323 } 324 325 func (ps *peerSet) PNWithoutBlock(hash common.Hash) []Peer { 326 ps.lock.RLock() 327 defer ps.lock.RUnlock() 328 329 list := make([]Peer, 0, len(ps.pnpeers)) 330 for _, p := range ps.pnpeers { 331 if !p.KnowsBlock(hash) { 332 list = append(list, p) 333 } 334 } 335 return list 336 } 337 338 func (ps *peerSet) ENWithoutBlock(hash common.Hash) []Peer { 339 ps.lock.RLock() 340 defer ps.lock.RUnlock() 341 342 list := make([]Peer, 0, len(ps.enpeers)) 343 for _, p := range ps.enpeers { 344 if !p.KnowsBlock(hash) { 345 list = append(list, p) 346 } 347 } 348 return list 349 } 350 351 func (ps *peerSet) typePeers(nodetype common.ConnType) []Peer { 352 ps.lock.RLock() 353 defer ps.lock.RUnlock() 354 list := make([]Peer, 0, len(ps.peers)) 355 for _, p := range ps.peers { 356 if p.ConnType() == nodetype { 357 list = append(list, p) 358 } 359 } 360 return list 361 } 362 363 // PeersWithoutTx retrieves a list of peers that do not have a given transaction 364 // in their set of known hashes. 365 func (ps *peerSet) PeersWithoutTx(hash common.Hash) []Peer { 366 ps.lock.RLock() 367 defer ps.lock.RUnlock() 368 369 list := make([]Peer, 0, len(ps.peers)) 370 for _, p := range ps.peers { 371 if !p.KnowsTx(hash) { 372 list = append(list, p) 373 } 374 } 375 return list 376 } 377 378 func (ps *peerSet) TypePeersWithoutTx(hash common.Hash, nodetype common.ConnType) []Peer { 379 ps.lock.RLock() 380 defer ps.lock.RUnlock() 381 382 list := make([]Peer, 0, len(ps.peers)) 383 for _, p := range ps.peers { 384 if p.ConnType() == nodetype && !p.KnowsTx(hash) { 385 list = append(list, p) 386 } 387 } 388 return list 389 } 390 391 func (ps *peerSet) CNWithoutTx(hash common.Hash) []Peer { 392 ps.lock.RLock() 393 defer ps.lock.RUnlock() 394 395 list := make([]Peer, 0, len(ps.cnpeers)) 396 for _, p := range ps.cnpeers { 397 if !p.KnowsTx(hash) { 398 list = append(list, p) 399 } 400 } 401 return list 402 } 403 404 // BestPeer retrieves the known peer with the currently highest total blockscore. 405 func (ps *peerSet) BestPeer() Peer { 406 ps.lock.RLock() 407 defer ps.lock.RUnlock() 408 409 var ( 410 bestPeer Peer 411 bestBlockScore *big.Int 412 ) 413 for _, p := range ps.peers { 414 if _, currBlockScore := p.Head(); bestPeer == nil || currBlockScore.Cmp(bestBlockScore) > 0 { 415 bestPeer, bestBlockScore = p, currBlockScore 416 } 417 } 418 return bestPeer 419 } 420 421 // RegisterValidator registers a validator. 422 func (ps *peerSet) RegisterValidator(connType common.ConnType, validator p2p.PeerTypeValidator) { 423 ps.validator[connType] = validator 424 } 425 426 // Close disconnects all peers. 427 // No new peers can be registered after Close has returned. 428 func (ps *peerSet) Close() { 429 ps.lock.Lock() 430 defer ps.lock.Unlock() 431 432 for _, p := range ps.peers { 433 p.DisconnectP2PPeer(p2p.DiscQuitting) 434 } 435 ps.closed = true 436 } 437 438 // samplePeersToSendBlock samples peers from peers without block. 439 // It uses different sampling policy for different node type. 440 func (peers *peerSet) SamplePeersToSendBlock(block *types.Block, nodeType common.ConnType) []Peer { 441 var peersWithoutBlock []Peer 442 hash := block.Hash() 443 444 switch nodeType { 445 case common.CONSENSUSNODE: 446 // If currNode is CN, sends block to sampled peers from (CN + PN), not to EN. 447 cnsWithoutBlock := peers.CNWithoutBlock(hash) 448 sampledCNsWithoutBlock := samplingPeers(cnsWithoutBlock, sampleSize(cnsWithoutBlock)) 449 450 // CN always broadcasts a block to its PN peers, unless the number of PN peers exceeds the limit. 451 pnsWithoutBlock := peers.PNWithoutBlock(hash) 452 if len(pnsWithoutBlock) > blockReceivingPNLimit { 453 pnsWithoutBlock = samplingPeers(pnsWithoutBlock, blockReceivingPNLimit) 454 } 455 456 logger.Trace("Propagated block", "hash", hash, 457 "CN recipients", len(sampledCNsWithoutBlock), "PN recipients", len(pnsWithoutBlock), "duration", common.PrettyDuration(time.Since(block.ReceivedAt))) 458 459 return append(cnsWithoutBlock, pnsWithoutBlock...) 460 case common.PROXYNODE: 461 // If currNode is PN, sends block to sampled peers from (PN + EN), not to CN. 462 peersWithoutBlock = peers.PeersWithoutBlockExceptCN(hash) 463 464 case common.ENDPOINTNODE: 465 // If currNode is EN, sends block to sampled EN peers, not to EN nor CN. 466 peersWithoutBlock = peers.ENWithoutBlock(hash) 467 468 default: 469 logger.Error("Undefined nodeType of protocolManager! nodeType: %v", nodeType) 470 return []Peer{} 471 } 472 473 sampledPeersWithoutBlock := samplingPeers(peersWithoutBlock, sampleSize(peersWithoutBlock)) 474 logger.Trace("Propagated block", "hash", hash, 475 "recipients", len(sampledPeersWithoutBlock), "duration", common.PrettyDuration(time.Since(block.ReceivedAt))) 476 477 return sampledPeersWithoutBlock 478 } 479 480 func (peers *peerSet) SampleResendPeersByType(nodeType common.ConnType) []Peer { 481 // TODO-Klaytn Need to tune pickSize. Currently use 2 for availability and efficiency. 482 var sampledPeers []Peer 483 switch nodeType { 484 case common.ENDPOINTNODE: 485 sampledPeers = peers.typePeers(common.CONSENSUSNODE) 486 if len(sampledPeers) < 2 { 487 sampledPeers = append(sampledPeers, samplingPeers(peers.typePeers(common.PROXYNODE), 2-len(sampledPeers))...) 488 } 489 if len(sampledPeers) < 2 { 490 sampledPeers = append(sampledPeers, samplingPeers(peers.typePeers(common.ENDPOINTNODE), 2-len(sampledPeers))...) 491 } 492 sampledPeers = samplingPeers(sampledPeers, 2) 493 case common.PROXYNODE: 494 sampledPeers = peers.typePeers(common.CONSENSUSNODE) 495 if len(sampledPeers) == 0 { 496 sampledPeers = peers.typePeers(common.PROXYNODE) 497 } 498 sampledPeers = samplingPeers(sampledPeers, 2) 499 default: 500 logger.Warn("Not supported nodeType", "nodeType", nodeType) 501 return nil 502 } 503 return sampledPeers 504 } 505 506 func (peers *peerSet) UpdateTypePeersWithoutTxs(tx *types.Transaction, nodeType common.ConnType, peersWithoutTxsMap map[Peer]types.Transactions) { 507 typePeers := peers.TypePeersWithoutTx(tx.Hash(), nodeType) 508 for _, peer := range typePeers { 509 peersWithoutTxsMap[peer] = append(peersWithoutTxsMap[peer], tx) 510 } 511 logger.Trace("Broadcast transaction", "hash", tx.Hash(), "recipients", len(typePeers)) 512 } 513 514 // RegisterSnapExtension unblocks an already connected `klay` peer waiting for its 515 // `snap` extension, or if no such peer exists, tracks the extension for the time 516 // being until the `eth` main protocol starts looking for it. 517 func (peers *peerSet) RegisterSnapExtension(peer *snap.Peer) error { 518 // Reject the peer if it advertises `snap` without `klay` as `snap` is only a 519 // satellite protocol meaningful with the chain selection of `klay` 520 if !peer.RunningCap(backend.IstanbulProtocol.Name, backend.IstanbulProtocol.Versions) { 521 return errSnapWithoutIstanbul 522 } 523 // Ensure nobody can double connect 524 peers.lock.Lock() 525 defer peers.lock.Unlock() 526 527 id := peer.ID() 528 if _, ok := peers.peers[id]; ok { 529 return errPeerAlreadyRegistered // avoid connections with the same id as existing ones 530 } 531 if _, ok := peers.snapPend[id]; ok { 532 return errPeerAlreadyRegistered // avoid connections with the same id as pending ones 533 } 534 // Inject the peer into an `eth` counterpart is available, otherwise save for later 535 if wait, ok := peers.snapWait[id]; ok { 536 delete(peers.snapWait, id) 537 wait <- peer 538 return nil 539 } 540 peers.snapPend[id] = peer 541 return nil 542 } 543 544 // WaitSnapExtension blocks until all satellite protocols are connected and tracked 545 // by the peerset. 546 func (ps *peerSet) WaitSnapExtension(peer Peer) (*snap.Peer, error) { 547 // If the peer does not support a compatible `snap`, don't wait 548 if !peer.RunningCap(snap.ProtocolName, snap.ProtocolVersions) { 549 return nil, nil 550 } 551 // Ensure nobody can double connect 552 wait := make(chan *snap.Peer) 553 snap, err := ps.waitSnapExtension(peer, wait) 554 if err != nil { 555 return nil, err 556 } 557 if snap != nil { 558 return snap, nil 559 } 560 561 return <-wait, nil 562 } 563 564 func (ps *peerSet) waitSnapExtension(peer Peer, wait chan *snap.Peer) (*snap.Peer, error) { 565 ps.lock.Lock() 566 defer ps.lock.Unlock() 567 568 id := peer.GetID() 569 if _, ok := ps.peers[id]; ok { 570 return nil, errPeerAlreadyRegistered // avoid connections with the same id as existing ones 571 } 572 if _, ok := ps.snapWait[id]; ok { 573 return nil, errPeerAlreadyRegistered // avoid connections with the same id as pending ones 574 } 575 // If `snap` already connected, retrieve the peer from the pending set 576 if snap, ok := ps.snapPend[id]; ok { 577 delete(ps.snapPend, id) 578 579 return snap, nil 580 } 581 // Otherwise wait for `snap` to connect concurrently 582 ps.snapWait[id] = wait 583 return nil, nil 584 }