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