diff --git a/peerstore/labels.go b/peerstore/labels.go new file mode 100644 index 00000000..e4309386 --- /dev/null +++ b/peerstore/labels.go @@ -0,0 +1,82 @@ +package peerstore + +import ( + "fmt" + "sync" +) + +// Label is an arbitrary label attached to an address or a peer. A Label can +// indicate the source of an address, a "pin" by a subsystem, an address scope, +// or an arbitrary tag. +// +// Labels are byte values in binary format, bound to strings via the `BindLabel` +// function to facilitate debugging. +// +// Values [0x00, 0x80) are RESERVED for the developers of libp2p. Users are free +// to register custom application-level labels in the range [0x80, 0xff], via +// the BindLabel function. +type Label uint8 + +const ( + // LabelSourceUnknown means that the source of an address is unknown. + // + // This is usually the case when an address has been inserted through the + // legacy methods of the peerstore. + LabelSourceUnknown = Label(0x00) + + // LabelSourceThirdParty indicates that we've learnt this address via a + // third party. + LabelSourceThirdParty = Label(0x01) + + // LabelSourceUncertified means that an address has been returned by the + // peer in question, but it is not authenticated, i.e. it is not part of a + // certified peer record. + LabelSourceUncertified = Label(0x02) + + // LabelSourceCertified means that the address is part of a standard + // certified libp2p peer record. + LabelSourceCertified = Label(0x03) + + // LabelSourceManual means that an address has been specified manually by a + // human, and therefore should take high precedence. + LabelSourceManual = Label(0x04) +) + +var ( + // labelsLk only guards registration (i.e. writes, not reads). + // + // It is assumed that user-defined labels will be registered during system + // initialisation. Once the system becomes operational, the descriptions are + // accessed by the String() method *without taking a lock*. + labelsLk sync.Mutex + + // labelsTable stores label allocations and their string mappings. + labelsTable = [256]string{ + 0x00: "unknown", + 0x01: "third_party", + 0x02: "untrusted", + 0x03: "trusted", + 0x04: "manual", + } +) + +func (p Label) String() string { + return labelsTable[p] +} + +// BindLabel registers a user-defined label and binds it to a string +// description. +func BindLabel(p Label, desc string) error { + labelsLk.Lock() + defer labelsLk.Unlock() + + if p < 0x80 { + return fmt.Errorf("failed to register user-defined peerstore label "+ + "due to range violation; should be in [0x80,0xff]; was: %x", p) + } + if d := labelsTable[p]; d != "" { + return fmt.Errorf("a label mapping for %x already exists: %s", p, d) + } + labelsTable[p] = desc + return nil +} diff --git a/peerstore/options.go b/peerstore/options.go new file mode 100644 index 00000000..5d63f0fe --- /dev/null +++ b/peerstore/options.go @@ -0,0 +1,43 @@ +package peerstore + +// WriteOpt is an option to be used in peerstore write operations. +type WriteOpt func(*writeOpts) error + +// ReadOpt is an option to be used in peerstore read/query operations. +type ReadOpt func(*readOpts) error + +type writeOpts struct { + labels []Label +} + +type readOpts struct { + includeLabels []Label + excludeLabels []Label +} + +// Labels is a write option to set labels on addresses or peers during a write +// operation. +func Labels(labels ...Label) WriteOpt { + return func(wo *writeOpts) error { + wo.labels = labels + return nil + } +} + +// IncludeLabels is a read option that restricts the results of a read/query +// operation to include ONLY addresses or peers with the listed labels. +func IncludeLabels(labels ...Label) ReadOpt { + return func(ro *readOpts) error { + ro.includeLabels = labels + return nil + } +} + +// ExcludeLabels is a read option that restricts the results of a read/query +// operation to include all hits BUT the ones with the listed labels. +func ExcludeLabels(labels ...Label) ReadOpt { + return func(ro *readOpts) error { + ro.excludeLabels = labels + return nil + } +} diff --git a/peerstore/peerstore.go b/peerstore/peerstore.go index e77b3c13..84953a4f 100644 --- a/peerstore/peerstore.go +++ b/peerstore/peerstore.go @@ -88,38 +88,38 @@ type PeerMetadata interface { // AddrBook holds the multiaddrs of peers. type AddrBook interface { - // AddAddr calls AddAddrs(p, []ma.Multiaddr{addr}, ttl) - AddAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration) + // AddAddr calls AddAddrs(p, []ma.Multiaddr{addr}, ttl, opts...) + AddAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration, opts ...WriteOpt) // AddAddrs gives this AddrBook 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 - AddAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duration) + AddAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duration, opts ...WriteOpt) - // SetAddr calls mgr.SetAddrs(p, addr, ttl) - SetAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration) + // SetAddr calls SetAddrs(p, []ma.Multiaddr{addr}, ttl, opts...) + SetAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration, opts ...WriteOpt) // 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. - SetAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duration) + SetAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duration, opts ...WriteOpt) // 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) + UpdateAddrs(p peer.ID, oldTTL time.Duration, newTTL time.Duration, opts ...WriteOpt) // Addrs returns all known (and valid) addresses for a given peer. - Addrs(p peer.ID) []ma.Multiaddr + Addrs(p peer.ID, opts ...ReadOpt) []ma.Multiaddr // 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. - AddrStream(context.Context, peer.ID) <-chan ma.Multiaddr + AddrStream(context.Context, peer.ID, ...ReadOpt) <-chan ma.Multiaddr // ClearAddresses removes all previously stored addresses - ClearAddrs(p peer.ID) + ClearAddrs(p peer.ID, opts ...WriteOpt) // PeersWithAddrs returns all of the peer IDs stored in the AddrBook - PeersWithAddrs() peer.IDSlice + PeersWithAddrs(...ReadOpt) peer.IDSlice } // CertifiedAddrBook manages "self-certified" addresses for remote peers.