github.com/xfond/vision@v1.8.9-0.20180514135602-f6bc65fc6811/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  	"math/rand"
    22  	"path/filepath"
    23  	"time"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/log"
    27  	"github.com/ethereum/go-ethereum/metrics"
    28  	"github.com/ethereum/go-ethereum/p2p/discover"
    29  	"github.com/ethereum/go-ethereum/p2p/netutil"
    30  	"github.com/ethereum/go-ethereum/swarm/network/kademlia"
    31  	"github.com/ethereum/go-ethereum/swarm/storage"
    32  )
    33  
    34  // Hive is the logistic manager of the swarm
    35  // it uses a generic kademlia nodetable to find best peer list
    36  // for any target
    37  // this is used by the netstore to search for content in the swarm
    38  // the bzz protocol peersMsgData exchange is relayed to Kademlia
    39  // for db storage and filtering
    40  // connections and disconnections are reported and relayed
    41  // to keep the nodetable uptodate
    42  
    43  var (
    44  	peersNumGauge     = metrics.NewRegisteredGauge("network.peers.num", nil)
    45  	addPeerCounter    = metrics.NewRegisteredCounter("network.addpeer.count", nil)
    46  	removePeerCounter = metrics.NewRegisteredCounter("network.removepeer.count", nil)
    47  )
    48  
    49  type Hive struct {
    50  	listenAddr   func() string
    51  	callInterval uint64
    52  	id           discover.NodeID
    53  	addr         kademlia.Address
    54  	kad          *kademlia.Kademlia
    55  	path         string
    56  	quit         chan bool
    57  	toggle       chan bool
    58  	more         chan bool
    59  
    60  	// for testing only
    61  	swapEnabled bool
    62  	syncEnabled bool
    63  	blockRead   bool
    64  	blockWrite  bool
    65  }
    66  
    67  const (
    68  	callInterval = 3000000000
    69  	// bucketSize   = 3
    70  	// maxProx      = 8
    71  	// proxBinSize  = 4
    72  )
    73  
    74  type HiveParams struct {
    75  	CallInterval uint64
    76  	KadDbPath    string
    77  	*kademlia.KadParams
    78  }
    79  
    80  //create default params
    81  func NewDefaultHiveParams() *HiveParams {
    82  	kad := kademlia.NewDefaultKadParams()
    83  	// kad.BucketSize = bucketSize
    84  	// kad.MaxProx = maxProx
    85  	// kad.ProxBinSize = proxBinSize
    86  
    87  	return &HiveParams{
    88  		CallInterval: callInterval,
    89  		KadParams:    kad,
    90  	}
    91  }
    92  
    93  //this can only finally be set after all config options (file, cmd line, env vars)
    94  //have been evaluated
    95  func (self *HiveParams) Init(path string) {
    96  	self.KadDbPath = filepath.Join(path, "bzz-peers.json")
    97  }
    98  
    99  func NewHive(addr common.Hash, params *HiveParams, swapEnabled, syncEnabled bool) *Hive {
   100  	kad := kademlia.New(kademlia.Address(addr), params.KadParams)
   101  	return &Hive{
   102  		callInterval: params.CallInterval,
   103  		kad:          kad,
   104  		addr:         kad.Addr(),
   105  		path:         params.KadDbPath,
   106  		swapEnabled:  swapEnabled,
   107  		syncEnabled:  syncEnabled,
   108  	}
   109  }
   110  
   111  func (self *Hive) SyncEnabled(on bool) {
   112  	self.syncEnabled = on
   113  }
   114  
   115  func (self *Hive) SwapEnabled(on bool) {
   116  	self.swapEnabled = on
   117  }
   118  
   119  func (self *Hive) BlockNetworkRead(on bool) {
   120  	self.blockRead = on
   121  }
   122  
   123  func (self *Hive) BlockNetworkWrite(on bool) {
   124  	self.blockWrite = on
   125  }
   126  
   127  // public accessor to the hive base address
   128  func (self *Hive) Addr() kademlia.Address {
   129  	return self.addr
   130  }
   131  
   132  // Start receives network info only at startup
   133  // listedAddr is a function to retrieve listening address to advertise to peers
   134  // connectPeer is a function to connect to a peer based on its NodeID or enode URL
   135  // there are called on the p2p.Server which runs on the node
   136  func (self *Hive) Start(id discover.NodeID, listenAddr func() string, connectPeer func(string) error) (err error) {
   137  	self.toggle = make(chan bool)
   138  	self.more = make(chan bool)
   139  	self.quit = make(chan bool)
   140  	self.id = id
   141  	self.listenAddr = listenAddr
   142  	err = self.kad.Load(self.path, nil)
   143  	if err != nil {
   144  		log.Warn(fmt.Sprintf("Warning: error reading kaddb '%s' (skipping): %v", self.path, err))
   145  		err = nil
   146  	}
   147  	// this loop is doing bootstrapping and maintains a healthy table
   148  	go self.keepAlive()
   149  	go func() {
   150  		// whenever toggled ask kademlia about most preferred peer
   151  		for alive := range self.more {
   152  			if !alive {
   153  				// receiving false closes the loop while allowing parallel routines
   154  				// to attempt to write to more (remove Peer when shutting down)
   155  				return
   156  			}
   157  			node, need, proxLimit := self.kad.Suggest()
   158  
   159  			if node != nil && len(node.Url) > 0 {
   160  				log.Trace(fmt.Sprintf("call known bee %v", node.Url))
   161  				// enode or any lower level connection address is unnecessary in future
   162  				// discovery table is used to look it up.
   163  				connectPeer(node.Url)
   164  			}
   165  			if need {
   166  				// a random peer is taken from the table
   167  				peers := self.kad.FindClosest(kademlia.RandomAddressAt(self.addr, rand.Intn(self.kad.MaxProx)), 1)
   168  				if len(peers) > 0 {
   169  					// a random address at prox bin 0 is sent for lookup
   170  					randAddr := kademlia.RandomAddressAt(self.addr, proxLimit)
   171  					req := &retrieveRequestMsgData{
   172  						Key: storage.Key(randAddr[:]),
   173  					}
   174  					log.Trace(fmt.Sprintf("call any bee near %v (PO%03d) - messenger bee: %v", randAddr, proxLimit, peers[0]))
   175  					peers[0].(*peer).retrieve(req)
   176  				} else {
   177  					log.Warn(fmt.Sprintf("no peer"))
   178  				}
   179  				log.Trace(fmt.Sprintf("buzz kept alive"))
   180  			} else {
   181  				log.Info(fmt.Sprintf("no need for more bees"))
   182  			}
   183  			select {
   184  			case self.toggle <- need:
   185  			case <-self.quit:
   186  				return
   187  			}
   188  			log.Debug(fmt.Sprintf("queen's address: %v, population: %d (%d)", self.addr, self.kad.Count(), self.kad.DBCount()))
   189  		}
   190  	}()
   191  	return
   192  }
   193  
   194  // keepAlive is a forever loop
   195  // in its awake state it periodically triggers connection attempts
   196  // by writing to self.more until Kademlia Table is saturated
   197  // wake state is toggled by writing to self.toggle
   198  // it restarts if the table becomes non-full again due to disconnections
   199  func (self *Hive) keepAlive() {
   200  	alarm := time.NewTicker(time.Duration(self.callInterval)).C
   201  	for {
   202  		peersNumGauge.Update(int64(self.kad.Count()))
   203  		select {
   204  		case <-alarm:
   205  			if self.kad.DBCount() > 0 {
   206  				select {
   207  				case self.more <- true:
   208  					log.Debug(fmt.Sprintf("buzz wakeup"))
   209  				default:
   210  				}
   211  			}
   212  		case need := <-self.toggle:
   213  			if alarm == nil && need {
   214  				alarm = time.NewTicker(time.Duration(self.callInterval)).C
   215  			}
   216  			if alarm != nil && !need {
   217  				alarm = nil
   218  
   219  			}
   220  		case <-self.quit:
   221  			return
   222  		}
   223  	}
   224  }
   225  
   226  func (self *Hive) Stop() error {
   227  	// closing toggle channel quits the updateloop
   228  	close(self.quit)
   229  	return self.kad.Save(self.path, saveSync)
   230  }
   231  
   232  // called at the end of a successful protocol handshake
   233  func (self *Hive) addPeer(p *peer) error {
   234  	addPeerCounter.Inc(1)
   235  	defer func() {
   236  		select {
   237  		case self.more <- true:
   238  		default:
   239  		}
   240  	}()
   241  	log.Trace(fmt.Sprintf("hi new bee %v", p))
   242  	err := self.kad.On(p, loadSync)
   243  	if err != nil {
   244  		return err
   245  	}
   246  	// self lookup (can be encoded as nil/zero key since peers addr known) + no id ()
   247  	// the most common way of saying hi in bzz is initiation of gossip
   248  	// let me know about anyone new from my hood , here is the storageradius
   249  	// to send the 6 byte self lookup
   250  	// we do not record as request or forward it, just reply with peers
   251  	p.retrieve(&retrieveRequestMsgData{})
   252  	log.Trace(fmt.Sprintf("'whatsup wheresdaparty' sent to %v", p))
   253  
   254  	return nil
   255  }
   256  
   257  // called after peer disconnected
   258  func (self *Hive) removePeer(p *peer) {
   259  	removePeerCounter.Inc(1)
   260  	log.Debug(fmt.Sprintf("bee %v removed", p))
   261  	self.kad.Off(p, saveSync)
   262  	select {
   263  	case self.more <- true:
   264  	default:
   265  	}
   266  	if self.kad.Count() == 0 {
   267  		log.Debug(fmt.Sprintf("empty, all bees gone"))
   268  	}
   269  }
   270  
   271  // Retrieve a list of live peers that are closer to target than us
   272  func (self *Hive) getPeers(target storage.Key, max int) (peers []*peer) {
   273  	var addr kademlia.Address
   274  	copy(addr[:], target[:])
   275  	for _, node := range self.kad.FindClosest(addr, max) {
   276  		peers = append(peers, node.(*peer))
   277  	}
   278  	return
   279  }
   280  
   281  // disconnects all the peers
   282  func (self *Hive) DropAll() {
   283  	log.Info(fmt.Sprintf("dropping all bees"))
   284  	for _, node := range self.kad.FindClosest(kademlia.Address{}, 0) {
   285  		node.Drop()
   286  	}
   287  }
   288  
   289  // contructor for kademlia.NodeRecord based on peer address alone
   290  // TODO: should go away and only addr passed to kademlia
   291  func newNodeRecord(addr *peerAddr) *kademlia.NodeRecord {
   292  	now := time.Now()
   293  	return &kademlia.NodeRecord{
   294  		Addr:  addr.Addr,
   295  		Url:   addr.String(),
   296  		Seen:  now,
   297  		After: now,
   298  	}
   299  }
   300  
   301  // called by the protocol when receiving peerset (for target address)
   302  // peersMsgData is converted to a slice of NodeRecords for Kademlia
   303  // this is to store all thats needed
   304  func (self *Hive) HandlePeersMsg(req *peersMsgData, from *peer) {
   305  	var nrs []*kademlia.NodeRecord
   306  	for _, p := range req.Peers {
   307  		if err := netutil.CheckRelayIP(from.remoteAddr.IP, p.IP); err != nil {
   308  			log.Trace(fmt.Sprintf("invalid peer IP %v from %v: %v", from.remoteAddr.IP, p.IP, err))
   309  			continue
   310  		}
   311  		nrs = append(nrs, newNodeRecord(p))
   312  	}
   313  	self.kad.Add(nrs)
   314  }
   315  
   316  // peer wraps the protocol instance to represent a connected peer
   317  // it implements kademlia.Node interface
   318  type peer struct {
   319  	*bzz // protocol instance running on peer connection
   320  }
   321  
   322  // protocol instance implements kademlia.Node interface (embedded peer)
   323  func (self *peer) Addr() kademlia.Address {
   324  	return self.remoteAddr.Addr
   325  }
   326  
   327  func (self *peer) Url() string {
   328  	return self.remoteAddr.String()
   329  }
   330  
   331  // TODO take into account traffic
   332  func (self *peer) LastActive() time.Time {
   333  	return self.lastActive
   334  }
   335  
   336  // reads the serialised form of sync state persisted as the 'Meta' attribute
   337  // and sets the decoded syncState on the online node
   338  func loadSync(record *kademlia.NodeRecord, node kademlia.Node) error {
   339  	p, ok := node.(*peer)
   340  	if !ok {
   341  		return fmt.Errorf("invalid type")
   342  	}
   343  	if record.Meta == nil {
   344  		log.Debug(fmt.Sprintf("no sync state for node record %v setting default", record))
   345  		p.syncState = &syncState{DbSyncState: &storage.DbSyncState{}}
   346  		return nil
   347  	}
   348  	state, err := decodeSync(record.Meta)
   349  	if err != nil {
   350  		return fmt.Errorf("error decoding kddb record meta info into a sync state: %v", err)
   351  	}
   352  	log.Trace(fmt.Sprintf("sync state for node record %v read from Meta: %s", record, string(*(record.Meta))))
   353  	p.syncState = state
   354  	return err
   355  }
   356  
   357  // callback when saving a sync state
   358  func saveSync(record *kademlia.NodeRecord, node kademlia.Node) {
   359  	if p, ok := node.(*peer); ok {
   360  		meta, err := encodeSync(p.syncState)
   361  		if err != nil {
   362  			log.Warn(fmt.Sprintf("error saving sync state for %v: %v", node, err))
   363  			return
   364  		}
   365  		log.Trace(fmt.Sprintf("saved sync state for %v: %s", node, string(*meta)))
   366  		record.Meta = meta
   367  	}
   368  }
   369  
   370  // the immediate response to a retrieve request,
   371  // sends relevant peer data given by the kademlia hive to the requester
   372  // TODO: remember peers sent for duration of the session, only new peers sent
   373  func (self *Hive) peers(req *retrieveRequestMsgData) {
   374  	if req != nil {
   375  		var addrs []*peerAddr
   376  		if req.timeout == nil || time.Now().Before(*(req.timeout)) {
   377  			key := req.Key
   378  			// self lookup from remote peer
   379  			if storage.IsZeroKey(key) {
   380  				addr := req.from.Addr()
   381  				key = storage.Key(addr[:])
   382  				req.Key = nil
   383  			}
   384  			// get peer addresses from hive
   385  			for _, peer := range self.getPeers(key, int(req.MaxPeers)) {
   386  				addrs = append(addrs, peer.remoteAddr)
   387  			}
   388  			log.Debug(fmt.Sprintf("Hive sending %d peer addresses to %v. req.Id: %v, req.Key: %v", len(addrs), req.from, req.Id, req.Key.Log()))
   389  
   390  			peersData := &peersMsgData{
   391  				Peers: addrs,
   392  				Key:   req.Key,
   393  				Id:    req.Id,
   394  			}
   395  			peersData.setTimeout(req.timeout)
   396  			req.from.peers(peersData)
   397  		}
   398  	}
   399  }
   400  
   401  func (self *Hive) String() string {
   402  	return self.kad.String()
   403  }