Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 4e719d5

Browse files
committedJan 21, 2025
fix: prefix
1 parent 06cf878 commit 4e719d5

File tree

5 files changed

+121
-67
lines changed

5 files changed

+121
-67
lines changed
 

‎pkg/topology/kademlia/binprefix.go

+53-36
Original file line numberDiff line numberDiff line change
@@ -13,59 +13,76 @@ import (
1313

1414
// generateCommonBinPrefixes generates the common bin prefixes
1515
// used by the bin balancer.
16-
func generateCommonBinPrefixes(base swarm.Address, suffixLength int) [][]swarm.Address {
16+
func generateConstCommonBinPrefixes(base swarm.Address, suffixLength int) [][]swarm.Address {
17+
binPrefixes := make([][]swarm.Address, int(swarm.MaxBins))
18+
19+
for i := 0; i < int(swarm.MaxBins); i++ {
20+
binPrefixes[i] = generateBinPrefixes(base, i, suffixLength)
21+
}
22+
23+
return binPrefixes
24+
}
25+
26+
// generateCommonBinPrefixes generates the common bin prefixes
27+
// used by the bin balancer.
28+
func generateCommonBinPrefixes(base swarm.Address, suffixLengths []int) [][]swarm.Address {
29+
binPrefixes := make([][]swarm.Address, int(swarm.MaxBins))
30+
31+
for i := 0; i < int(swarm.MaxBins); i++ {
32+
binPrefixes[i] = generateBinPrefixes(base, i, suffixLengths[i])
33+
}
34+
35+
return binPrefixes
36+
}
37+
38+
func generateBinPrefixes(base swarm.Address, bin, suffixLength int) []swarm.Address {
1739
bitCombinationsCount := int(math.Pow(2, float64(suffixLength)))
1840
bitSuffixes := make([]uint8, bitCombinationsCount)
1941

2042
for i := 0; i < bitCombinationsCount; i++ {
2143
bitSuffixes[i] = uint8(i)
2244
}
2345

24-
binPrefixes := make([][]swarm.Address, int(swarm.MaxBins))
46+
binPrefixes := make([]swarm.Address, bitCombinationsCount)
2547

2648
// copy base address
27-
for i := range binPrefixes {
28-
binPrefixes[i] = make([]swarm.Address, bitCombinationsCount)
29-
for j := range binPrefixes[i] {
30-
binPrefixes[i][j] = base.Clone()
31-
}
49+
for j := range binPrefixes {
50+
binPrefixes[j] = base.Clone()
3251
}
3352

34-
for i := range binPrefixes {
35-
for j := range binPrefixes[i] {
36-
pseudoAddrBytes := binPrefixes[i][j].Bytes()
37-
38-
if len(pseudoAddrBytes) < 1 {
39-
continue
40-
}
41-
42-
// flip first bit for bin
43-
indexByte, posBit := i/8, i%8
44-
if hasBit(bits.Reverse8(pseudoAddrBytes[indexByte]), uint8(posBit)) {
45-
pseudoAddrBytes[indexByte] = bits.Reverse8(clearBit(bits.Reverse8(pseudoAddrBytes[indexByte]), uint8(posBit)))
46-
} else {
47-
pseudoAddrBytes[indexByte] = bits.Reverse8(setBit(bits.Reverse8(pseudoAddrBytes[indexByte]), uint8(posBit)))
48-
}
53+
for j := range binPrefixes {
54+
pseudoAddrBytes := binPrefixes[j].Bytes()
4955

50-
// set pseudo suffix
51-
bitSuffixPos := suffixLength - 1
52-
for l := i + 1; l < i+suffixLength+1; l++ {
53-
index, pos := l/8, l%8
56+
if len(pseudoAddrBytes) < 1 {
57+
continue
58+
}
5459

55-
if hasBit(bitSuffixes[j], uint8(bitSuffixPos)) {
56-
pseudoAddrBytes[index] = bits.Reverse8(setBit(bits.Reverse8(pseudoAddrBytes[index]), uint8(pos)))
57-
} else {
58-
pseudoAddrBytes[index] = bits.Reverse8(clearBit(bits.Reverse8(pseudoAddrBytes[index]), uint8(pos)))
59-
}
60+
// flip first bit for bin
61+
indexByte, posBit := bin/8, bin%8
62+
if hasBit(bits.Reverse8(pseudoAddrBytes[indexByte]), uint8(posBit)) {
63+
pseudoAddrBytes[indexByte] = bits.Reverse8(clearBit(bits.Reverse8(pseudoAddrBytes[indexByte]), uint8(posBit)))
64+
} else {
65+
pseudoAddrBytes[indexByte] = bits.Reverse8(setBit(bits.Reverse8(pseudoAddrBytes[indexByte]), uint8(posBit)))
66+
}
6067

61-
bitSuffixPos--
62-
}
68+
// set pseudo suffix
69+
bitSuffixPos := suffixLength - 1
70+
for l := bin + 1; l < bin+suffixLength+1; l++ {
71+
index, pos := l/8, l%8
6372

64-
// clear rest of the bits
65-
for l := i + suffixLength + 1; l < len(pseudoAddrBytes)*8; l++ {
66-
index, pos := l/8, l%8
73+
if hasBit(bitSuffixes[j], uint8(bitSuffixPos)) {
74+
pseudoAddrBytes[index] = bits.Reverse8(setBit(bits.Reverse8(pseudoAddrBytes[index]), uint8(pos)))
75+
} else {
6776
pseudoAddrBytes[index] = bits.Reverse8(clearBit(bits.Reverse8(pseudoAddrBytes[index]), uint8(pos)))
6877
}
78+
79+
bitSuffixPos--
80+
}
81+
82+
// clear rest of the bits
83+
for l := bin + suffixLength + 1; l < len(pseudoAddrBytes)*8; l++ {
84+
index, pos := l/8, l%8
85+
pseudoAddrBytes[index] = bits.Reverse8(clearBit(bits.Reverse8(pseudoAddrBytes[index]), uint8(pos)))
6986
}
7087
}
7188

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package kademlia
2+
3+
import (
4+
"testing"
5+
6+
"github.com/ethersphere/bee/v2/pkg/swarm"
7+
)
8+
9+
func TestGenerateCommonBinPrefixes(t *testing.T) {
10+
base := swarm.MustParseHexAddress("abcdef1234567890")
11+
suffixLength := 3
12+
13+
suffixLengths := make([]int, 32)
14+
for i := range suffixLengths {
15+
suffixLengths[i] = 3
16+
}
17+
18+
prefixes := generateCommonBinPrefixes(base, suffixLengths)
19+
20+
if len(prefixes) != int(swarm.MaxBins) {
21+
t.Fatalf("expected %d bins, got %d", swarm.MaxBins, len(prefixes))
22+
}
23+
24+
for i := 0; i < int(swarm.MaxBins); i++ {
25+
for j := 0; j < len(prefixes[i]); j++ {
26+
proximity := swarm.Proximity(base.Bytes(), prefixes[i][j].Bytes())
27+
if want := uint8(i); want != proximity {
28+
t.Fatalf("expected proximity %d for bin %d, got %d", want, i, proximity)
29+
}
30+
}
31+
}
32+
33+
bitCombinationsCount := 1 << suffixLength
34+
for i := 0; i < int(swarm.MaxBins); i++ {
35+
if len(prefixes[i]) != bitCombinationsCount {
36+
t.Fatalf("expected %d addresses in bin %d, got %d", bitCombinationsCount, i, len(prefixes[i]))
37+
}
38+
39+
for j := 0; j < bitCombinationsCount; j++ {
40+
if len(prefixes[i][j].Bytes()) != len(base.Bytes()) {
41+
t.Fatalf("expected address length %d, got %d", len(base.Bytes()), len(prefixes[i][j].Bytes()))
42+
}
43+
}
44+
}
45+
}

‎pkg/topology/kademlia/export_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ var (
1414
PruneOversaturatedBinsFunc = func(k *Kad) func(uint8) {
1515
return k.pruneOversaturatedBins
1616
}
17-
GenerateCommonBinPrefixes = generateCommonBinPrefixes
17+
GenerateCommonBinPrefixes = generateConstCommonBinPrefixes
1818
)
1919

2020
const (

‎pkg/topology/kademlia/kademlia.go

+21-30
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const (
4949

5050
// Default option values
5151
const (
52-
defaultBitSuffixLength = 2 // the number of bits used to create pseudo addresses for balancing, 2^2, 8 addresses
52+
defaultBitSuffixLength = 4 // the number of bits used to create pseudo addresses for balancing, 2^2, 8 addresses
5353
defaultLowWaterMark = 3 // the number of peers in consecutive deepest bins that constitute as nearest neighbours
5454
defaultSaturationPeers = 8
5555
defaultOverSaturationPeers = 18
@@ -111,18 +111,21 @@ type kadOptions struct {
111111
StaticNodes []swarm.Address
112112
ExcludeFunc excludeFunc
113113

114-
TimeToRetry time.Duration
115-
ShortRetry time.Duration
116-
PruneWakeup time.Duration
117-
BitSuffixLength int // additional depth of common prefix for bin
114+
TimeToRetry time.Duration
115+
ShortRetry time.Duration
116+
PruneWakeup time.Duration
117+
// BitSuffixLength int // additional depth of common prefix for bin
118118
SaturationPeers int
119119
OverSaturationPeers int
120120
BootnodeOverSaturationPeers int
121121
BroadcastBinSize int
122122
LowWaterMark int
123123
}
124124

125-
var saturationCounts = [swarm.MaxBins]int{64, 32, 16, 12, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}
125+
var (
126+
saturationCounts = [swarm.MaxBins]int{64, 32, 16, 12, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}
127+
prefixBits = [swarm.MaxBins]int{6, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}
128+
)
126129

127130
func newKadOptions(o Options) kadOptions {
128131
ko := kadOptions{
@@ -134,12 +137,10 @@ func newKadOptions(o Options) kadOptions {
134137
StaticNodes: o.StaticNodes,
135138
ExcludeFunc: o.ExcludeFunc,
136139
// copy or use default
137-
TimeToRetry: defaultValDuration(o.TimeToRetry, defaultTimeToRetry),
138-
ShortRetry: defaultValDuration(o.ShortRetry, defaultShortRetry),
139-
PruneWakeup: defaultValDuration(o.PruneWakeup, defaultPruneWakeup),
140-
BitSuffixLength: defaultValInt(o.BitSuffixLength, defaultBitSuffixLength),
141-
SaturationPeers: defaultValInt(o.SaturationPeers, defaultSaturationPeers),
142-
OverSaturationPeers: defaultValInt(o.OverSaturationPeers, defaultOverSaturationPeers),
140+
TimeToRetry: defaultValDuration(o.TimeToRetry, defaultTimeToRetry),
141+
ShortRetry: defaultValDuration(o.ShortRetry, defaultShortRetry),
142+
PruneWakeup: defaultValDuration(o.PruneWakeup, defaultPruneWakeup),
143+
// BitSuffixLength: defaultValInt(o.BitSuffixLength, defaultBitSuffixLength),
143144
BootnodeOverSaturationPeers: defaultValInt(o.BootnodeOverSaturationPeers, defaultBootNodeOverSaturationPeers),
144145
BroadcastBinSize: defaultValInt(o.BroadcastBinSize, defaultBroadcastBinSize),
145146
LowWaterMark: defaultValInt(o.LowWaterMark, defaultLowWaterMark),
@@ -167,11 +168,7 @@ func defaultValDuration(v *time.Duration, d time.Duration) time.Duration {
167168
}
168169

169170
func makeSaturationFunc(o kadOptions) binSaturationFunc {
170-
os := o.OverSaturationPeers
171-
if o.BootnodeMode {
172-
os = o.BootnodeOverSaturationPeers
173-
}
174-
return binSaturated(os, isStaticPeer(o.StaticNodes))
171+
return binSaturated(isStaticPeer(o.StaticNodes))
175172
}
176173

177174
// Kad is the Swarm forwarding kademlia implementation.
@@ -258,11 +255,7 @@ func New(
258255
k.opt.PruneFunc = k.pruneOversaturatedBins
259256
}
260257

261-
os := k.opt.OverSaturationPeers
262-
if k.opt.BootnodeMode {
263-
os = k.opt.BootnodeOverSaturationPeers
264-
}
265-
k.opt.PruneCountFunc = binPruneCount(os, isStaticPeer(k.opt.StaticNodes))
258+
k.opt.PruneCountFunc = binPruneCount(isStaticPeer(k.opt.StaticNodes))
266259

267260
if k.opt.ExcludeFunc == nil {
268261
k.opt.ExcludeFunc = func(f ...im.ExcludeOp) peerExcludeFunc {
@@ -272,9 +265,7 @@ func New(
272265
}
273266
}
274267

275-
if k.opt.BitSuffixLength > 0 {
276-
k.commonBinPrefixes = generateCommonBinPrefixes(k.base, k.opt.BitSuffixLength)
277-
}
268+
k.commonBinPrefixes = generateCommonBinPrefixes(k.base, prefixBits[:])
278269

279270
k.bgBroadcastCtx, k.bgBroadcastCancel = context.WithCancel(context.Background())
280271

@@ -317,12 +308,12 @@ func (k *Kad) connectBalanced(wg *sync.WaitGroup, peerConnChan chan<- *peerConnI
317308

318309
// Connect to closest known peer which we haven't tried connecting to recently.
319310

320-
_, exists := nClosePeerInSlice(binConnectedPeers, pseudoAddr, noopSanctionedPeerFn, uint8(i+k.opt.BitSuffixLength+1))
311+
_, exists := nClosePeerInSlice(binConnectedPeers, pseudoAddr, noopSanctionedPeerFn, uint8(i+prefixBits[i]+1))
321312
if exists {
322313
continue
323314
}
324315

325-
closestKnownPeer, exists := nClosePeerInSlice(binPeers, pseudoAddr, skipPeers, uint8(i+k.opt.BitSuffixLength+1))
316+
closestKnownPeer, exists := nClosePeerInSlice(binPeers, pseudoAddr, skipPeers, uint8(i+prefixBits[i]+1))
326317
if !exists {
327318
continue
328319
}
@@ -738,7 +729,7 @@ func (k *Kad) balancedSlotPeers(pseudoAddr swarm.Address, peers []swarm.Address,
738729
var ret []swarm.Address
739730

740731
for _, peer := range peers {
741-
if int(swarm.ExtendedProximity(peer.Bytes(), pseudoAddr.Bytes())) >= po+k.opt.BitSuffixLength+1 {
732+
if int(swarm.ExtendedProximity(peer.Bytes(), pseudoAddr.Bytes())) >= po+prefixBits[po]+1 {
742733
ret = append(ret, peer)
743734
}
744735
}
@@ -866,7 +857,7 @@ func (k *Kad) connectBootNodes(ctx context.Context) {
866857
// binSaturated indicates whether a certain bin is saturated or not.
867858
// when a bin is not saturated it means we would like to proactively
868859
// initiate connections to other peers in the bin.
869-
func binSaturated(oversaturationAmount int, staticNode staticPeerFunc) binSaturationFunc {
860+
func binSaturated(staticNode staticPeerFunc) binSaturationFunc {
870861
return func(bin uint8, connected *pslice.PSlice, exclude peerExcludeFunc) bool {
871862
size := 0
872863
_ = connected.EachBin(func(addr swarm.Address, po uint8) (bool, bool, error) {
@@ -881,7 +872,7 @@ func binSaturated(oversaturationAmount int, staticNode staticPeerFunc) binSatura
881872
}
882873

883874
// binPruneCount counts how many peers should be pruned from a bin.
884-
func binPruneCount(oversaturationAmount int, staticNode staticPeerFunc) pruneCountFunc {
875+
func binPruneCount(staticNode staticPeerFunc) pruneCountFunc {
885876
return func(bin uint8, connected *pslice.PSlice, exclude peerExcludeFunc) (int, int) {
886877
size := 0
887878
_ = connected.EachBin(func(addr swarm.Address, po uint8) (bool, bool, error) {

‎pkg/topology/kademlia/kademlia_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -1898,6 +1898,7 @@ func mineBin(t *testing.T, base swarm.Address, bin, count int, isBalanced bool)
18981898
}
18991899

19001900
if isBalanced {
1901+
19011902
prefixes := kademlia.GenerateCommonBinPrefixes(base, kademlia.DefaultBitSuffixLength)
19021903
for i := 0; i < int(math.Pow(2, float64(kademlia.DefaultBitSuffixLength))); i++ {
19031904
rndAddrs[i] = prefixes[bin][i]

0 commit comments

Comments
 (0)
Please sign in to comment.