go-libp2p-peerstore/peerstore.go

362 lines
8.2 KiB
Go
Raw Normal View History

2016-06-01 02:31:50 +08:00
package peerstore
2015-10-01 06:42:55 +08:00
import (
2016-10-05 07:19:16 +08:00
"context"
2015-10-01 06:42:55 +08:00
"errors"
"fmt"
2015-10-01 06:42:55 +08:00
"sync"
"time"
2017-02-04 04:49:59 +08:00
ic "github.com/libp2p/go-libp2p-crypto"
2015-10-01 06:42:55 +08:00
2015-11-19 03:47:51 +08:00
//ds "github.com/jbenet/go-datastore"
//dssync "github.com/jbenet/go-datastore/sync"
2018-06-14 07:27:57 +08:00
"github.com/ipfs/go-datastore"
2017-02-04 04:49:59 +08:00
logging "github.com/ipfs/go-log"
"github.com/libp2p/go-libp2p-peer"
ma "github.com/multiformats/go-multiaddr"
2015-10-01 06:42:55 +08:00
)
2016-06-01 02:31:50 +08:00
var log = logging.Logger("peerstore")
2015-10-01 06:42:55 +08:00
const (
// AddressTTL is the expiration time of addresses.
AddressTTL = time.Hour
)
// Peerstore provides a threadsafe store of Peer related
// information.
type Peerstore interface {
AddrBook
KeyBook
Metrics
// PeerInfo returns a peer.PeerInfo struct for given peer.ID.
// This is a small slice of the information Peerstore has on
// that peer, useful to other services.
2016-06-01 02:31:50 +08:00
PeerInfo(peer.ID) PeerInfo
2015-10-01 06:42:55 +08:00
// Get/Put is a simple registry for other peer-related key/value pairs.
// if we find something we use often, it should become its own set of
// methods. this is a last resort.
2016-06-01 02:31:50 +08:00
Get(id peer.ID, key string) (interface{}, error)
Put(id peer.ID, key string, val interface{}) error
GetProtocols(peer.ID) ([]string, error)
AddProtocols(peer.ID, ...string) error
SetProtocols(peer.ID, ...string) error
SupportsProtocols(peer.ID, ...string) ([]string, error)
2015-10-01 06:42:55 +08:00
}
// AddrBook is an interface that fits the new AddrManager. I'm patching
// it up in here to avoid changing a ton of the codebase.
type AddrBook interface {
// AddAddr calls AddAddrs(p, []ma.Multiaddr{addr}, ttl)
2016-06-01 02:31:50 +08:00
AddAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration)
2015-10-01 06:42:55 +08:00
// AddAddrs gives AddrManager addresses to use, with a given ttl
// (time-to-live), after which the address is no longer valid.
// If the manager has a longer TTL, the operation is a no-op for that address
2016-06-01 02:31:50 +08:00
AddAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duration)
2015-10-01 06:42:55 +08:00
// SetAddr calls mgr.SetAddrs(p, addr, ttl)
2016-06-01 02:31:50 +08:00
SetAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration)
2015-10-01 06:42:55 +08:00
// SetAddrs sets the ttl on addresses. This clears any TTL there previously.
// This is used when we receive the best estimate of the validity of an address.
2016-06-01 02:31:50 +08:00
SetAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duration)
2015-10-01 06:42:55 +08:00
// UpdateAddrs updates the addresses associated with the given peer that have
// the given oldTTL to have the given newTTL.
UpdateAddrs(p peer.ID, oldTTL time.Duration, newTTL time.Duration)
2016-08-20 05:51:59 +08:00
// Addresses returns all known (and valid) addresses for a given peer
2016-06-01 02:31:50 +08:00
Addrs(p peer.ID) []ma.Multiaddr
2015-10-01 06:42:55 +08:00
// AddrStream returns a channel that gets all addresses for a given
// peer sent on it. If new addresses are added after the call is made
// they will be sent along through the channel as well.
2016-06-01 02:31:50 +08:00
AddrStream(context.Context, peer.ID) <-chan ma.Multiaddr
2015-10-01 06:42:55 +08:00
// ClearAddresses removes all previously stored addresses
2016-06-01 02:31:50 +08:00
ClearAddrs(p peer.ID)
2018-06-14 07:27:14 +08:00
// Peers returns all of the peer IDs stored in the AddrBook
Peers() []peer.ID
2015-10-01 06:42:55 +08:00
}
// KeyBook tracks the Public keys of Peers.
type KeyBook interface {
2016-06-01 02:31:50 +08:00
PubKey(peer.ID) ic.PubKey
AddPubKey(peer.ID, ic.PubKey) error
2015-10-01 06:42:55 +08:00
2016-06-01 02:31:50 +08:00
PrivKey(peer.ID) ic.PrivKey
AddPrivKey(peer.ID, ic.PrivKey) error
2015-10-01 06:42:55 +08:00
}
type keybook struct {
2016-06-01 02:31:50 +08:00
pks map[peer.ID]ic.PubKey
sks map[peer.ID]ic.PrivKey
2015-10-01 06:42:55 +08:00
sync.RWMutex // same lock. wont happen a ton.
}
func newKeybook() *keybook {
return &keybook{
2016-06-01 02:31:50 +08:00
pks: map[peer.ID]ic.PubKey{},
sks: map[peer.ID]ic.PrivKey{},
2015-10-01 06:42:55 +08:00
}
}
2016-06-01 02:31:50 +08:00
func (kb *keybook) Peers() []peer.ID {
2015-10-01 06:42:55 +08:00
kb.RLock()
2016-06-01 02:31:50 +08:00
ps := make([]peer.ID, 0, len(kb.pks)+len(kb.sks))
2015-10-01 06:42:55 +08:00
for p := range kb.pks {
ps = append(ps, p)
}
for p := range kb.sks {
if _, found := kb.pks[p]; !found {
ps = append(ps, p)
}
}
kb.RUnlock()
return ps
}
2016-06-01 02:31:50 +08:00
func (kb *keybook) PubKey(p peer.ID) ic.PubKey {
2015-10-01 06:42:55 +08:00
kb.RLock()
pk := kb.pks[p]
kb.RUnlock()
if pk != nil {
return pk
}
pk, err := p.ExtractPublicKey()
if err == nil && pk != nil {
kb.Lock()
kb.pks[p] = pk
kb.Unlock()
}
2015-10-01 06:42:55 +08:00
return pk
}
2016-06-01 02:31:50 +08:00
func (kb *keybook) AddPubKey(p peer.ID, pk ic.PubKey) error {
2015-10-01 06:42:55 +08:00
// check it's correct first
if !p.MatchesPublicKey(pk) {
return errors.New("ID does not match PublicKey")
}
kb.Lock()
kb.pks[p] = pk
kb.Unlock()
return nil
}
2016-06-01 02:31:50 +08:00
func (kb *keybook) PrivKey(p peer.ID) ic.PrivKey {
2015-10-01 06:42:55 +08:00
kb.RLock()
sk := kb.sks[p]
kb.RUnlock()
return sk
}
2016-06-01 02:31:50 +08:00
func (kb *keybook) AddPrivKey(p peer.ID, sk ic.PrivKey) error {
2015-10-01 06:42:55 +08:00
if sk == nil {
return errors.New("sk is nil (PrivKey)")
}
// check it's correct first
if !p.MatchesPrivateKey(sk) {
return errors.New("ID does not match PrivateKey")
}
kb.Lock()
kb.sks[p] = sk
kb.Unlock()
return nil
}
type peerstore struct {
2016-10-05 09:01:51 +08:00
*keybook
*metrics
2018-06-14 07:27:14 +08:00
AddrBook
2015-10-01 06:42:55 +08:00
// store other data, like versions
2015-11-19 03:47:51 +08:00
//ds ds.ThreadSafeDatastore
// TODO: use a datastore for this
ds map[string]interface{}
dslock sync.Mutex
2016-08-20 05:51:59 +08:00
// lock for protocol information, separate from datastore lock
protolock sync.Mutex
2015-10-01 06:42:55 +08:00
}
// NewPeerstore creates a threadsafe collection of peers.
func NewPeerstore() Peerstore {
return &peerstore{
2018-06-14 07:27:57 +08:00
keybook: newKeybook(),
metrics: NewMetrics(),
AddrBook: &AddrManager{},
ds: make(map[string]interface{}),
}
}
// NewPeerstoreDatastore creates a threadsafe collection of peers backed by a
// Datastore to prevent excess memory pressure.
2018-06-27 07:06:05 +08:00
func NewPeerstoreDatastore(ctx context.Context, ds datastore.Batching) (Peerstore, error) {
addrBook, err := NewDatastoreAddrManager(ctx, ds, time.Second)
if err != nil {
return nil, err
}
ps := &peerstore{
2018-06-14 07:27:57 +08:00
keybook: newKeybook(),
metrics: NewMetrics(),
2018-06-27 07:06:05 +08:00
AddrBook: addrBook,
2018-06-14 07:27:57 +08:00
ds: make(map[string]interface{}),
2015-10-01 06:42:55 +08:00
}
2018-06-27 07:06:05 +08:00
return ps, nil
2015-10-01 06:42:55 +08:00
}
2016-06-01 02:31:50 +08:00
func (ps *peerstore) Put(p peer.ID, key string, val interface{}) error {
2015-11-19 03:47:51 +08:00
//dsk := ds.NewKey(string(p) + "/" + key)
//return ps.ds.Put(dsk, val)
ps.dslock.Lock()
defer ps.dslock.Unlock()
ps.ds[string(p)+"/"+key] = val
return nil
2015-10-01 06:42:55 +08:00
}
var ErrNotFound = errors.New("item not found")
2016-06-01 02:31:50 +08:00
func (ps *peerstore) Get(p peer.ID, key string) (interface{}, error) {
2015-11-19 03:47:51 +08:00
//dsk := ds.NewKey(string(p) + "/" + key)
//return ps.ds.Get(dsk)
ps.dslock.Lock()
defer ps.dslock.Unlock()
i, ok := ps.ds[string(p)+"/"+key]
if !ok {
return nil, ErrNotFound
2015-11-19 03:47:51 +08:00
}
return i, nil
2015-10-01 06:42:55 +08:00
}
2016-06-01 02:31:50 +08:00
func (ps *peerstore) Peers() []peer.ID {
set := map[peer.ID]struct{}{}
2015-10-01 06:42:55 +08:00
for _, p := range ps.keybook.Peers() {
set[p] = struct{}{}
}
2018-06-14 07:27:14 +08:00
for _, p := range ps.AddrBook.Peers() {
2015-10-01 06:42:55 +08:00
set[p] = struct{}{}
}
2016-06-01 02:31:50 +08:00
pps := make([]peer.ID, 0, len(set))
2015-10-01 06:42:55 +08:00
for p := range set {
pps = append(pps, p)
}
return pps
}
2016-06-01 02:31:50 +08:00
func (ps *peerstore) PeerInfo(p peer.ID) PeerInfo {
2015-10-01 06:42:55 +08:00
return PeerInfo{
ID: p,
2018-06-14 07:27:14 +08:00
Addrs: ps.AddrBook.Addrs(p),
2015-10-01 06:42:55 +08:00
}
}
func (ps *peerstore) SetProtocols(p peer.ID, protos ...string) error {
ps.protolock.Lock()
defer ps.protolock.Unlock()
protomap := make(map[string]struct{})
for _, proto := range protos {
protomap[proto] = struct{}{}
}
return ps.Put(p, "protocols", protomap)
}
func (ps *peerstore) AddProtocols(p peer.ID, protos ...string) error {
2016-08-20 05:51:59 +08:00
ps.protolock.Lock()
defer ps.protolock.Unlock()
protomap, err := ps.getProtocolMap(p)
if err != nil {
return err
}
for _, proto := range protos {
protomap[proto] = struct{}{}
}
return ps.Put(p, "protocols", protomap)
}
func (ps *peerstore) getProtocolMap(p peer.ID) (map[string]struct{}, error) {
iprotomap, err := ps.Get(p, "protocols")
switch err {
default:
return nil, err
case ErrNotFound:
return make(map[string]struct{}), nil
case nil:
cast, ok := iprotomap.(map[string]struct{})
if !ok {
return nil, fmt.Errorf("stored protocol set was not a map")
}
return cast, nil
}
}
func (ps *peerstore) GetProtocols(p peer.ID) ([]string, error) {
2016-08-20 05:51:59 +08:00
ps.protolock.Lock()
defer ps.protolock.Unlock()
pmap, err := ps.getProtocolMap(p)
if err != nil {
return nil, err
}
var out []string
for k, _ := range pmap {
out = append(out, k)
}
return out, nil
}
func (ps *peerstore) SupportsProtocols(p peer.ID, protos ...string) ([]string, error) {
2016-08-20 05:51:59 +08:00
ps.protolock.Lock()
defer ps.protolock.Unlock()
pmap, err := ps.getProtocolMap(p)
if err != nil {
return nil, err
}
var out []string
for _, proto := range protos {
if _, ok := pmap[proto]; ok {
out = append(out, proto)
}
}
return out, nil
}
2016-06-01 02:31:50 +08:00
func PeerInfos(ps Peerstore, peers []peer.ID) []PeerInfo {
2015-10-01 06:42:55 +08:00
pi := make([]PeerInfo, len(peers))
for i, p := range peers {
pi[i] = ps.PeerInfo(p)
}
return pi
}
2016-06-01 02:31:50 +08:00
func PeerInfoIDs(pis []PeerInfo) []peer.ID {
ps := make([]peer.ID, len(pis))
2015-10-01 06:42:55 +08:00
for i, pi := range pis {
ps[i] = pi.ID
}
return ps
}