github.com/klaytn/klaytn@v1.12.1/node/sc/bridgepeer.go (about) 1 // Modifications Copyright 2019 The klaytn Authors 2 // Copyright 2015 The go-ethereum Authors 3 // This file is part of go-ethereum. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from eth/peer.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package sc 22 23 import ( 24 "errors" 25 "fmt" 26 "math/big" 27 "sync" 28 "time" 29 30 "github.com/klaytn/klaytn/blockchain/types" 31 "github.com/klaytn/klaytn/common" 32 "github.com/klaytn/klaytn/networks/p2p" 33 "github.com/klaytn/klaytn/networks/p2p/discover" 34 ) 35 36 var ( 37 errClosed = errors.New("peer set is closed") 38 errAlreadyRegistered = errors.New("peer is already registered") 39 errNotRegistered = errors.New("peer is not registered") 40 ) 41 42 const ( 43 maxKnownTxs = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS) 44 45 handshakeTimeout = 5 * time.Second 46 ) 47 48 // BridgePeerInfo represents a short summary of the Klaytn Bridge sub-protocol metadata known 49 // about a connected peer. 50 type BridgePeerInfo struct { 51 Version int `json:"version"` // Klaytn Bridge protocol version negotiated 52 Head string `json:"head"` // SHA3 hash of the peer's best owned block 53 } 54 55 type PeerSetManager interface { 56 BridgePeerSet() *bridgePeerSet 57 } 58 59 //go:generate mockgen -destination=bridgepeer_mock_test.go -package=sc github.com/klaytn/klaytn/node/sc BridgePeer 60 type BridgePeer interface { 61 // Close signals the broadcast goroutine to terminate. 62 Close() 63 64 // Info gathers and returns a collection of metadata known about a peer. 65 Info() *BridgePeerInfo 66 67 Head() (hash common.Hash, td *big.Int) 68 69 // AddToKnownTxs adds a transaction hash to knownTxsCache for the peer, ensuring that it 70 // will never be propagated to this particular peer. 71 AddToKnownTxs(hash common.Hash) 72 73 // Send writes an RLP-encoded message with the given code. 74 // data should have been encoded as an RLP list. 75 Send(msgcode uint64, data interface{}) error 76 77 // Handshake executes the Klaytn protocol handshake, negotiating version number, 78 // network IDs, difficulties, head, genesis blocks, and onChildChain(if the node is on child chain for the peer) 79 // and returning if the peer on the same chain or not and error. 80 Handshake(network uint64, chainID, td *big.Int, head common.Hash) error 81 82 // ConnType returns the conntype of the peer. 83 ConnType() common.ConnType 84 85 // GetID returns the id of the peer. 86 GetID() string 87 88 // GetP2PPeerID returns the id of the p2p.Peer. 89 GetP2PPeerID() discover.NodeID 90 91 // GetChainID returns the chain id of the peer. 92 GetChainID() *big.Int 93 94 // GetAddr returns the address of the peer. 95 GetAddr() common.Address 96 97 // SetAddr sets the address of the peer. 98 SetAddr(addr common.Address) 99 100 // GetVersion returns the version of the peer. 101 GetVersion() int 102 103 // KnowsTx returns if the peer is known to have the transaction, based on knownTxsCache. 104 KnowsTx(hash common.Hash) bool 105 106 // GetP2PPeer returns the p2p. 107 GetP2PPeer() *p2p.Peer 108 109 // GetRW returns the MsgReadWriter of the peer. 110 GetRW() p2p.MsgReadWriter 111 112 // Handle is the callback invoked to manage the life cycle of a Klaytn Peer. When 113 // this function terminates, the Peer is disconnected. 114 Handle(bn *MainBridge) error 115 116 SendRequestRPC(data []byte) error 117 SendResponseRPC(data []byte) error 118 119 // SendServiceChainTxs sends child chain tx data to from child chain to parent chain. 120 SendServiceChainTxs(txs types.Transactions) error 121 122 // SendServiceChainInfoRequest sends a parentChainInfo request from child chain to parent chain. 123 SendServiceChainInfoRequest(addr *common.Address) error 124 125 // SendServiceChainInfoResponse sends a parentChainInfo from parent chain to child chain. 126 // parentChainInfo includes nonce of an account and gasPrice in the parent chain. 127 SendServiceChainInfoResponse(pcInfo *parentChainInfo) error 128 129 // SendServiceChainReceiptRequest sends a receipt request from child chain to parent chain. 130 SendServiceChainReceiptRequest(txHashes []common.Hash) error 131 132 // SendServiceChainReceiptResponse sends a receipt as a response to request from child chain. 133 SendServiceChainReceiptResponse(receipts []*types.ReceiptForStorage) error 134 135 // SendServiceChainInvalidTxResponse sends a response that contains list of invalid tx and error from parent chain. 136 SendServiceChainInvalidTxResponse(invalidTxs []InvalidParentChainTx) error 137 } 138 139 // baseBridgePeer is a common data structure used by implementation of Peer. 140 type baseBridgePeer struct { 141 id string 142 143 addr common.Address 144 145 *p2p.Peer 146 rw p2p.MsgReadWriter 147 148 version int // Protocol version negotiated 149 150 head common.Hash 151 td *big.Int 152 lock sync.RWMutex 153 154 knownTxsCache common.Cache // FIFO cache of transaction hashes known to be known by this peer 155 term chan struct{} // Termination channel to stop the broadcaster 156 157 chainID *big.Int // A child chain must know parent chain's ChainID to sign a transaction. 158 159 respCh chan *big.Int 160 } 161 162 // newKnownTxCache returns an empty cache for knownTxsCache. 163 func newKnownTxCache() common.Cache { 164 return common.NewCache(common.FIFOCacheConfig{CacheSize: maxKnownTxs, IsScaled: true}) 165 } 166 167 // newPeer returns new Peer interface. 168 func newBridgePeer(version int, p *p2p.Peer, rw p2p.MsgReadWriter) BridgePeer { 169 id := p.ID() 170 171 return &singleChannelPeer{ 172 baseBridgePeer: &baseBridgePeer{ 173 Peer: p, 174 rw: rw, 175 version: version, 176 id: fmt.Sprintf("%x", id[:8]), 177 knownTxsCache: newKnownTxCache(), 178 term: make(chan struct{}), 179 respCh: make(chan *big.Int), 180 }, 181 } 182 } 183 184 // Close signals the broadcast goroutine to terminate. 185 func (p *baseBridgePeer) Close() { 186 close(p.term) 187 } 188 189 // Info gathers and returns a collection of metadata known about a peer. 190 func (p *baseBridgePeer) Info() *BridgePeerInfo { 191 hash, _ := p.Head() 192 193 return &BridgePeerInfo{ 194 Version: p.version, 195 Head: hash.Hex(), 196 } 197 } 198 199 // Head retrieves a copy of the current head hash and total blockscore of the 200 // peer. 201 func (p *baseBridgePeer) Head() (hash common.Hash, td *big.Int) { 202 p.lock.RLock() 203 defer p.lock.RUnlock() 204 205 copy(hash[:], p.head[:]) 206 return hash, new(big.Int).Set(p.td) 207 } 208 209 // SetHead updates the head hash and total blockscore of the peer. 210 func (p *baseBridgePeer) SetHead(hash common.Hash, td *big.Int) { 211 p.lock.Lock() 212 defer p.lock.Unlock() 213 214 copy(p.head[:], hash[:]) 215 p.td.Set(td) 216 } 217 218 // AddToKnownTxs adds a transaction hash to knownTxsCache for the peer, ensuring that it 219 // will never be propagated to this particular peer. 220 func (p *baseBridgePeer) AddToKnownTxs(hash common.Hash) { 221 p.knownTxsCache.Add(hash, struct{}{}) 222 } 223 224 // Send writes an RLP-encoded message with the given code. 225 // data should have been encoded as an RLP list. 226 func (p *baseBridgePeer) Send(msgcode uint64, data interface{}) error { 227 return p2p.Send(p.rw, msgcode, data) 228 } 229 230 func (p *baseBridgePeer) SendRequestRPC(data []byte) error { 231 return p2p.Send(p.rw, ServiceChainCall, data) 232 } 233 234 func (p *baseBridgePeer) SendResponseRPC(data []byte) error { 235 return p2p.Send(p.rw, ServiceChainResponse, data) 236 } 237 238 func (p *baseBridgePeer) SendServiceChainTxs(txs types.Transactions) error { 239 return p2p.Send(p.rw, ServiceChainTxsMsg, txs) 240 } 241 242 func (p *baseBridgePeer) SendServiceChainInfoRequest(addr *common.Address) error { 243 return p2p.Send(p.rw, ServiceChainParentChainInfoRequestMsg, addr) 244 } 245 246 func (p *baseBridgePeer) SendServiceChainInfoResponse(pcInfo *parentChainInfo) error { 247 return p2p.Send(p.rw, ServiceChainParentChainInfoResponseMsg, pcInfo) 248 } 249 250 func (p *baseBridgePeer) SendServiceChainReceiptRequest(txHashes []common.Hash) error { 251 return p2p.Send(p.rw, ServiceChainReceiptRequestMsg, txHashes) 252 } 253 254 func (p *baseBridgePeer) SendServiceChainReceiptResponse(receipts []*types.ReceiptForStorage) error { 255 return p2p.Send(p.rw, ServiceChainReceiptResponseMsg, receipts) 256 } 257 258 func (p *baseBridgePeer) SendServiceChainInvalidTxResponse(invalidTxs []InvalidParentChainTx) error { 259 return p2p.Send(p.rw, ServiceChainInvalidTxResponseMsg, invalidTxs) 260 } 261 262 // Handshake executes the Klaytn protocol handshake, negotiating version number, 263 // network IDs, difficulties, head and genesis blocks. 264 func (p *baseBridgePeer) Handshake(network uint64, chainID, td *big.Int, head common.Hash) error { 265 // Send out own handshake in a new thread 266 errc := make(chan error, 2) 267 var status statusData // safe to read after two values have been received from errc 268 269 go func() { 270 errc <- p2p.Send(p.rw, StatusMsg, &statusData{ 271 ProtocolVersion: uint32(p.version), 272 NetworkId: network, 273 TD: td, 274 CurrentBlock: head, 275 ChainID: chainID, 276 }) 277 }() 278 go func() { 279 e := p.readStatus(network, &status) 280 if e != nil { 281 errc <- e 282 return 283 } 284 errc <- e 285 }() 286 timeout := time.NewTimer(handshakeTimeout) 287 defer timeout.Stop() 288 for i := 0; i < 2; i++ { 289 select { 290 case err := <-errc: 291 if err != nil { 292 return err 293 } 294 case <-timeout.C: 295 return p2p.DiscReadTimeout 296 } 297 } 298 p.td, p.head, p.chainID = status.TD, status.CurrentBlock, status.ChainID 299 return nil 300 } 301 302 func (p *baseBridgePeer) readStatus(network uint64, status *statusData) error { 303 msg, err := p.rw.ReadMsg() 304 if err != nil { 305 return err 306 } 307 if msg.Code != StatusMsg { 308 return errResp(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, StatusMsg) 309 } 310 if msg.Size > ProtocolMaxMsgSize { 311 return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize) 312 } 313 // Decode the handshake and make sure everything matches 314 if err := msg.Decode(&status); err != nil { 315 return errResp(ErrDecode, "msg %v: %v", msg, err) 316 } 317 if status.NetworkId != network { 318 return errResp(ErrNetworkIdMismatch, "%d (!= %d)", status.NetworkId, network) 319 } 320 if int(status.ProtocolVersion) != p.version { 321 return errResp(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, p.version) 322 } 323 return nil 324 } 325 326 // String implements fmt.Stringer. 327 func (p *baseBridgePeer) String() string { 328 return fmt.Sprintf("Peer %s [%s]", p.id, 329 fmt.Sprintf("klay/%2d", p.version), 330 ) 331 } 332 333 // ConnType returns the conntype of the peer. 334 func (p *baseBridgePeer) ConnType() common.ConnType { 335 return p.Peer.ConnType() 336 } 337 338 // GetID returns the id of the peer. 339 func (p *baseBridgePeer) GetID() string { 340 return p.id 341 } 342 343 // GetP2PPeerID returns the id of the p2p.Peer. 344 func (p *baseBridgePeer) GetP2PPeerID() discover.NodeID { 345 return p.Peer.ID() 346 } 347 348 // GetChainID returns the chain id of the peer. 349 func (p *baseBridgePeer) GetChainID() *big.Int { 350 return p.chainID 351 } 352 353 // GetAddr returns the address of the peer. 354 func (p *baseBridgePeer) GetAddr() common.Address { 355 return p.addr 356 } 357 358 // SetAddr sets the address of the peer. 359 func (p *baseBridgePeer) SetAddr(addr common.Address) { 360 p.addr = addr 361 } 362 363 // GetVersion returns the version of the peer. 364 func (p *baseBridgePeer) GetVersion() int { 365 return p.version 366 } 367 368 // KnowsTx returns if the peer is known to have the transaction, based on knownTxsCache. 369 func (p *baseBridgePeer) KnowsTx(hash common.Hash) bool { 370 _, ok := p.knownTxsCache.Get(hash) 371 return ok 372 } 373 374 // GetP2PPeer returns the p2p.Peer. 375 func (p *baseBridgePeer) GetP2PPeer() *p2p.Peer { 376 return p.Peer 377 } 378 379 // GetRW returns the MsgReadWriter of the peer. 380 func (p *baseBridgePeer) GetRW() p2p.MsgReadWriter { 381 return p.rw 382 } 383 384 // Handle is the callback invoked to manage the life cycle of a Klaytn Peer. When 385 // this function terminates, the Peer is disconnected. 386 func (p *baseBridgePeer) Handle(bn *MainBridge) error { 387 return bn.handle(p) 388 } 389 390 // singleChannelPeer is a peer that uses a single channel. 391 type singleChannelPeer struct { 392 *baseBridgePeer 393 } 394 395 // bridgePeerSet represents the collection of active peers currently participating in 396 // the Klaytn sub-protocol. 397 type bridgePeerSet struct { 398 peers map[string]BridgePeer 399 lock sync.RWMutex 400 closed bool 401 } 402 403 // newBridgePeerSet creates a new peer set to track the active participants. 404 func newBridgePeerSet() *bridgePeerSet { 405 peerSet := &bridgePeerSet{ 406 peers: make(map[string]BridgePeer), 407 } 408 409 return peerSet 410 } 411 412 // Register injects a new peer into the working set, or returns an error if the 413 // peer is already known. 414 func (ps *bridgePeerSet) Register(p BridgePeer) error { 415 ps.lock.Lock() 416 defer ps.lock.Unlock() 417 418 if ps.closed { 419 return errClosed 420 } 421 if _, ok := ps.peers[p.GetID()]; ok { 422 return errAlreadyRegistered 423 } 424 ps.peers[p.GetID()] = p 425 426 return nil 427 } 428 429 // Unregister removes a remote peer from the active set, disabling any further 430 // actions to/from that particular entity. 431 func (ps *bridgePeerSet) Unregister(id string) error { 432 ps.lock.Lock() 433 defer ps.lock.Unlock() 434 435 p, ok := ps.peers[id] 436 if !ok { 437 return errNotRegistered 438 } 439 delete(ps.peers, id) 440 p.Close() 441 442 return nil 443 } 444 445 // istanbul BFT 446 func (ps *bridgePeerSet) Peers() map[string]BridgePeer { 447 ps.lock.RLock() 448 defer ps.lock.RUnlock() 449 450 set := make(map[string]BridgePeer) 451 for id, p := range ps.peers { 452 set[id] = p 453 } 454 return set 455 } 456 457 // Peer retrieves the registered peer with the given id. 458 func (ps *bridgePeerSet) Peer(id string) BridgePeer { 459 ps.lock.RLock() 460 defer ps.lock.RUnlock() 461 462 return ps.peers[id] 463 } 464 465 // Len returns if the current number of peers in the set. 466 func (ps *bridgePeerSet) Len() int { 467 ps.lock.RLock() 468 defer ps.lock.RUnlock() 469 470 return len(ps.peers) 471 } 472 473 // PeersWithoutTx retrieves a list of peers that do not have a given transaction 474 // in their set of known hashes. 475 func (ps *bridgePeerSet) PeersWithoutTx(hash common.Hash) []BridgePeer { 476 ps.lock.RLock() 477 defer ps.lock.RUnlock() 478 479 list := make([]BridgePeer, 0, len(ps.peers)) 480 for _, p := range ps.peers { 481 if !p.KnowsTx(hash) { 482 list = append(list, p) 483 } 484 } 485 return list 486 } 487 488 // BestPeer retrieves the known peer with the currently highest total blockscore. 489 func (ps *bridgePeerSet) BestPeer() BridgePeer { 490 ps.lock.RLock() 491 defer ps.lock.RUnlock() 492 493 var ( 494 bestPeer BridgePeer 495 bestTd *big.Int 496 ) 497 for _, p := range ps.peers { 498 if _, td := p.Head(); bestPeer == nil || td.Cmp(bestTd) > 0 { 499 bestPeer, bestTd = p, td 500 } 501 } 502 return bestPeer 503 } 504 505 // Close disconnects all peers. 506 // No new peers can be registered after Close has returned. 507 func (ps *bridgePeerSet) Close() { 508 ps.lock.Lock() 509 defer ps.lock.Unlock() 510 511 for _, p := range ps.peers { 512 p.GetP2PPeer().Disconnect(p2p.DiscQuitting) 513 } 514 ps.closed = true 515 }