Michael Sutton 71b284f4d5
Address manager randomization weighted by connection failures (#1916)
* Address manager refactor stage 1

* Use a simpler weightedRand function which makes it easier parameterize to the process

* Switch back to connectionFailedCount

* Simplify selected entry deletion

* Fix function comment

Co-authored-by: Constantine Bitensky <cbitensky1@gmail.com>
Co-authored-by: Ori Newman <orinewman1@gmail.com>
2021-12-30 12:05:53 +02:00

64 lines
1.6 KiB
Go

package addressmanager
import (
"math"
"math/rand"
"time"
"github.com/kaspanet/kaspad/app/appmessage"
)
// AddressRandomize implement addressRandomizer interface
type AddressRandomize struct {
random *rand.Rand
maxFailedCount uint64
}
// NewAddressRandomize returns a new RandomizeAddress.
func NewAddressRandomize(maxFailedCount uint64) *AddressRandomize {
return &AddressRandomize{
random: rand.New(rand.NewSource(time.Now().UnixNano())),
maxFailedCount: maxFailedCount,
}
}
// weightedRand is a help function which returns a random index in the
// range [0, len(weights)-1] with probability weighted by `weights`
func weightedRand(weights []float32) int {
sum := float32(0)
for _, weight := range weights {
sum += weight
}
randPoint := rand.Float32()
scanPoint := float32(0)
for i, weight := range weights {
normalizedWeight := weight / sum
scanPoint += normalizedWeight
if randPoint <= scanPoint {
return i
}
}
return len(weights) - 1
}
// RandomAddresses returns count addresses at random from input list
func (amc *AddressRandomize) RandomAddresses(addresses []*address, count int) []*appmessage.NetAddress {
if len(addresses) < count {
count = len(addresses)
}
weights := make([]float32, 0, len(addresses))
for _, addr := range addresses {
weights = append(weights, float32(math.Pow(64, float64(amc.maxFailedCount-addr.connectionFailedCount))))
}
result := make([]*appmessage.NetAddress, 0, count)
for count > 0 {
i := weightedRand(weights)
result = append(result, addresses[i].netAddress)
// Zero entry i to avoid re-selection
weights[i] = 0
// Update count
count--
}
return result
}