github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/eth/peer.go (about) 1 // Copyright 2015 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum 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 Spectrum 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 Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package eth 18 19 import ( 20 "errors" 21 "fmt" 22 "github.com/SmartMeshFoundation/Spectrum/common" 23 "github.com/SmartMeshFoundation/Spectrum/core/types" 24 "github.com/SmartMeshFoundation/Spectrum/p2p" 25 "github.com/SmartMeshFoundation/Spectrum/rlp" 26 mapset "github.com/deckarep/golang-set" 27 "math/big" 28 "sync" 29 "time" 30 ) 31 32 var ( 33 errClosed = errors.New("peer set is closed") 34 errAlreadyRegistered = errors.New("peer is already registered") 35 errNotRegistered = errors.New("peer is not registered") 36 ) 37 38 const ( 39 maxKnownTxs = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS) 40 maxKnownBlocks = 1024 // Maximum block hashes to keep in the known list (prevent DOS) 41 handshakeTimeout = 5 * time.Second 42 ) 43 44 // PeerInfo represents a short summary of the Ethereum sub-protocol metadata known 45 // about a connected peer. 46 type PeerInfo struct { 47 Version int `json:"version"` // Ethereum protocol version negotiated 48 Difficulty *big.Int `json:"difficulty"` // Total difficulty of the peer's blockchain 49 Head string `json:"head"` // SHA3 hash of the peer's best owned block 50 } 51 52 type peer struct { 53 id string 54 55 *p2p.Peer 56 rw p2p.MsgReadWriter 57 58 version int // Protocol version negotiated 59 forkDrop *time.Timer // Timed connection dropper if forks aren't validated in time 60 61 head common.Hash 62 td *big.Int 63 lock sync.RWMutex 64 65 knownTxs mapset.Set // Set of transaction hashes known to be known by this peer 66 knownBlocks mapset.Set // Set of block hashes known to be known by this peer 67 } 68 69 func newPeer(version int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer { 70 id := p.ID() 71 72 return &peer{ 73 Peer: p, 74 rw: rw, 75 version: version, 76 id: fmt.Sprintf("%x", id[:8]), 77 knownTxs: mapset.NewSet(), 78 knownBlocks: mapset.NewSet(), 79 } 80 } 81 82 // Info gathers and returns a collection of metadata known about a peer. 83 func (p *peer) Info() *PeerInfo { 84 hash, td := p.Head() 85 86 return &PeerInfo{ 87 Version: p.version, 88 Difficulty: td, 89 Head: hash.Hex(), 90 } 91 } 92 93 // Head retrieves a copy of the current head hash and total difficulty of the 94 // peer. 95 func (p *peer) Head() (hash common.Hash, td *big.Int) { 96 p.lock.RLock() 97 defer p.lock.RUnlock() 98 99 copy(hash[:], p.head[:]) 100 return hash, new(big.Int).Set(p.td) 101 } 102 103 // SetHead updates the head hash and total difficulty of the peer. 104 func (p *peer) SetHead(hash common.Hash, td *big.Int) { 105 p.lock.Lock() 106 defer p.lock.Unlock() 107 108 copy(p.head[:], hash[:]) 109 p.td.Set(td) 110 } 111 112 // MarkBlock marks a block as known for the peer, ensuring that the block will 113 // never be propagated to this particular peer. 114 func (p *peer) MarkBlock(hash common.Hash) { 115 // If we reached the memory allowance, drop a previously known block hash 116 for p.knownBlocks.Cardinality() >= maxKnownBlocks { 117 p.knownBlocks.Pop() 118 } 119 p.knownBlocks.Add(hash) 120 } 121 122 // MarkTransaction marks a transaction as known for the peer, ensuring that it 123 // will never be propagated to this particular peer. 124 func (p *peer) MarkTransaction(hash common.Hash) { 125 // If we reached the memory allowance, drop a previously known transaction hash 126 for p.knownTxs.Cardinality() >= maxKnownTxs { 127 p.knownTxs.Pop() 128 } 129 p.knownTxs.Add(hash) 130 } 131 132 // SendTransactions sends transactions to the peer and includes the hashes 133 // in its transaction hash set for future reference. 134 func (p *peer) SendTransactions(txs types.Transactions) error { 135 for _, tx := range txs { 136 p.knownTxs.Add(tx.Hash()) 137 } 138 return p2p.Send(p.rw, TxMsg, txs) 139 } 140 141 // SendNewBlockHashes announces the availability of a number of blocks through 142 // a hash notification. 143 func (p *peer) SendNewBlockHashes(hashes []common.Hash, numbers []uint64) error { 144 for _, hash := range hashes { 145 p.knownBlocks.Add(hash) 146 } 147 request := make(newBlockHashesData, len(hashes)) 148 for i := 0; i < len(hashes); i++ { 149 request[i].Hash = hashes[i] 150 request[i].Number = numbers[i] 151 } 152 return p2p.Send(p.rw, NewBlockHashesMsg, request) 153 } 154 155 // SendNewBlock propagates an entire block to a remote peer. 156 func (p *peer) SendNewBlock(block *types.Block, td *big.Int) error { 157 p.knownBlocks.Add(block.Hash()) 158 return p2p.Send(p.rw, NewBlockMsg, []interface{}{block, td}) 159 } 160 161 // SendBlockHeaders sends a batch of block headers to the remote peer. 162 func (p *peer) SendBlockHeaders(headers []*types.Header) error { 163 return p2p.Send(p.rw, BlockHeadersMsg, headers) 164 } 165 166 // SendBlockBodies sends a batch of block contents to the remote peer. 167 func (p *peer) SendBlockBodies(bodies []*blockBody) error { 168 return p2p.Send(p.rw, BlockBodiesMsg, blockBodiesData(bodies)) 169 } 170 171 // SendBlockBodiesRLP sends a batch of block contents to the remote peer from 172 // an already RLP encoded format. 173 func (p *peer) SendBlockBodiesRLP(bodies []rlp.RawValue) error { 174 return p2p.Send(p.rw, BlockBodiesMsg, bodies) 175 } 176 177 // SendNodeDataRLP sends a batch of arbitrary internal data, corresponding to the 178 // hashes requested. 179 func (p *peer) SendNodeData(data [][]byte) error { 180 return p2p.Send(p.rw, NodeDataMsg, data) 181 } 182 183 // SendReceiptsRLP sends a batch of transaction receipts, corresponding to the 184 // ones requested from an already RLP encoded format. 185 func (p *peer) SendReceiptsRLP(receipts []rlp.RawValue) error { 186 return p2p.Send(p.rw, ReceiptsMsg, receipts) 187 } 188 189 // RequestOneHeader is a wrapper around the header query functions to fetch a 190 // single header. It is used solely by the fetcher. 191 func (p *peer) RequestOneHeader(hash common.Hash) error { 192 p.Log().Debug("Fetching single header", "hash", hash) 193 return p2p.Send(p.rw, GetBlockHeadersMsg, &getBlockHeadersData{Origin: hashOrNumber{Hash: hash}, Amount: uint64(1), Skip: uint64(0), Reverse: false}) 194 } 195 196 // RequestHeadersByHash fetches a batch of blocks' headers corresponding to the 197 // specified header query, based on the hash of an origin block. 198 func (p *peer) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error { 199 p.Log().Debug("Fetching batch of headers", "count", amount, "fromhash", origin, "skip", skip, "reverse", reverse) 200 return p2p.Send(p.rw, GetBlockHeadersMsg, &getBlockHeadersData{Origin: hashOrNumber{Hash: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse}) 201 } 202 203 // RequestHeadersByNumber fetches a batch of blocks' headers corresponding to the 204 // specified header query, based on the number of an origin block. 205 func (p *peer) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error { 206 p.Log().Debug("Fetching batch of headers", "count", amount, "fromnum", origin, "skip", skip, "reverse", reverse) 207 return p2p.Send(p.rw, GetBlockHeadersMsg, &getBlockHeadersData{Origin: hashOrNumber{Number: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse}) 208 } 209 210 // RequestBodies fetches a batch of blocks' bodies corresponding to the hashes 211 // specified. 212 func (p *peer) RequestBodies(hashes []common.Hash) error { 213 p.Log().Debug("Fetching batch of block bodies", "count", len(hashes)) 214 return p2p.Send(p.rw, GetBlockBodiesMsg, hashes) 215 } 216 217 // RequestNodeData fetches a batch of arbitrary data from a node's known state 218 // data, corresponding to the specified hashes. 219 func (p *peer) RequestNodeData(hashes []common.Hash) error { 220 p.Log().Debug("Fetching batch of state data", "count", len(hashes)) 221 return p2p.Send(p.rw, GetNodeDataMsg, hashes) 222 } 223 224 // RequestReceipts fetches a batch of transaction receipts from a remote node. 225 func (p *peer) RequestReceipts(hashes []common.Hash) error { 226 p.Log().Debug("Fetching batch of receipts", "count", len(hashes)) 227 return p2p.Send(p.rw, GetReceiptsMsg, hashes) 228 } 229 230 // Handshake executes the eth protocol handshake, negotiating version number, 231 // network IDs, difficulties, head and genesis blocks. 232 func (p *peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis common.Hash) error { 233 // Send out own handshake in a new thread 234 errc := make(chan error, 2) 235 var status statusData // safe to read after two values have been received from errc 236 237 go func() { 238 errc <- p2p.Send(p.rw, StatusMsg, &statusData{ 239 ProtocolVersion: uint32(p.version), 240 NetworkId: network, 241 TD: td, 242 CurrentBlock: head, 243 GenesisBlock: genesis, 244 }) 245 }() 246 go func() { 247 errc <- p.readStatus(network, &status, genesis) 248 }() 249 timeout := time.NewTimer(handshakeTimeout) 250 defer timeout.Stop() 251 for i := 0; i < 2; i++ { 252 select { 253 case err := <-errc: 254 if err != nil { 255 return err 256 } 257 case <-timeout.C: 258 return p2p.DiscReadTimeout 259 } 260 } 261 p.td, p.head = status.TD, status.CurrentBlock 262 return nil 263 } 264 265 func (p *peer) readStatus(network uint64, status *statusData, genesis common.Hash) (err error) { 266 msg, err := p.rw.ReadMsg() 267 if err != nil { 268 return err 269 } 270 if msg.Code != StatusMsg { 271 return errResp(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, StatusMsg) 272 } 273 if msg.Size > ProtocolMaxMsgSize { 274 return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize) 275 } 276 // Decode the handshake and make sure everything matches 277 if err := msg.Decode(&status); err != nil { 278 return errResp(ErrDecode, "msg %v: %v", msg, err) 279 } 280 if status.GenesisBlock != genesis { 281 return errResp(ErrGenesisBlockMismatch, "%x (!= %x)", status.GenesisBlock[:8], genesis[:8]) 282 } 283 if status.NetworkId != network { 284 return errResp(ErrNetworkIdMismatch, "%d (!= %d)", status.NetworkId, network) 285 } 286 if int(status.ProtocolVersion) != p.version { 287 return errResp(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, p.version) 288 } 289 return nil 290 } 291 292 // String implements fmt.Stringer. 293 func (p *peer) String() string { 294 return fmt.Sprintf("Peer %s [%s]", p.id, 295 fmt.Sprintf("eth/%2d", p.version), 296 ) 297 } 298 299 // peerSet represents the collection of active peers currently participating in 300 // the Ethereum sub-protocol. 301 type peerSet struct { 302 peers map[string]*peer 303 lock sync.RWMutex 304 closed bool 305 } 306 307 // newPeerSet creates a new peer set to track the active participants. 308 func newPeerSet() *peerSet { 309 return &peerSet{ 310 peers: make(map[string]*peer), 311 } 312 } 313 314 // Register injects a new peer into the working set, or returns an error if the 315 // peer is already known. 316 func (ps *peerSet) Register(p *peer) error { 317 ps.lock.Lock() 318 defer ps.lock.Unlock() 319 320 if ps.closed { 321 return errClosed 322 } 323 if _, ok := ps.peers[p.id]; ok { 324 return errAlreadyRegistered 325 } 326 ps.peers[p.id] = p 327 return nil 328 } 329 330 // Unregister removes a remote peer from the active set, disabling any further 331 // actions to/from that particular entity. 332 func (ps *peerSet) Unregister(id string) error { 333 ps.lock.Lock() 334 defer ps.lock.Unlock() 335 336 if _, ok := ps.peers[id]; !ok { 337 return errNotRegistered 338 } 339 delete(ps.peers, id) 340 return nil 341 } 342 343 // Peer retrieves the registered peer with the given id. 344 func (ps *peerSet) Peer(id string) *peer { 345 ps.lock.RLock() 346 defer ps.lock.RUnlock() 347 348 return ps.peers[id] 349 } 350 351 // Len returns if the current number of peers in the set. 352 func (ps *peerSet) Len() int { 353 ps.lock.RLock() 354 defer ps.lock.RUnlock() 355 356 return len(ps.peers) 357 } 358 359 // PeersWithoutBlock retrieves a list of peers that do not have a given block in 360 // their set of known hashes. 361 func (ps *peerSet) PeersWithoutBlock(hash common.Hash) []*peer { 362 ps.lock.RLock() 363 defer ps.lock.RUnlock() 364 365 list := make([]*peer, 0, len(ps.peers)) 366 for _, p := range ps.peers { 367 if !p.knownBlocks.Contains(hash) { 368 list = append(list, p) 369 } 370 } 371 return list 372 } 373 374 // PeersWithoutTx retrieves a list of peers that do not have a given transaction 375 // in their set of known hashes. 376 func (ps *peerSet) PeersWithoutTx(hash common.Hash) []*peer { 377 ps.lock.RLock() 378 defer ps.lock.RUnlock() 379 380 list := make([]*peer, 0, len(ps.peers)) 381 for _, p := range ps.peers { 382 if !p.knownTxs.Contains(hash) { 383 list = append(list, p) 384 } 385 } 386 return list 387 } 388 389 // BestPeer retrieves the known peer with the currently highest total difficulty. 390 func (ps *peerSet) BestPeer() *peer { 391 ps.lock.RLock() 392 defer ps.lock.RUnlock() 393 394 var ( 395 bestPeer *peer 396 bestTd *big.Int 397 ) 398 for _, p := range ps.peers { 399 if _, td := p.Head(); bestPeer == nil || td.Cmp(bestTd) > 0 { 400 bestPeer, bestTd = p, td 401 } 402 } 403 return bestPeer 404 } 405 406 // Close disconnects all peers. 407 // No new peers can be registered after Close has returned. 408 func (ps *peerSet) Close() { 409 ps.lock.Lock() 410 defer ps.lock.Unlock() 411 412 for _, p := range ps.peers { 413 p.Disconnect(p2p.DiscQuitting) 414 } 415 ps.closed = true 416 }