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  }