github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/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/ethereumproject/go-ethereum/common" 27 "github.com/ethereumproject/go-ethereum/core/types" 28 "github.com/ethereumproject/go-ethereum/logger" 29 "github.com/ethereumproject/go-ethereum/logger/glog" 30 "github.com/ethereumproject/go-ethereum/p2p" 31 "github.com/ethereumproject/go-ethereum/rlp" 32 "gopkg.in/fatih/set.v0" 33 ) 34 35 var ( 36 errClosed = errors.New("peer set is closed") 37 errAlreadyRegistered = errors.New("peer is already registered") 38 errNotRegistered = errors.New("peer is not registered") 39 ) 40 41 const ( 42 maxKnownTxs = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS) 43 maxKnownBlocks = 1024 // Maximum block hashes to keep in the known list (prevent DOS) 44 45 // maxQueuedTxs is the maximum number of transaction lists to queue up before 46 // dropping broadcasts. This is a sensitive number as a transaction list might 47 // contain a single transaction, or thousands. 48 maxQueuedTxs = 128 49 50 // maxQueuedProps is the maximum number of block propagations to queue up before 51 // dropping broadcasts. There's not much point in queueing stale blocks, so a few 52 // that might cover uncles should be enough. 53 maxQueuedProps = 4 54 55 // maxQueuedAnns is the maximum number of block announcements to queue up before 56 // dropping broadcasts. Similarly to block propagations, there's no point to queue 57 // above some healthy uncle limit, so use that. 58 maxQueuedAnns = 4 59 60 handshakeTimeout = 5 * time.Second 61 ) 62 63 // PeerInfo represents a short summary of the Ethereum sub-protocol metadata known 64 // about a connected peer. 65 type PeerInfo struct { 66 Version int `json:"version"` // Ethereum protocol version negotiated 67 Difficulty *big.Int `json:"difficulty"` // Total difficulty of the peer's blockchain 68 Head string `json:"head"` // SHA3 hash of the peer's best owned block 69 } 70 71 // propEvent is a block propagation, waiting for its turn in the broadcast queue. 72 type propEvent struct { 73 block *types.Block 74 td *big.Int 75 } 76 77 type peer struct { 78 id string 79 80 *p2p.Peer 81 rw p2p.MsgReadWriter 82 83 version int // Protocol version negotiated 84 forkDrop *time.Timer // Timed connection dropper if forks aren't validated in time 85 86 head common.Hash 87 td *big.Int 88 lock sync.RWMutex 89 90 knownTxs *set.Set // Set of transaction hashes known to be known by this peer 91 knownBlocks *set.Set // Set of block hashes known to be known by this peer 92 93 queuedTxs chan []*types.Transaction // Queue of transactions to broadcast to the peer 94 queuedProps chan *propEvent // Queue of blocks to broadcast to the peer 95 queuedAnns chan *types.Block // Queue of blocks to announce to the peer 96 term chan struct{} // Termination channel to stop the broadcaster 97 } 98 99 func newPeer(version int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer { 100 id := p.ID() 101 102 return &peer{ 103 Peer: p, 104 rw: rw, 105 version: version, 106 id: fmt.Sprintf("%x", id[:8]), 107 knownTxs: set.New(), 108 knownBlocks: set.New(), 109 queuedTxs: make(chan []*types.Transaction, maxQueuedTxs), 110 queuedProps: make(chan *propEvent, maxQueuedProps), 111 queuedAnns: make(chan *types.Block, maxQueuedAnns), 112 term: make(chan struct{}), 113 } 114 } 115 116 // broadcast is a write loop that multiplexes block propagations, announcements 117 // and transaction broadcasts into the remote peer. The goal is to have an async 118 // writer that does not lock up node internals. 119 func (p *peer) broadcast() { 120 for { 121 select { 122 case txs := <-p.queuedTxs: 123 if err := p.SendTransactions(txs); err != nil { 124 return 125 } 126 glog.V(logger.Detail).Infoln("Broadcast transactions", "count", len(txs)) 127 128 case prop := <-p.queuedProps: 129 if err := p.SendNewBlock(prop.block, prop.td); err != nil { 130 return 131 } 132 glog.V(logger.Detail).Infoln("Propagated block", "number", prop.block.Number(), "hash", prop.block.Hash().Hex(), "td", prop.td) 133 134 case block := <-p.queuedAnns: 135 if err := p.SendNewBlockHashes([]common.Hash{block.Hash()}, []uint64{block.NumberU64()}); err != nil { 136 return 137 } 138 glog.V(logger.Detail).Infoln("Announced block", "number", block.Number(), "hash", block.Hash().Hex()) 139 140 case <-p.term: 141 return 142 } 143 } 144 } 145 146 // close signals the broadcast goroutine to terminate. 147 func (p *peer) close() { 148 close(p.term) 149 } 150 151 // Info gathers and returns a collection of metadata known about a peer. 152 func (p *peer) Info() *PeerInfo { 153 hash, td := p.Head() 154 155 return &PeerInfo{ 156 Version: p.version, 157 Difficulty: td, 158 Head: hash.Hex(), 159 } 160 } 161 162 // Head retrieves a copy of the current head hash and total difficulty of the 163 // peer. 164 func (p *peer) Head() (hash common.Hash, td *big.Int) { 165 p.lock.RLock() 166 defer p.lock.RUnlock() 167 168 copy(hash[:], p.head[:]) 169 return hash, new(big.Int).Set(p.td) 170 } 171 172 // SetHead updates the head hash and total difficulty of the peer. 173 func (p *peer) SetHead(hash common.Hash, td *big.Int) { 174 p.lock.Lock() 175 defer p.lock.Unlock() 176 177 copy(p.head[:], hash[:]) 178 p.td.Set(td) 179 } 180 181 // MarkBlock marks a block as known for the peer, ensuring that the block will 182 // never be propagated to this particular peer. 183 func (p *peer) MarkBlock(hash common.Hash) { 184 // If we reached the memory allowance, drop a previously known block hash 185 for p.knownBlocks.Size() >= maxKnownBlocks { 186 p.knownBlocks.Pop() 187 } 188 p.knownBlocks.Add(hash) 189 } 190 191 // MarkTransaction marks a transaction as known for the peer, ensuring that it 192 // will never be propagated to this particular peer. 193 func (p *peer) MarkTransaction(hash common.Hash) { 194 // If we reached the memory allowance, drop a previously known transaction hash 195 for p.knownTxs.Size() >= maxKnownTxs { 196 p.knownTxs.Pop() 197 } 198 p.knownTxs.Add(hash) 199 } 200 201 // SendTransactions sends transactions to the peer and includes the hashes 202 // in its transaction hash set for future reference. 203 func (p *peer) SendTransactions(txs types.Transactions) error { 204 for _, tx := range txs { 205 p.knownTxs.Add(tx.Hash()) 206 } 207 s, e := p2p.Send(p.rw, TxMsg, txs) 208 mlogWireDelegate(p, "send", TxMsg, s, txs, nil) 209 return e 210 } 211 212 // AsyncSendTransactions queues list of transactions propagation to a remote 213 // peer. If the peer's broadcast queue is full, the event is silently dropped. 214 func (p *peer) AsyncSendTransactions(txs []*types.Transaction) { 215 select { 216 case p.queuedTxs <- txs: 217 for _, tx := range txs { 218 p.knownTxs.Add(tx.Hash()) 219 } 220 default: 221 glog.V(logger.Debug).Infoln("Dropping transaction propagation", "count", len(txs)) 222 } 223 } 224 225 // SendNewBlockHashes announces the availability of a number of blocks through 226 // a hash notification. 227 func (p *peer) SendNewBlockHashes(hashes []common.Hash, numbers []uint64) error { 228 for _, hash := range hashes { 229 p.knownBlocks.Add(hash) 230 } 231 request := make(newBlockHashesData, len(hashes)) 232 for i := 0; i < len(hashes); i++ { 233 request[i].Hash = hashes[i] 234 request[i].Number = numbers[i] 235 } 236 s, e := p2p.Send(p.rw, NewBlockHashesMsg, request) 237 mlogWireDelegate(p, "send", NewBlockHashesMsg, s, request, nil) 238 return e 239 } 240 241 // AsyncSendNewBlockHash queues the availability of a block for propagation to a 242 // remote peer. If the peer's broadcast queue is full, the event is silently 243 // dropped. 244 func (p *peer) AsyncSendNewBlockHash(block *types.Block) { 245 select { 246 case p.queuedAnns <- block: 247 p.knownBlocks.Add(block.Hash()) 248 default: 249 glog.V(logger.Debug).Infoln("Dropping block announcement", "number", block.NumberU64(), "hash", block.Hash()) 250 } 251 } 252 253 // SendNewBlock propagates an entire block to a remote peer. 254 func (p *peer) SendNewBlock(block *types.Block, td *big.Int) error { 255 p.knownBlocks.Add(block.Hash()) 256 s, e := p2p.Send(p.rw, NewBlockMsg, []interface{}{block, td}) 257 mlogWireDelegate(p, "send", NewBlockMsg, s, newBlockData{Block: block, TD: td}, nil) // send slice of len 1 258 return e 259 } 260 261 // AsyncSendNewBlock queues an entire block for propagation to a remote peer. If 262 // the peer's broadcast queue is full, the event is silently dropped. 263 func (p *peer) AsyncSendNewBlock(block *types.Block, td *big.Int) { 264 select { 265 case p.queuedProps <- &propEvent{block: block, td: td}: 266 p.knownBlocks.Add(block.Hash()) 267 default: 268 glog.V(logger.Debug).Infoln("Dropping block propagation", "number", block.NumberU64(), "hash", block.Hash()) 269 } 270 } 271 272 // SendBlockHeaders sends a batch of block headers to the remote peer.m 273 func (p *peer) SendBlockHeaders(headers []*types.Header) error { 274 s, e := p2p.Send(p.rw, BlockHeadersMsg, headers) 275 mlogWireDelegate(p, "send", BlockHeadersMsg, s, headers, nil) 276 return e 277 } 278 279 // SendBlockBodies sends a batch of block contents to the remote peer. 280 func (p *peer) SendBlockBodies(bodies []*blockBody) error { 281 s, e := p2p.Send(p.rw, BlockBodiesMsg, blockBodiesData(bodies)) 282 mlogWireDelegate(p, "send", BlockBodiesMsg, s, bodies, nil) 283 return e 284 } 285 286 // SendBlockBodiesRLP sends a batch of block contents to the remote peer from 287 // an already RLP encoded format. 288 func (p *peer) SendBlockBodiesRLP(bodies []rlp.RawValue) error { 289 s, e := p2p.Send(p.rw, BlockBodiesMsg, bodies) 290 mlogWireDelegate(p, "send", BlockBodiesMsg, s, bodies, nil) 291 return e 292 } 293 294 // SendNodeDataRLP sends a batch of arbitrary internal data, corresponding to the 295 // hashes requested. 296 func (p *peer) SendNodeData(data [][]byte) error { 297 s, e := p2p.Send(p.rw, NodeDataMsg, data) 298 mlogWireDelegate(p, "send", NodeDataMsg, s, data, nil) 299 return e 300 } 301 302 // SendReceiptsRLP sends a batch of transaction receipts, corresponding to the 303 // ones requested from an already RLP encoded format. 304 func (p *peer) SendReceiptsRLP(receipts []rlp.RawValue) error { 305 s, e := p2p.Send(p.rw, ReceiptsMsg, receipts) 306 mlogWireDelegate(p, "send", ReceiptsMsg, s, receipts, nil) 307 return e 308 } 309 310 // RequestHeaders is a wrapper around the header query functions to fetch a 311 // single header. It is used solely by the fetcher. 312 func (p *peer) RequestOneHeader(hash common.Hash) error { 313 glog.V(logger.Debug).Infof("fetching from: %v req=singleheader hash=%x", p, hash) 314 d := &getBlockHeadersData{Origin: hashOrNumber{Hash: hash}, Amount: uint64(1), Skip: uint64(0), Reverse: false} 315 s, e := p2p.Send(p.rw, GetBlockHeadersMsg, d) 316 mlogWireDelegate(p, "send", GetBlockHeadersMsg, s, d, nil) 317 return e 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 glog.V(logger.Debug).Infof("fetching from: %v req=headersbyhash n=%d origin=%x, skipping=%d reverse=%v", p, amount, origin[:4], skip, reverse) 324 d := &getBlockHeadersData{Origin: hashOrNumber{Hash: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse} 325 s, e := p2p.Send(p.rw, GetBlockHeadersMsg, d) 326 mlogWireDelegate(p, "send", GetBlockHeadersMsg, s, d, nil) 327 return e 328 } 329 330 // RequestHeadersByNumber fetches a batch of blocks' headers corresponding to the 331 // specified header query, based on the number of an origin block. 332 func (p *peer) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error { 333 glog.V(logger.Debug).Infof("fetching from: %v %d req=headersbynumber n=%d, skipping=%d reverse=%v", p, amount, origin, skip, reverse) 334 d := &getBlockHeadersData{Origin: hashOrNumber{Number: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse} 335 s, e := p2p.Send(p.rw, GetBlockHeadersMsg, d) 336 mlogWireDelegate(p, "send", GetBlockHeadersMsg, s, d, nil) 337 return e 338 } 339 340 // RequestBodies fetches a batch of blocks' bodies corresponding to the hashes 341 // specified. 342 func (p *peer) RequestBodies(hashes []common.Hash) error { 343 glog.V(logger.Debug).Infof("fetching from: %v req=blockbodies n=%d first=%s", p, len(hashes), hashes[0].Hex()) 344 s, e := p2p.Send(p.rw, GetBlockBodiesMsg, hashes) 345 mlogWireDelegate(p, "send", GetBlockBodiesMsg, s, hashes, nil) 346 return e 347 } 348 349 // RequestNodeData fetches a batch of arbitrary data from a node's known state 350 // data, corresponding to the specified hashes. 351 func (p *peer) RequestNodeData(hashes []common.Hash) error { 352 glog.V(logger.Debug).Infof("fetching from: %v req=statedata n=%d first=%s", p, len(hashes), hashes[0].Hex()) 353 s, e := p2p.Send(p.rw, GetNodeDataMsg, hashes) 354 mlogWireDelegate(p, "send", GetNodeDataMsg, s, hashes, nil) 355 return e 356 } 357 358 // RequestReceipts fetches a batch of transaction receipts from a remote node. 359 func (p *peer) RequestReceipts(hashes []common.Hash) error { 360 glog.V(logger.Debug).Infof("fetching from: %v req=receipts n=%d first=%s", p, len(hashes), hashes[0].Hex()) 361 s, e := p2p.Send(p.rw, GetReceiptsMsg, hashes) 362 mlogWireDelegate(p, "send", GetReceiptsMsg, s, hashes, nil) 363 return e 364 } 365 366 // Handshake executes the eth protocol handshake, negotiating version number, 367 // network IDs, difficulties, head and genesis blocks. 368 func (p *peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis common.Hash) error { 369 // Send out own handshake in a new thread 370 sendErrc := make(chan error, 1) 371 recErrc := make(chan error, 1) 372 var sendErr, recErr error 373 var sendSize, recSize int 374 var status statusData // safe to read after two values have been received from errc 375 376 d := &statusData{ 377 ProtocolVersion: uint32(p.version), 378 NetworkId: uint32(network), 379 TD: td, 380 CurrentBlock: head, 381 GenesisBlock: genesis, 382 } 383 384 go func() { 385 var e error 386 sendSize, e = p2p.Send(p.rw, StatusMsg, d) 387 sendErrc <- e 388 }() 389 go func() { 390 var e error 391 var s uint32 392 s, e = p.readStatusReturnSize(network, &status, genesis) 393 recSize = int(s) 394 recErrc <- e 395 }() 396 timeout := time.NewTimer(handshakeTimeout) 397 defer timeout.Stop() 398 399 defer mlogWireDelegate(p, "receive", StatusMsg, recSize, &status, recErr) 400 defer mlogWireDelegate(p, "send", StatusMsg, sendSize, d, sendErr) 401 402 for i := 0; i < 2; i++ { 403 select { 404 case err := <-sendErrc: 405 if err != nil { 406 sendErr = err 407 return err 408 } 409 case err := <-recErrc: 410 if err != nil { 411 recErr = err 412 return err 413 } 414 case <-timeout.C: 415 recErr = p2p.DiscReadTimeout 416 return p2p.DiscReadTimeout 417 } 418 } 419 p.td, p.head = status.TD, status.CurrentBlock 420 return nil 421 } 422 423 func (p *peer) readStatusReturnSize(network uint64, status *statusData, genesis common.Hash) (size uint32, err error) { 424 msg, err := p.rw.ReadMsg() 425 if err != nil { 426 return msg.Size, err 427 } 428 if msg.Code != StatusMsg { 429 return msg.Size, errResp(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, StatusMsg) 430 } 431 if msg.Size > ProtocolMaxMsgSize { 432 return msg.Size, errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize) 433 } 434 // Decode the handshake and make sure everything matches 435 if err := msg.Decode(&status); err != nil { 436 return msg.Size, errResp(ErrDecode, "msg %v: %v", msg, err) 437 } 438 if status.GenesisBlock != genesis { 439 return msg.Size, errResp(ErrGenesisBlockMismatch, "%x (!= %x…)", status.GenesisBlock, genesis.Bytes()[:8]) 440 } 441 if status.NetworkId != uint32(network) { 442 return msg.Size, errResp(ErrNetworkIdMismatch, "%d (!= %d)", status.NetworkId, network) 443 } 444 if int(status.ProtocolVersion) != p.version { 445 return msg.Size, errResp(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, p.version) 446 } 447 return msg.Size, nil 448 } 449 450 func (p *peer) readStatus(network uint64, status *statusData, genesis common.Hash) (err error) { 451 _, err = p.readStatusReturnSize(network, status, genesis) 452 return 453 } 454 455 // String implements fmt.Stringer. 456 func (p *peer) String() string { 457 // id is %x[:8] 458 return fmt.Sprintf("peer:%s@[%s] eth/%d", p.id, p.Name(), p.version) 459 }