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