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