Signed-off-by: Leo Chen <leo@harmony.one>pull/372/head
parent
43e39bb52f
commit
6b46b91b0e
@ -0,0 +1,31 @@ |
|||||||
|
package discovery |
||||||
|
|
||||||
|
import ( |
||||||
|
"testing" |
||||||
|
|
||||||
|
"github.com/harmony-one/harmony/internal/utils" |
||||||
|
"github.com/harmony-one/harmony/p2p" |
||||||
|
"github.com/harmony-one/harmony/p2p/p2pimpl" |
||||||
|
) |
||||||
|
|
||||||
|
var ( |
||||||
|
ip = "127.0.0.1" |
||||||
|
port = "7099" |
||||||
|
service *Service |
||||||
|
) |
||||||
|
|
||||||
|
func TestDiscoveryService(t *testing.T) { |
||||||
|
selfPeer := p2p.Peer{IP: ip, Port: port} |
||||||
|
priKey, _, err := utils.GenKeyP2P(ip, port) |
||||||
|
|
||||||
|
host, err := p2pimpl.NewHost(&selfPeer, priKey) |
||||||
|
if err != nil { |
||||||
|
t.Fatalf("unable to new host in harmony: %v", err) |
||||||
|
} |
||||||
|
|
||||||
|
service = New(host, "rendezvous") |
||||||
|
|
||||||
|
if service == nil { |
||||||
|
t.Fatalf("unable to create new discovery service") |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
package discovery |
||||||
|
|
||||||
|
import "errors" |
||||||
|
|
||||||
|
// Errors of peer discovery
|
||||||
|
var ( |
||||||
|
ErrGetPeers = errors.New("[DISCOVERY]: get peer list failed") |
||||||
|
ErrConnectionFull = errors.New("[DISCOVERY]: node's incoming connection full") |
||||||
|
ErrPing = errors.New("[DISCOVERY]: ping peer failed") |
||||||
|
ErrPong = errors.New("[DISCOVERY]: pong peer failed") |
||||||
|
ErrDHTBootstrap = errors.New("[DISCOVERY]: DHT bootstrap failed") |
||||||
|
) |
@ -0,0 +1,118 @@ |
|||||||
|
package discovery |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"io" |
||||||
|
"sync" |
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/log" |
||||||
|
"github.com/harmony-one/harmony/internal/utils" |
||||||
|
"github.com/harmony-one/harmony/p2p" |
||||||
|
|
||||||
|
peerstore "github.com/libp2p/go-libp2p-peerstore" |
||||||
|
|
||||||
|
libp2pdis "github.com/libp2p/go-libp2p-discovery" |
||||||
|
libp2pdht "github.com/libp2p/go-libp2p-kad-dht" |
||||||
|
) |
||||||
|
|
||||||
|
// Constants for discovery service.
|
||||||
|
const ( |
||||||
|
numIncoming = 128 |
||||||
|
numOutgoing = 16 |
||||||
|
) |
||||||
|
|
||||||
|
// Service is the struct for discovery service.
|
||||||
|
type Service struct { |
||||||
|
Host p2p.Host |
||||||
|
DHT *libp2pdht.IpfsDHT |
||||||
|
Rendezvous string |
||||||
|
reader io.Reader |
||||||
|
writer io.Writer |
||||||
|
ctx context.Context |
||||||
|
} |
||||||
|
|
||||||
|
// New returns discovery service.
|
||||||
|
// h is the p2p host
|
||||||
|
// r is the rendezvous string, we use shardID to start (TODO: leo, build two overlays of network)
|
||||||
|
func New(h p2p.Host, r string) *Service { |
||||||
|
ctx := context.Background() |
||||||
|
dht, err := libp2pdht.New(ctx, h.GetP2PHost()) |
||||||
|
if err != nil { |
||||||
|
panic(err) |
||||||
|
} |
||||||
|
|
||||||
|
return &Service{ |
||||||
|
Host: h, |
||||||
|
DHT: dht, |
||||||
|
Rendezvous: r, |
||||||
|
ctx: ctx, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// StartService starts discovery service.
|
||||||
|
func (s *Service) StartService() { |
||||||
|
log.Info("Starting discovery service.") |
||||||
|
err := s.Init() |
||||||
|
if err != nil { |
||||||
|
log.Error("StartService Aborted", "Error", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// We use a rendezvous point "shardID" to announce our location.
|
||||||
|
log.Info("Announcing ourselves...") |
||||||
|
routingDiscovery := libp2pdis.NewRoutingDiscovery(s.DHT) |
||||||
|
libp2pdis.Advertise(s.ctx, routingDiscovery, s.Rendezvous) |
||||||
|
log.Debug("Successfully announced!") |
||||||
|
|
||||||
|
log.Debug("Searching for other peers...") |
||||||
|
peerChan, err := routingDiscovery.FindPeers(s.ctx, s.Rendezvous) |
||||||
|
if err != nil { |
||||||
|
log.Error("FindPeers", "error", err) |
||||||
|
} |
||||||
|
|
||||||
|
for peer := range peerChan { |
||||||
|
// skip myself
|
||||||
|
if peer.ID == s.Host.GetP2PHost().ID() { |
||||||
|
continue |
||||||
|
} |
||||||
|
log.Debug("Found peer", "adding peer", peer) |
||||||
|
p := p2p.Peer{PeerID: peer.ID, Addrs: peer.Addrs} |
||||||
|
s.Host.AddPeer(&p) |
||||||
|
} |
||||||
|
|
||||||
|
select {} |
||||||
|
} |
||||||
|
|
||||||
|
// StopService shutdowns discovery service.
|
||||||
|
func (s *Service) StopService() { |
||||||
|
log.Info("Shutting down discovery service.") |
||||||
|
} |
||||||
|
|
||||||
|
// Init is to initialize for discoveryService.
|
||||||
|
func (s *Service) Init() error { |
||||||
|
log.Info("Init discovery service") |
||||||
|
|
||||||
|
// Bootstrap the DHT. In the default configuration, this spawns a Background
|
||||||
|
// thread that will refresh the peer table every five minutes.
|
||||||
|
log.Debug("Bootstrapping the DHT") |
||||||
|
if err := s.DHT.Bootstrap(s.ctx); err != nil { |
||||||
|
return ErrDHTBootstrap |
||||||
|
} |
||||||
|
|
||||||
|
var wg sync.WaitGroup |
||||||
|
for _, peerAddr := range utils.BootNodes { |
||||||
|
peerinfo, _ := peerstore.InfoFromP2pAddr(peerAddr) |
||||||
|
wg.Add(1) |
||||||
|
go func() { |
||||||
|
defer wg.Done() |
||||||
|
if err := s.Host.GetP2PHost().Connect(s.ctx, *peerinfo); err != nil { |
||||||
|
log.Warn("can't connect to bootnode", "error", err) |
||||||
|
} else { |
||||||
|
log.Info("connected to bootnode", "node", *peerinfo) |
||||||
|
} |
||||||
|
}() |
||||||
|
} |
||||||
|
wg.Wait() |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
Loading…
Reference in new issue