organize.
no objections from @davecgh
This commit is contained in:
parent
ba937630d0
commit
36e8b4c82e
2 changed files with 171 additions and 160 deletions
|
@ -26,6 +26,71 @@ import (
|
||||||
"github.com/conformal/btcwire"
|
"github.com/conformal/btcwire"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AddrManager provides a concurrency safe address manager for caching potential
|
||||||
|
// peers on the bitcoin network.
|
||||||
|
type AddrManager struct {
|
||||||
|
mtx sync.Mutex
|
||||||
|
dataDir string
|
||||||
|
lookupFunc func(string) ([]net.IP, error)
|
||||||
|
rand *rand.Rand
|
||||||
|
key [32]byte
|
||||||
|
addrIndex map[string]*knownAddress // address key to ka for all addrs.
|
||||||
|
addrNew [newBucketCount]map[string]*knownAddress
|
||||||
|
addrTried [triedBucketCount]*list.List
|
||||||
|
started int32
|
||||||
|
shutdown int32
|
||||||
|
wg sync.WaitGroup
|
||||||
|
quit chan struct{}
|
||||||
|
nTried int
|
||||||
|
nNew int
|
||||||
|
lamtx sync.Mutex
|
||||||
|
localAddresses map[string]*localAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
type serializedKnownAddress struct {
|
||||||
|
Addr string
|
||||||
|
Src string
|
||||||
|
Attempts int
|
||||||
|
TimeStamp int64
|
||||||
|
LastAttempt int64
|
||||||
|
LastSuccess int64
|
||||||
|
// no refcount or tried, that is available from context.
|
||||||
|
}
|
||||||
|
|
||||||
|
type serializedAddrManager struct {
|
||||||
|
Version int
|
||||||
|
Key [32]byte
|
||||||
|
Addresses []*serializedKnownAddress
|
||||||
|
NewBuckets [newBucketCount][]string // string is NetAddressKey
|
||||||
|
TriedBuckets [triedBucketCount][]string
|
||||||
|
}
|
||||||
|
|
||||||
|
type localAddress struct {
|
||||||
|
na *btcwire.NetAddress
|
||||||
|
score AddressPriority
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddressPriority type is used to describe the heirarchy of local address
|
||||||
|
// discovery methods.
|
||||||
|
type AddressPriority int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// InterfacePrio signifies the address is on a local interface
|
||||||
|
InterfacePrio AddressPriority = iota
|
||||||
|
|
||||||
|
// BoundPrio signifies the address has been explicity bounded to.
|
||||||
|
BoundPrio
|
||||||
|
|
||||||
|
// UpnpPrio signifies the address was obtained from UPnP.
|
||||||
|
UpnpPrio
|
||||||
|
|
||||||
|
// HTTPPrio signifies the address was obtained from an external HTTP service.
|
||||||
|
HTTPPrio
|
||||||
|
|
||||||
|
// ManualPrio signifies the address was provided by --externalip.
|
||||||
|
ManualPrio
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// needAddressThreshold is the number of addresses under which the
|
// needAddressThreshold is the number of addresses under which the
|
||||||
// address manager will claim to need more addresses.
|
// address manager will claim to need more addresses.
|
||||||
|
@ -94,117 +159,6 @@ const (
|
||||||
serialisationVersion = 1
|
serialisationVersion = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
// knownAddress tracks information about a known network address that is used
|
|
||||||
// to determine how viable an address is.
|
|
||||||
type knownAddress struct {
|
|
||||||
na *btcwire.NetAddress
|
|
||||||
srcAddr *btcwire.NetAddress
|
|
||||||
attempts int
|
|
||||||
lastattempt time.Time
|
|
||||||
lastsuccess time.Time
|
|
||||||
tried bool
|
|
||||||
refs int // reference count of new buckets
|
|
||||||
}
|
|
||||||
|
|
||||||
// NetAddress returns the underlying btcwire.NetAddress associated with the
|
|
||||||
// known address.
|
|
||||||
func (ka *knownAddress) NetAddress() *btcwire.NetAddress {
|
|
||||||
return ka.na
|
|
||||||
}
|
|
||||||
|
|
||||||
// LastAttempt returns the last time the known address was attempted.
|
|
||||||
func (ka *knownAddress) LastAttempt() time.Time {
|
|
||||||
return ka.lastattempt
|
|
||||||
}
|
|
||||||
|
|
||||||
// bad returns true if the address in question has not been tried in the last
|
|
||||||
// minute and meets one of the following criteria:
|
|
||||||
// 1) It claims to be from the future
|
|
||||||
// 2) It hasn't been seen in over a month
|
|
||||||
// 3) It has failed at least three times and never succeeded
|
|
||||||
// 4) It has failed ten times in the last week
|
|
||||||
// All addresses that meet these criteria are assumed to be worthless and not
|
|
||||||
// worth keeping hold of.
|
|
||||||
func bad(ka *knownAddress) bool {
|
|
||||||
if ka.lastattempt.After(time.Now().Add(-1 * time.Minute)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// From the future?
|
|
||||||
if ka.na.Timestamp.After(time.Now().Add(10 * time.Minute)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Over a month old?
|
|
||||||
if ka.na.Timestamp.After(time.Now().Add(-1 * numMissingDays * time.Hour * 24)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Never succeeded?
|
|
||||||
if ka.lastsuccess.IsZero() && ka.attempts >= numRetries {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hasn't succeeded in too long?
|
|
||||||
if !ka.lastsuccess.After(time.Now().Add(-1*minBadDays*time.Hour*24)) &&
|
|
||||||
ka.attempts >= maxFailures {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// chance returns the selection probability for a known address. The priority
|
|
||||||
// depends upon how recently the address has been seen, how recently it was last
|
|
||||||
// attempted and how often attempts to connect to it have failed.
|
|
||||||
func chance(ka *knownAddress) float64 {
|
|
||||||
now := time.Now()
|
|
||||||
lastSeen := now.Sub(ka.na.Timestamp)
|
|
||||||
lastAttempt := now.Sub(ka.lastattempt)
|
|
||||||
|
|
||||||
if lastSeen < 0 {
|
|
||||||
lastSeen = 0
|
|
||||||
}
|
|
||||||
if lastAttempt < 0 {
|
|
||||||
lastAttempt = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
c := 600.0 / (600.0 + lastSeen.Seconds())
|
|
||||||
|
|
||||||
// Very recent attempts are less likely to be retried.
|
|
||||||
if lastAttempt > 10*time.Minute {
|
|
||||||
c *= 0.01
|
|
||||||
}
|
|
||||||
|
|
||||||
// Failed attempts deprioritise.
|
|
||||||
for i := ka.attempts; i < 0; i++ {
|
|
||||||
c /= 1.5
|
|
||||||
}
|
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddrManager provides a concurrency safe address manager for caching potential
|
|
||||||
// peers on the bitcoin network.
|
|
||||||
type AddrManager struct {
|
|
||||||
mtx sync.Mutex
|
|
||||||
dataDir string
|
|
||||||
lookupFunc func(string) ([]net.IP, error)
|
|
||||||
rand *rand.Rand
|
|
||||||
key [32]byte
|
|
||||||
addrIndex map[string]*knownAddress // address key to ka for all addrs.
|
|
||||||
addrNew [newBucketCount]map[string]*knownAddress
|
|
||||||
addrTried [triedBucketCount]*list.List
|
|
||||||
started int32
|
|
||||||
shutdown int32
|
|
||||||
wg sync.WaitGroup
|
|
||||||
quit chan struct{}
|
|
||||||
nTried int
|
|
||||||
nNew int
|
|
||||||
lamtx sync.Mutex
|
|
||||||
localAddresses map[string]*localAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateAddress is a helper function to either update an address already known
|
// updateAddress is a helper function to either update an address already known
|
||||||
// to the address manager, or to add the address if not already known.
|
// to the address manager, or to add the address if not already known.
|
||||||
func (a *AddrManager) updateAddress(netAddr, srcAddr *btcwire.NetAddress) {
|
func (a *AddrManager) updateAddress(netAddr, srcAddr *btcwire.NetAddress) {
|
||||||
|
@ -273,7 +227,7 @@ func (a *AddrManager) updateAddress(netAddr, srcAddr *btcwire.NetAddress) {
|
||||||
|
|
||||||
// Enforce max addresses.
|
// Enforce max addresses.
|
||||||
if len(a.addrNew[bucket]) > newBucketSize {
|
if len(a.addrNew[bucket]) > newBucketSize {
|
||||||
log.Tracef("new bucket is full, expiring old ")
|
log.Tracef("new bucket is full, expiring old")
|
||||||
a.expireNew(bucket)
|
a.expireNew(bucket)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +249,7 @@ func (a *AddrManager) expireNew(bucket int) {
|
||||||
// use that information instead.
|
// use that information instead.
|
||||||
var oldest *knownAddress
|
var oldest *knownAddress
|
||||||
for k, v := range a.addrNew[bucket] {
|
for k, v := range a.addrNew[bucket] {
|
||||||
if bad(v) {
|
if v.isBad() {
|
||||||
log.Tracef("expiring bad address %v", k)
|
log.Tracef("expiring bad address %v", k)
|
||||||
delete(a.addrNew[bucket], k)
|
delete(a.addrNew[bucket], k)
|
||||||
v.refs--
|
v.refs--
|
||||||
|
@ -303,7 +257,7 @@ func (a *AddrManager) expireNew(bucket int) {
|
||||||
a.nNew--
|
a.nNew--
|
||||||
delete(a.addrIndex, k)
|
delete(a.addrIndex, k)
|
||||||
}
|
}
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
if oldest == nil {
|
if oldest == nil {
|
||||||
oldest = v
|
oldest = v
|
||||||
|
@ -404,24 +358,6 @@ out:
|
||||||
log.Trace("Address handler done")
|
log.Trace("Address handler done")
|
||||||
}
|
}
|
||||||
|
|
||||||
type serializedKnownAddress struct {
|
|
||||||
Addr string
|
|
||||||
Src string
|
|
||||||
Attempts int
|
|
||||||
TimeStamp int64
|
|
||||||
LastAttempt int64
|
|
||||||
LastSuccess int64
|
|
||||||
// no refcount or tried, that is available from context.
|
|
||||||
}
|
|
||||||
|
|
||||||
type serializedAddrManager struct {
|
|
||||||
Version int
|
|
||||||
Key [32]byte
|
|
||||||
Addresses []*serializedKnownAddress
|
|
||||||
NewBuckets [newBucketCount][]string // string is NetAddressKey
|
|
||||||
TriedBuckets [triedBucketCount][]string
|
|
||||||
}
|
|
||||||
|
|
||||||
// savePeers saves all the known addresses to a file so they can be read back
|
// savePeers saves all the known addresses to a file so they can be read back
|
||||||
// in at next run.
|
// in at next run.
|
||||||
func (a *AddrManager) savePeers() {
|
func (a *AddrManager) savePeers() {
|
||||||
|
@ -846,7 +782,7 @@ func (a *AddrManager) GetAddress(class string, newBias int) *knownAddress {
|
||||||
}
|
}
|
||||||
ka := e.Value.(*knownAddress)
|
ka := e.Value.(*knownAddress)
|
||||||
randval := a.rand.Intn(large)
|
randval := a.rand.Intn(large)
|
||||||
if float64(randval) < (factor * chance(ka) * float64(large)) {
|
if float64(randval) < (factor * ka.chance() * float64(large)) {
|
||||||
log.Tracef("Selected %v from tried bucket",
|
log.Tracef("Selected %v from tried bucket",
|
||||||
NetAddressKey(ka.na))
|
NetAddressKey(ka.na))
|
||||||
return ka
|
return ka
|
||||||
|
@ -874,7 +810,7 @@ func (a *AddrManager) GetAddress(class string, newBias int) *knownAddress {
|
||||||
nth--
|
nth--
|
||||||
}
|
}
|
||||||
randval := a.rand.Intn(large)
|
randval := a.rand.Intn(large)
|
||||||
if float64(randval) < (factor * chance(ka) * float64(large)) {
|
if float64(randval) < (factor * ka.chance() * float64(large)) {
|
||||||
log.Tracef("Selected %v from new bucket",
|
log.Tracef("Selected %v from new bucket",
|
||||||
NetAddressKey(ka.na))
|
NetAddressKey(ka.na))
|
||||||
return ka
|
return ka
|
||||||
|
@ -1017,32 +953,6 @@ func (a *AddrManager) Good(addr *btcwire.NetAddress) {
|
||||||
a.addrNew[newBucket][rmkey] = rmka
|
a.addrNew[newBucket][rmkey] = rmka
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddressPriority type is used to describe the heirarchy of local address
|
|
||||||
// discovery methods.
|
|
||||||
type AddressPriority int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// InterfacePrio signifies the address is on a local interface
|
|
||||||
InterfacePrio AddressPriority = iota
|
|
||||||
|
|
||||||
// BoundPrio signifies the address has been explicity bounded to.
|
|
||||||
BoundPrio
|
|
||||||
|
|
||||||
// UpnpPrio signifies the address was obtained from UPnP.
|
|
||||||
UpnpPrio
|
|
||||||
|
|
||||||
// HTTPPrio signifies the address was obtained from an external HTTP service.
|
|
||||||
HTTPPrio
|
|
||||||
|
|
||||||
// ManualPrio signifies the address was provided by --externalip.
|
|
||||||
ManualPrio
|
|
||||||
)
|
|
||||||
|
|
||||||
type localAddress struct {
|
|
||||||
na *btcwire.NetAddress
|
|
||||||
score AddressPriority
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddLocalAddress adds na to the list of known local addresses to advertise
|
// AddLocalAddress adds na to the list of known local addresses to advertise
|
||||||
// with the given priority.
|
// with the given priority.
|
||||||
func (a *AddrManager) AddLocalAddress(na *btcwire.NetAddress, priority AddressPriority) error {
|
func (a *AddrManager) AddLocalAddress(na *btcwire.NetAddress, priority AddressPriority) error {
|
||||||
|
|
101
addrmgr/knownaddress.go
Normal file
101
addrmgr/knownaddress.go
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
// Copyright (c) 2013-2014 Conformal Systems LLC.
|
||||||
|
// Use of this source code is governed by an ISC
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package addrmgr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/conformal/btcwire"
|
||||||
|
)
|
||||||
|
|
||||||
|
// knownAddress tracks information about a known network address that is used
|
||||||
|
// to determine how viable an address is.
|
||||||
|
type knownAddress struct {
|
||||||
|
na *btcwire.NetAddress
|
||||||
|
srcAddr *btcwire.NetAddress
|
||||||
|
attempts int
|
||||||
|
lastattempt time.Time
|
||||||
|
lastsuccess time.Time
|
||||||
|
tried bool
|
||||||
|
refs int // reference count of new buckets
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetAddress returns the underlying btcwire.NetAddress associated with the
|
||||||
|
// known address.
|
||||||
|
func (ka *knownAddress) NetAddress() *btcwire.NetAddress {
|
||||||
|
return ka.na
|
||||||
|
}
|
||||||
|
|
||||||
|
// LastAttempt returns the last time the known address was attempted.
|
||||||
|
func (ka *knownAddress) LastAttempt() time.Time {
|
||||||
|
return ka.lastattempt
|
||||||
|
}
|
||||||
|
|
||||||
|
// chance returns the selection probability for a known address. The priority
|
||||||
|
// depends upon how recently the address has been seen, how recently it was last
|
||||||
|
// attempted and how often attempts to connect to it have failed.
|
||||||
|
func (ka *knownAddress) chance() float64 {
|
||||||
|
now := time.Now()
|
||||||
|
lastSeen := now.Sub(ka.na.Timestamp)
|
||||||
|
lastAttempt := now.Sub(ka.lastattempt)
|
||||||
|
|
||||||
|
if lastSeen < 0 {
|
||||||
|
lastSeen = 0
|
||||||
|
}
|
||||||
|
if lastAttempt < 0 {
|
||||||
|
lastAttempt = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
c := 600.0 / (600.0 + lastSeen.Seconds())
|
||||||
|
|
||||||
|
// Very recent attempts are less likely to be retried.
|
||||||
|
if lastAttempt > 10*time.Minute {
|
||||||
|
c *= 0.01
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed attempts deprioritise.
|
||||||
|
for i := ka.attempts; i < 0; i++ {
|
||||||
|
c /= 1.5
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// isBad returns true if the address in question has not been tried in the last
|
||||||
|
// minute and meets one of the following criteria:
|
||||||
|
// 1) It claims to be from the future
|
||||||
|
// 2) It hasn't been seen in over a month
|
||||||
|
// 3) It has failed at least three times and never succeeded
|
||||||
|
// 4) It has failed ten times in the last week
|
||||||
|
// All addresses that meet these criteria are assumed to be worthless and not
|
||||||
|
// worth keeping hold of.
|
||||||
|
func (ka *knownAddress) isBad() bool {
|
||||||
|
if ka.lastattempt.After(time.Now().Add(-1 * time.Minute)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// From the future?
|
||||||
|
if ka.na.Timestamp.After(time.Now().Add(10 * time.Minute)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Over a month old?
|
||||||
|
if ka.na.Timestamp.After(time.Now().Add(-1 * numMissingDays * time.Hour * 24)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Never succeeded?
|
||||||
|
if ka.lastsuccess.IsZero() && ka.attempts >= numRetries {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hasn't succeeded in too long?
|
||||||
|
if !ka.lastsuccess.After(time.Now().Add(-1*minBadDays*time.Hour*24)) &&
|
||||||
|
ka.attempts >= maxFailures {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue