github.com/cryptoecc/eth-ecc@v0.0.3/eth/peer.go (about) 1 // Copyright 2015 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 eth 18 19 import ( 20 "errors" 21 "fmt" 22 "math/big" 23 "sync" 24 "time" 25 26 "github.com/cryptoecc/ETH-ECC/common" 27 "github.com/cryptoecc/ETH-ECC/core/types" 28 "github.com/cryptoecc/ETH-ECC/p2p" 29 "github.com/cryptoecc/ETH-ECC/rlp" 30 mapset "github.com/deckarep/golang-set" 31 ) 32 33 var ( 34 errClosed = errors.New("peer set is closed") 35 errAlreadyRegistered = errors.New("peer is already registered") 36 errNotRegistered = errors.New("peer is not registered") 37 ) 38 39 const ( 40 maxKnownTxs = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS) 41 maxKnownBlocks = 1024 // Maximum block hashes to keep in the known list (prevent DOS) 42 43 // maxQueuedTxs is the maximum number of transaction lists to queue up before 44 // dropping broadcasts. This is a sensitive number as a transaction list might 45 // contain a single transaction, or thousands. 46 maxQueuedTxs = 128 47 48 // maxQueuedProps is the maximum number of block propagations to queue up before 49 // dropping broadcasts. There's not much point in queueing stale blocks, so a few 50 // that might cover uncles should be enough. 51 maxQueuedProps = 4 52 53 // maxQueuedAnns is the maximum number of block announcements to queue up before 54 // dropping broadcasts. Similarly to block propagations, there's no point to queue 55 // above some healthy uncle limit, so use that. 56 maxQueuedAnns = 4 57 58 handshakeTimeout = 5 * time.Second 59 ) 60 61 // PeerInfo represents a short summary of the Ethereum sub-protocol metadata known 62 // about a connected peer. 63 type PeerInfo struct { 64 Version int `json:"version"` // Ethereum protocol version negotiated 65 Difficulty *big.Int `json:"difficulty"` // Total difficulty of the peer's blockchain 66 Head string `json:"head"` // SHA3 hash of the peer's best owned block 67 } 68 69 // propEvent is a block propagation, waiting for its turn in the broadcast queue. 70 type propEvent struct { 71 block *types.Block 72 td *big.Int 73 } 74 75 type peer struct { 76 id string 77 78 *p2p.Peer 79 rw p2p.MsgReadWriter 80 81 version int // Protocol version negotiated 82 syncDrop *time.Timer // Timed connection dropper if sync progress isn't validated in time 83 84 head common.Hash 85 td *big.Int 86 lock sync.RWMutex 87 88 knownTxs mapset.Set // Set of transaction hashes known to be known by this peer 89 knownBlocks mapset.Set // Set of block hashes known to be known by this peer 90 queuedTxs chan []*types.Transaction // Queue of transactions to broadcast to the peer 91 queuedProps chan *propEvent // Queue of blocks to broadcast to the peer 92 queuedAnns chan *types.Block // Queue of blocks to announce to the peer 93 term chan struct{} // Termination channel to stop the broadcaster 94 } 95 96 func newPeer(version int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer { 97 return &peer{ 98 Peer: p, 99 rw: rw, 100 version: version, 101 id: fmt.Sprintf("%x", p.ID().Bytes()[:8]), 102 knownTxs: mapset.NewSet(), 103 knownBlocks: mapset.NewSet(), 104 queuedTxs: make(chan []*types.Transaction, maxQueuedTxs), 105 queuedProps: make(chan *propEvent, maxQueuedProps), 106 queuedAnns: make(chan *types.Block, maxQueuedAnns), 107 term: make(chan struct{}), 108 } 109 } 110 111 // broadcast is a write loop that multiplexes block propagations, announcements 112 // and transaction broadcasts into the remote peer. The goal is to have an async 113 // writer that does not lock up node internals. 114 func (p *peer) broadcast() { 115 for { 116 select { 117 case txs := <-p.queuedTxs: 118 if err := p.SendTransactions(txs); err != nil { 119 return 120 } 121 p.Log().Trace("Broadcast transactions", "count", len(txs)) 122 123 case prop := <-p.queuedProps: 124 if err := p.SendNewBlock(prop.block, prop.td); err != nil { 125 return 126 } 127 p.Log().Trace("Propagated block", "number", prop.block.Number(), "hash", prop.block.Hash(), "td", prop.td) 128 129 case block := <-p.queuedAnns: 130 if err := p.SendNewBlockHashes([]common.Hash{block.Hash()}, []uint64{block.NumberU64()}); err != nil { 131 return 132 } 133 p.Log().Trace("Announced block", "number", block.Number(), "hash", block.Hash()) 134 135 case <-p.term: 136 return 137 } 138 } 139 } 140 141 // close signals the broadcast goroutine to terminate. 142 func (p *peer) close() { 143 close(p.term) 144 } 145 146 // Info gathers and returns a collection of metadata known about a peer. 147 func (p *peer) Info() *PeerInfo { 148 hash, td := p.Head() 149 150 return &PeerInfo{ 151 Version: p.version, 152 Difficulty: td, 153 Head: hash.Hex(), 154 } 155 } 156 157 // Head retrieves a copy of the current head hash and total difficulty of the 158 // peer. 159 func (p *peer) Head() (hash common.Hash, td *big.Int) { 160 p.lock.RLock() 161 defer p.lock.RUnlock() 162 163 copy(hash[:], p.head[:]) 164 return hash, new(big.Int).Set(p.td) 165 } 166 167 // SetHead updates the head hash and total difficulty of the peer. 168 func (p *peer) SetHead(hash common.Hash, td *big.Int) { 169 p.lock.Lock() 170 defer p.lock.Unlock() 171 172 copy(p.head[:], hash[:]) 173 p.td.Set(td) 174 } 175 176 // MarkBlock marks a block as known for the peer, ensuring that the block will 177 // never be propagated to this particular peer. 178 func (p *peer) MarkBlock(hash common.Hash) { 179 // If we reached the memory allowance, drop a previously known block hash 180 for p.knownBlocks.Cardinality() >= maxKnownBlocks { 181 p.knownBlocks.Pop() 182 } 183 p.knownBlocks.Add(hash) 184 } 185 186 // MarkTransaction marks a transaction as known for the peer, ensuring that it 187 // will never be propagated to this particular peer. 188 func (p *peer) MarkTransaction(hash common.Hash) { 189 // If we reached the memory allowance, drop a previously known transaction hash 190 for p.knownTxs.Cardinality() >= maxKnownTxs { 191 p.knownTxs.Pop() 192 } 193 p.knownTxs.Add(hash) 194 } 195 196 // SendTransactions sends transactions to the peer and includes the hashes 197 // in its transaction hash set for future reference. 198 func (p *peer) SendTransactions(txs types.Transactions) error { 199 // Mark all the transactions as known, but ensure we don't overflow our limits 200 for _, tx := range txs { 201 p.knownTxs.Add(tx.Hash()) 202 } 203 for p.knownTxs.Cardinality() >= maxKnownTxs { 204 p.knownTxs.Pop() 205 } 206 return p2p.Send(p.rw, TxMsg, txs) 207 } 208 209 // AsyncSendTransactions queues list of transactions propagation to a remote 210 // peer. If the peer's broadcast queue is full, the event is silently dropped. 211 func (p *peer) AsyncSendTransactions(txs []*types.Transaction) { 212 select { 213 case p.queuedTxs <- txs: 214 // Mark all the transactions as known, but ensure we don't overflow our limits 215 for _, tx := range txs { 216 p.knownTxs.Add(tx.Hash()) 217 } 218 for p.knownTxs.Cardinality() >= maxKnownTxs { 219 p.knownTxs.Pop() 220 } 221 default: 222 p.Log().Debug("Dropping transaction propagation", "count", len(txs)) 223 } 224 } 225 226 // SendNewBlockHashes announces the availability of a number of blocks through 227 // a hash notification. 228 func (p *peer) SendNewBlockHashes(hashes []common.Hash, numbers []uint64) error { 229 // Mark all the block hashes as known, but ensure we don't overflow our limits 230 for _, hash := range hashes { 231 p.knownBlocks.Add(hash) 232 } 233 for p.knownBlocks.Cardinality() >= maxKnownBlocks { 234 p.knownBlocks.Pop() 235 } 236 request := make(newBlockHashesData, len(hashes)) 237 for i := 0; i < len(hashes); i++ { 238 request[i].Hash = hashes[i] 239 request[i].Number = numbers[i] 240 } 241 return p2p.Send(p.rw, NewBlockHashesMsg, request) 242 } 243 244 // AsyncSendNewBlockHash queues the availability of a block for propagation to a 245 // remote peer. If the peer's broadcast queue is full, the event is silently 246 // dropped. 247 func (p *peer) AsyncSendNewBlockHash(block *types.Block) { 248 select { 249 case p.queuedAnns <- block: 250 // Mark all the block hash as known, but ensure we don't overflow our limits 251 p.knownBlocks.Add(block.Hash()) 252 for p.knownBlocks.Cardinality() >= maxKnownBlocks { 253 p.knownBlocks.Pop() 254 } 255 default: 256 p.Log().Debug("Dropping block announcement", "number", block.NumberU64(), "hash", block.Hash()) 257 } 258 } 259 260 // SendNewBlock propagates an entire block to a remote peer. 261 func (p *peer) SendNewBlock(block *types.Block, td *big.Int) error { 262 // Mark all the block hash as known, but ensure we don't overflow our limits 263 p.knownBlocks.Add(block.Hash()) 264 for p.knownBlocks.Cardinality() >= maxKnownBlocks { 265 p.knownBlocks.Pop() 266 } 267 return p2p.Send(p.rw, NewBlockMsg, []interface{}{block, td}) 268 } 269 270 // AsyncSendNewBlock queues an entire block for propagation to a remote peer. If 271 // the peer's broadcast queue is full, the event is silently dropped. 272 func (p *peer) AsyncSendNewBlock(block *types.Block, td *big.Int) { 273 select { 274 case p.queuedProps <- &propEvent{block: block, td: td}: 275 // Mark all the block hash as known, but ensure we don't overflow our limits 276 p.knownBlocks.Add(block.Hash()) 277 for p.knownBlocks.Cardinality() >= maxKnownBlocks { 278 p.knownBlocks.Pop() 279 } 280 default: 281 p.Log().Debug("Dropping block propagation", "number", block.NumberU64(), "hash", block.Hash()) 282 } 283 } 284 285 // SendBlockHeaders sends a batch of block headers to the remote peer. 286 func (p *peer) SendBlockHeaders(headers []*types.Header) error { 287 return p2p.Send(p.rw, BlockHeadersMsg, headers) 288 } 289 290 // SendBlockBodies sends a batch of block contents to the remote peer. 291 func (p *peer) SendBlockBodies(bodies []*blockBody) error { 292 return p2p.Send(p.rw, BlockBodiesMsg, blockBodiesData(bodies)) 293 } 294 295 // SendBlockBodiesRLP sends a batch of block contents to the remote peer from 296 // an already RLP encoded format. 297 func (p *peer) SendBlockBodiesRLP(bodies []rlp.RawValue) error { 298 return p2p.Send(p.rw, BlockBodiesMsg, bodies) 299 } 300 301 // SendNodeDataRLP sends a batch of arbitrary internal data, corresponding to the 302 // hashes requested. 303 func (p *peer) SendNodeData(data [][]byte) error { 304 return p2p.Send(p.rw, NodeDataMsg, data) 305 } 306 307 // SendReceiptsRLP sends a batch of transaction receipts, corresponding to the 308 // ones requested from an already RLP encoded format. 309 func (p *peer) SendReceiptsRLP(receipts []rlp.RawValue) error { 310 return p2p.Send(p.rw, ReceiptsMsg, receipts) 311 } 312 313 // RequestOneHeader is a wrapper around the header query functions to fetch a 314 // single header. It is used solely by the fetcher. 315 func (p *peer) RequestOneHeader(hash common.Hash) error { 316 p.Log().Debug("Fetching single header", "hash", hash) 317 return p2p.Send(p.rw, GetBlockHeadersMsg, &getBlockHeadersData{Origin: hashOrNumber{Hash: hash}, Amount: uint64(1), Skip: uint64(0), Reverse: false}) 318 } 319 320 // RequestHeadersByHash fetches a batch of blocks' headers corresponding to the 321 // specified header query, based on the hash of an origin block. 322 func (p *peer) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error { 323 p.Log().Debug("Fetching batch of headers", "count", amount, "fromhash", origin, "skip", skip, "reverse", reverse) 324 return p2p.Send(p.rw, GetBlockHeadersMsg, &getBlockHeadersData{Origin: hashOrNumber{Hash: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse}) 325 } 326 327 // RequestHeadersByNumber fetches a batch of blocks' headers corresponding to the 328 // specified header query, based on the number of an origin block. 329 func (p *peer) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error { 330 p.Log().Debug("Fetching batch of headers", "count", amount, "fromnum", origin, "skip", skip, "reverse", reverse) 331 return p2p.Send(p.rw, GetBlockHeadersMsg, &getBlockHeadersData{Origin: hashOrNumber{Number: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse}) 332 } 333 334 // RequestBodies fetches a batch of blocks' bodies corresponding to the hashes 335 // specified. 336 func (p *peer) RequestBodies(hashes []common.Hash) error { 337 p.Log().Debug("Fetching batch of block bodies", "count", len(hashes)) 338 return p2p.Send(p.rw, GetBlockBodiesMsg, hashes) 339 } 340 341 // RequestNodeData fetches a batch of arbitrary data from a node's known state 342 // data, corresponding to the specified hashes. 343 func (p *peer) RequestNodeData(hashes []common.Hash) error { 344 p.Log().Debug("Fetching batch of state data", "count", len(hashes)) 345 return p2p.Send(p.rw, GetNodeDataMsg, hashes) 346 } 347 348 // RequestReceipts fetches a batch of transaction receipts from a remote node. 349 func (p *peer) RequestReceipts(hashes []common.Hash) error { 350 p.Log().Debug("Fetching batch of receipts", "count", len(hashes)) 351 return p2p.Send(p.rw, GetReceiptsMsg, hashes) 352 } 353 354 // Handshake executes the eth protocol handshake, negotiating version number, 355 // network IDs, difficulties, head and genesis blocks. 356 func (p *peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis common.Hash) error { 357 // Send out own handshake in a new thread 358 errc := make(chan error, 2) 359 var status statusData // safe to read after two values have been received from errc 360 361 go func() { 362 errc <- p2p.Send(p.rw, StatusMsg, &statusData{ 363 ProtocolVersion: uint32(p.version), 364 NetworkId: network, 365 TD: td, 366 CurrentBlock: head, 367 GenesisBlock: genesis, 368 }) 369 }() 370 go func() { 371 errc <- p.readStatus(network, &status, genesis) 372 }() 373 timeout := time.NewTimer(handshakeTimeout) 374 defer timeout.Stop() 375 for i := 0; i < 2; i++ { 376 select { 377 case err := <-errc: 378 if err != nil { 379 return err 380 } 381 case <-timeout.C: 382 return p2p.DiscReadTimeout 383 } 384 } 385 p.td, p.head = status.TD, status.CurrentBlock 386 return nil 387 } 388 389 func (p *peer) readStatus(network uint64, status *statusData, genesis common.Hash) (err error) { 390 msg, err := p.rw.ReadMsg() 391 if err != nil { 392 return err 393 } 394 if msg.Code != StatusMsg { 395 return errResp(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, StatusMsg) 396 } 397 if msg.Size > protocolMaxMsgSize { 398 return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, protocolMaxMsgSize) 399 } 400 // Decode the handshake and make sure everything matches 401 if err := msg.Decode(&status); err != nil { 402 return errResp(ErrDecode, "msg %v: %v", msg, err) 403 } 404 if status.GenesisBlock != genesis { 405 return errResp(ErrGenesisBlockMismatch, "%x (!= %x)", status.GenesisBlock[:8], genesis[:8]) 406 } 407 if status.NetworkId != network { 408 return errResp(ErrNetworkIdMismatch, "%d (!= %d)", status.NetworkId, network) 409 } 410 if int(status.ProtocolVersion) != p.version { 411 return errResp(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, p.version) 412 } 413 return nil 414 } 415 416 // String implements fmt.Stringer. 417 func (p *peer) String() string { 418 return fmt.Sprintf("Peer %s [%s]", p.id, 419 fmt.Sprintf("eth/%2d", p.version), 420 ) 421 } 422 423 // peerSet represents the collection of active peers currently participating in 424 // the Ethereum sub-protocol. 425 type peerSet struct { 426 peers map[string]*peer 427 lock sync.RWMutex 428 closed bool 429 } 430 431 // newPeerSet creates a new peer set to track the active participants. 432 func newPeerSet() *peerSet { 433 return &peerSet{ 434 peers: make(map[string]*peer), 435 } 436 } 437 438 // Register injects a new peer into the working set, or returns an error if the 439 // peer is already known. If a new peer it registered, its broadcast loop is also 440 // started. 441 func (ps *peerSet) Register(p *peer) error { 442 ps.lock.Lock() 443 defer ps.lock.Unlock() 444 445 if ps.closed { 446 return errClosed 447 } 448 if _, ok := ps.peers[p.id]; ok { 449 return errAlreadyRegistered 450 } 451 ps.peers[p.id] = p 452 go p.broadcast() 453 454 return nil 455 } 456 457 // Unregister removes a remote peer from the active set, disabling any further 458 // actions to/from that particular entity. 459 func (ps *peerSet) Unregister(id string) error { 460 ps.lock.Lock() 461 defer ps.lock.Unlock() 462 463 p, ok := ps.peers[id] 464 if !ok { 465 return errNotRegistered 466 } 467 delete(ps.peers, id) 468 p.close() 469 470 return nil 471 } 472 473 // Peer retrieves the registered peer with the given id. 474 func (ps *peerSet) Peer(id string) *peer { 475 ps.lock.RLock() 476 defer ps.lock.RUnlock() 477 478 return ps.peers[id] 479 } 480 481 // Len returns if the current number of peers in the set. 482 func (ps *peerSet) Len() int { 483 ps.lock.RLock() 484 defer ps.lock.RUnlock() 485 486 return len(ps.peers) 487 } 488 489 // PeersWithoutBlock retrieves a list of peers that do not have a given block in 490 // their set of known hashes. 491 func (ps *peerSet) PeersWithoutBlock(hash common.Hash) []*peer { 492 ps.lock.RLock() 493 defer ps.lock.RUnlock() 494 495 list := make([]*peer, 0, len(ps.peers)) 496 for _, p := range ps.peers { 497 if !p.knownBlocks.Contains(hash) { 498 list = append(list, p) 499 } 500 } 501 return list 502 } 503 504 // PeersWithoutTx retrieves a list of peers that do not have a given transaction 505 // in their set of known hashes. 506 func (ps *peerSet) PeersWithoutTx(hash common.Hash) []*peer { 507 ps.lock.RLock() 508 defer ps.lock.RUnlock() 509 510 list := make([]*peer, 0, len(ps.peers)) 511 for _, p := range ps.peers { 512 if !p.knownTxs.Contains(hash) { 513 list = append(list, p) 514 } 515 } 516 return list 517 } 518 519 // BestPeer retrieves the known peer with the currently highest total difficulty. 520 func (ps *peerSet) BestPeer() *peer { 521 ps.lock.RLock() 522 defer ps.lock.RUnlock() 523 524 var ( 525 bestPeer *peer 526 bestTd *big.Int 527 ) 528 for _, p := range ps.peers { 529 if _, td := p.Head(); bestPeer == nil || td.Cmp(bestTd) > 0 { 530 bestPeer, bestTd = p, td 531 } 532 } 533 return bestPeer 534 } 535 536 // Close disconnects all peers. 537 // No new peers can be registered after Close has returned. 538 func (ps *peerSet) Close() { 539 ps.lock.Lock() 540 defer ps.lock.Unlock() 541 542 for _, p := range ps.peers { 543 p.Disconnect(p2p.DiscQuitting) 544 } 545 ps.closed = true 546 }