github.com/ethersphere/bee/v2@v2.2.0/pkg/topology/kademlia/binprefix.go (about)

     1  // Copyright 2020 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package kademlia
     6  
     7  import (
     8  	"math"
     9  	"math/bits"
    10  
    11  	"github.com/ethersphere/bee/v2/pkg/swarm"
    12  )
    13  
    14  // generateCommonBinPrefixes generates the common bin prefixes
    15  // used by the bin balancer.
    16  func generateCommonBinPrefixes(base swarm.Address, suffixLength int) [][]swarm.Address {
    17  	bitCombinationsCount := int(math.Pow(2, float64(suffixLength)))
    18  	bitSuffixes := make([]uint8, bitCombinationsCount)
    19  
    20  	for i := 0; i < bitCombinationsCount; i++ {
    21  		bitSuffixes[i] = uint8(i)
    22  	}
    23  
    24  	binPrefixes := make([][]swarm.Address, int(swarm.MaxBins))
    25  
    26  	// 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  		}
    32  	}
    33  
    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  			}
    49  
    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
    54  
    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  
    61  				bitSuffixPos--
    62  			}
    63  
    64  			// clear rest of the bits
    65  			for l := i + suffixLength + 1; l < len(pseudoAddrBytes)*8; l++ {
    66  				index, pos := l/8, l%8
    67  				pseudoAddrBytes[index] = bits.Reverse8(clearBit(bits.Reverse8(pseudoAddrBytes[index]), uint8(pos)))
    68  			}
    69  		}
    70  	}
    71  
    72  	return binPrefixes
    73  }
    74  
    75  // Clears the bit at pos in n.
    76  func clearBit(n, pos uint8) uint8 {
    77  	mask := ^(uint8(1) << pos)
    78  	return n & mask
    79  }
    80  
    81  // Sets the bit at pos in the integer n.
    82  func setBit(n, pos uint8) uint8 {
    83  	return n | 1<<pos
    84  }
    85  
    86  func hasBit(n, pos uint8) bool {
    87  	return n&(1<<pos) > 0
    88  }