github.com/gobitfly/go-ethereum@v1.8.12/swarm/network/hive.go (about)

     1  // Copyright 2016 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 network
    18  
    19  import (
    20  	"fmt"
    21  	"sync"
    22  	"time"
    23  
    24  	"github.com/ethereum/go-ethereum/common/hexutil"
    25  	"github.com/ethereum/go-ethereum/p2p"
    26  	"github.com/ethereum/go-ethereum/p2p/discover"
    27  	"github.com/ethereum/go-ethereum/swarm/log"
    28  	"github.com/ethereum/go-ethereum/swarm/state"
    29  )
    30  
    31  /*
    32  Hive is the logistic manager of the swarm
    33  
    34  When the hive is started, a forever loop is launched that
    35  asks the Overlay Topology driver (e.g., generic kademlia nodetable)
    36  to suggest peers to bootstrap connectivity
    37  */
    38  
    39  // Overlay is the interface for kademlia (or other topology drivers)
    40  type Overlay interface {
    41  	// suggest peers to connect to
    42  	SuggestPeer() (OverlayAddr, int, bool)
    43  	// register and deregister peer connections
    44  	On(OverlayConn) (depth uint8, changed bool)
    45  	Off(OverlayConn)
    46  	// register peer addresses
    47  	Register([]OverlayAddr) error
    48  	// iterate over connected peers
    49  	EachConn([]byte, int, func(OverlayConn, int, bool) bool)
    50  	// iterate over known peers (address records)
    51  	EachAddr([]byte, int, func(OverlayAddr, int, bool) bool)
    52  	// pretty print the connectivity
    53  	String() string
    54  	// base Overlay address of the node itself
    55  	BaseAddr() []byte
    56  	// connectivity health check used for testing
    57  	Healthy(*PeerPot) *Health
    58  }
    59  
    60  // HiveParams holds the config options to hive
    61  type HiveParams struct {
    62  	Discovery             bool  // if want discovery of not
    63  	PeersBroadcastSetSize uint8 // how many peers to use when relaying
    64  	MaxPeersPerRequest    uint8 // max size for peer address batches
    65  	KeepAliveInterval     time.Duration
    66  }
    67  
    68  // NewHiveParams returns hive config with only the
    69  func NewHiveParams() *HiveParams {
    70  	return &HiveParams{
    71  		Discovery:             true,
    72  		PeersBroadcastSetSize: 3,
    73  		MaxPeersPerRequest:    5,
    74  		KeepAliveInterval:     500 * time.Millisecond,
    75  	}
    76  }
    77  
    78  // Hive manages network connections of the swarm node
    79  type Hive struct {
    80  	*HiveParams                      // settings
    81  	Overlay                          // the overlay connectiviy driver
    82  	Store       state.Store          // storage interface to save peers across sessions
    83  	addPeer     func(*discover.Node) // server callback to connect to a peer
    84  	// bookkeeping
    85  	lock   sync.Mutex
    86  	ticker *time.Ticker
    87  }
    88  
    89  // NewHive constructs a new hive
    90  // HiveParams: config parameters
    91  // Overlay: connectivity driver using a network topology
    92  // StateStore: to save peers across sessions
    93  func NewHive(params *HiveParams, overlay Overlay, store state.Store) *Hive {
    94  	return &Hive{
    95  		HiveParams: params,
    96  		Overlay:    overlay,
    97  		Store:      store,
    98  	}
    99  }
   100  
   101  // Start stars the hive, receives p2p.Server only at startup
   102  // server is used to connect to a peer based on its NodeID or enode URL
   103  // these are called on the p2p.Server which runs on the node
   104  func (h *Hive) Start(server *p2p.Server) error {
   105  	log.Info(fmt.Sprintf("%08x hive starting", h.BaseAddr()[:4]))
   106  	// if state store is specified, load peers to prepopulate the overlay address book
   107  	if h.Store != nil {
   108  		log.Info("detected an existing store. trying to load peers")
   109  		if err := h.loadPeers(); err != nil {
   110  			log.Error(fmt.Sprintf("%08x hive encoutered an error trying to load peers", h.BaseAddr()[:4]))
   111  			return err
   112  		}
   113  	}
   114  	// assigns the p2p.Server#AddPeer function to connect to peers
   115  	h.addPeer = server.AddPeer
   116  	// ticker to keep the hive alive
   117  	h.ticker = time.NewTicker(h.KeepAliveInterval)
   118  	// this loop is doing bootstrapping and maintains a healthy table
   119  	go h.connect()
   120  	return nil
   121  }
   122  
   123  // Stop terminates the updateloop and saves the peers
   124  func (h *Hive) Stop() error {
   125  	log.Info(fmt.Sprintf("%08x hive stopping, saving peers", h.BaseAddr()[:4]))
   126  	h.ticker.Stop()
   127  	if h.Store != nil {
   128  		if err := h.savePeers(); err != nil {
   129  			return fmt.Errorf("could not save peers to persistence store: %v", err)
   130  		}
   131  		if err := h.Store.Close(); err != nil {
   132  			return fmt.Errorf("could not close file handle to persistence store: %v", err)
   133  		}
   134  	}
   135  	log.Info(fmt.Sprintf("%08x hive stopped, dropping peers", h.BaseAddr()[:4]))
   136  	h.EachConn(nil, 255, func(p OverlayConn, _ int, _ bool) bool {
   137  		log.Info(fmt.Sprintf("%08x dropping peer %08x", h.BaseAddr()[:4], p.Address()[:4]))
   138  		p.Drop(nil)
   139  		return true
   140  	})
   141  
   142  	log.Info(fmt.Sprintf("%08x all peers dropped", h.BaseAddr()[:4]))
   143  	return nil
   144  }
   145  
   146  // connect is a forever loop
   147  // at each iteration, ask the overlay driver to suggest the most preferred peer to connect to
   148  // as well as advertises saturation depth if needed
   149  func (h *Hive) connect() {
   150  	for range h.ticker.C {
   151  
   152  		addr, depth, changed := h.SuggestPeer()
   153  		if h.Discovery && changed {
   154  			NotifyDepth(uint8(depth), h)
   155  		}
   156  		if addr == nil {
   157  			continue
   158  		}
   159  
   160  		log.Trace(fmt.Sprintf("%08x hive connect() suggested %08x", h.BaseAddr()[:4], addr.Address()[:4]))
   161  		under, err := discover.ParseNode(string(addr.(Addr).Under()))
   162  		if err != nil {
   163  			log.Warn(fmt.Sprintf("%08x unable to connect to bee %08x: invalid node URL: %v", h.BaseAddr()[:4], addr.Address()[:4], err))
   164  			continue
   165  		}
   166  		log.Trace(fmt.Sprintf("%08x attempt to connect to bee %08x", h.BaseAddr()[:4], addr.Address()[:4]))
   167  		h.addPeer(under)
   168  	}
   169  }
   170  
   171  // Run protocol run function
   172  func (h *Hive) Run(p *BzzPeer) error {
   173  	dp := newDiscovery(p, h)
   174  	depth, changed := h.On(dp)
   175  	// if we want discovery, advertise change of depth
   176  	if h.Discovery {
   177  		if changed {
   178  			// if depth changed, send to all peers
   179  			NotifyDepth(depth, h)
   180  		} else {
   181  			// otherwise just send depth to new peer
   182  			dp.NotifyDepth(depth)
   183  		}
   184  	}
   185  	NotifyPeer(p.Off(), h)
   186  	defer h.Off(dp)
   187  	return dp.Run(dp.HandleMsg)
   188  }
   189  
   190  // NodeInfo function is used by the p2p.server RPC interface to display
   191  // protocol specific node information
   192  func (h *Hive) NodeInfo() interface{} {
   193  	return h.String()
   194  }
   195  
   196  // PeerInfo function is used by the p2p.server RPC interface to display
   197  // protocol specific information any connected peer referred to by their NodeID
   198  func (h *Hive) PeerInfo(id discover.NodeID) interface{} {
   199  	addr := NewAddrFromNodeID(id)
   200  	return struct {
   201  		OAddr hexutil.Bytes
   202  		UAddr hexutil.Bytes
   203  	}{
   204  		OAddr: addr.OAddr,
   205  		UAddr: addr.UAddr,
   206  	}
   207  }
   208  
   209  // ToAddr returns the serialisable version of u
   210  func ToAddr(pa OverlayPeer) *BzzAddr {
   211  	if addr, ok := pa.(*BzzAddr); ok {
   212  		return addr
   213  	}
   214  	if p, ok := pa.(*discPeer); ok {
   215  		return p.BzzAddr
   216  	}
   217  	return pa.(*BzzPeer).BzzAddr
   218  }
   219  
   220  // loadPeers, savePeer implement persistence callback/
   221  func (h *Hive) loadPeers() error {
   222  	var as []*BzzAddr
   223  	err := h.Store.Get("peers", &as)
   224  	if err != nil {
   225  		if err == state.ErrNotFound {
   226  			log.Info(fmt.Sprintf("hive %08x: no persisted peers found", h.BaseAddr()[:4]))
   227  			return nil
   228  		}
   229  		return err
   230  	}
   231  	log.Info(fmt.Sprintf("hive %08x: peers loaded", h.BaseAddr()[:4]))
   232  
   233  	return h.Register(toOverlayAddrs(as...))
   234  }
   235  
   236  // toOverlayAddrs transforms an array of BzzAddr to OverlayAddr
   237  func toOverlayAddrs(as ...*BzzAddr) (oas []OverlayAddr) {
   238  	for _, a := range as {
   239  		oas = append(oas, OverlayAddr(a))
   240  	}
   241  	return
   242  }
   243  
   244  // savePeers, savePeer implement persistence callback/
   245  func (h *Hive) savePeers() error {
   246  	var peers []*BzzAddr
   247  	h.Overlay.EachAddr(nil, 256, func(pa OverlayAddr, i int, _ bool) bool {
   248  		if pa == nil {
   249  			log.Warn(fmt.Sprintf("empty addr: %v", i))
   250  			return true
   251  		}
   252  		apa := ToAddr(pa)
   253  		log.Trace("saving peer", "peer", apa)
   254  		peers = append(peers, apa)
   255  		return true
   256  	})
   257  	if err := h.Store.Put("peers", peers); err != nil {
   258  		return fmt.Errorf("could not save peers: %v", err)
   259  	}
   260  	return nil
   261  }