Commit c754f210 authored by Juan Batiz-Benet's avatar Juan Batiz-Benet
Browse files

p2p/protocol/identify: dont double count observers

If the same peer observed the same address twice, it would be
double counted as different observations. This change adds a map
to make sure we're counting each observer once.

This is easily extended to require more than two observations,
but i have not yet encountered NATs for whom this is relevant.
parent 2acaf71e
......@@ -256,7 +256,7 @@ func (ids *IDService) consumeObservedAddress(observed []byte, c inet.Conn) {
// ok! we have the observed version of one of our ListenAddresses!
log.Debugf("added own observed listen addr: %s --> %s", c.LocalMultiaddr(), maddr)
ids.observedAddrs.Add(maddr)
ids.observedAddrs.Add(maddr, c.RemoteMultiaddr())
}
func addrInAddrs(a ma.Multiaddr, as []ma.Multiaddr) bool {
......
......@@ -15,9 +15,9 @@ import (
// - have been observed recently (10min), because our position in the
// network, or network port mapppings, may have changed.
type ObservedAddr struct {
Addr ma.Multiaddr
LastSeen time.Time
TimesSeen int
Addr ma.Multiaddr
SeenBy map[string]struct{}
LastSeen time.Time
}
// ObservedAddrSet keeps track of a set of ObservedAddrs
......@@ -25,7 +25,7 @@ type ObservedAddr struct {
type ObservedAddrSet struct {
sync.Mutex // guards whole datastruct.
addrs map[string]ObservedAddr
addrs map[string]*ObservedAddr
ttl time.Duration
}
......@@ -54,29 +54,40 @@ func (oas *ObservedAddrSet) Addrs() []ma.Multiaddr {
// very useful. We make the assumption that if we've
// connected to two different peers, and they both have
// reported seeing the same address, it is probably useful.
if a.TimesSeen > 1 {
//
// Note: make sure not to double count observers.
if len(a.SeenBy) > 1 {
addrs = append(addrs, a.Addr)
}
}
return addrs
}
func (oas *ObservedAddrSet) Add(addr ma.Multiaddr) {
func (oas *ObservedAddrSet) Add(addr ma.Multiaddr, observer ma.Multiaddr) {
oas.Lock()
defer oas.Unlock()
// for zero-value.
if oas.addrs == nil {
oas.addrs = make(map[string]ObservedAddr)
oas.addrs = make(map[string]*ObservedAddr)
oas.ttl = peer.OwnObservedAddrTTL
}
s := addr.String()
oas.addrs[s] = ObservedAddr{
Addr: addr,
TimesSeen: oas.addrs[s].TimesSeen + 1,
LastSeen: time.Now(),
oa, found := oas.addrs[s]
// first time seeing address.
if !found {
oa = &ObservedAddr{
Addr: addr,
SeenBy: make(map[string]struct{}),
}
oas.addrs[s] = oa
}
// Add current observer.
oa.SeenBy[observer.String()] = struct{}{}
oa.LastSeen = time.Now()
}
func (oas *ObservedAddrSet) SetTTL(ttl time.Duration) {
......
......@@ -36,6 +36,9 @@ func TestObsAddrSet(t *testing.T) {
a1 := m("/ip4/1.2.3.4/tcp/1231")
a2 := m("/ip4/1.2.3.4/tcp/1232")
a3 := m("/ip4/1.2.3.4/tcp/1233")
a4 := m("/ip4/1.2.3.4/tcp/1234")
a5 := m("/ip4/1.2.3.4/tcp/1235")
a6 := m("/ip4/1.2.3.4/tcp/1236")
oas := ObservedAddrSet{}
......@@ -43,23 +46,34 @@ func TestObsAddrSet(t *testing.T) {
t.Error("addrs should be empty")
}
oas.Add(a1)
oas.Add(a2)
oas.Add(a3)
oas.Add(a1, a4)
oas.Add(a2, a4)
oas.Add(a3, a4)
// these are all different so we should not yet get them.
if !addrsMarch(oas.Addrs(), nil) {
t.Error("addrs should _still_ be empty (once)")
}
oas.Add(a1)
// same observer, so should not yet get them.
oas.Add(a1, a4)
oas.Add(a2, a4)
oas.Add(a3, a4)
if !addrsMarch(oas.Addrs(), nil) {
t.Error("addrs should _still_ be empty (same obs)")
}
oas.Add(a1, a5)
if !addrsMarch(oas.Addrs(), []ma.Multiaddr{a1}) {
t.Error("addrs should only have a1")
}
oas.Add(a2)
oas.Add(a1)
oas.Add(a1)
oas.Add(a2, a5)
oas.Add(a1, a5)
oas.Add(a1, a5)
oas.Add(a2, a6)
oas.Add(a1, a6)
oas.Add(a1, a6)
if !addrsMarch(oas.Addrs(), []ma.Multiaddr{a1, a2}) {
t.Error("addrs should only have a1, a2")
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment