github.com/truechain/go-ethereum@v1.8.11/swarm/network/kademlia/address.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package kademlia
    18  
    19  import (
    20  	"fmt"
    21  	"math/rand"
    22  	"strings"
    23  
    24  	"github.com/ethereum/go-ethereum/common"
    25  )
    26  
    27  type Address common.Hash
    28  
    29  func (a Address) String() string {
    30  	return fmt.Sprintf("%x", a[:])
    31  }
    32  
    33  func (a *Address) MarshalJSON() (out []byte, err error) {
    34  	return []byte(`"` + a.String() + `"`), nil
    35  }
    36  
    37  func (a *Address) UnmarshalJSON(value []byte) error {
    38  	*a = Address(common.HexToHash(string(value[1 : len(value)-1])))
    39  	return nil
    40  }
    41  
    42  // the string form of the binary representation of an address (only first 8 bits)
    43  func (a Address) Bin() string {
    44  	var bs []string
    45  	for _, b := range a[:] {
    46  		bs = append(bs, fmt.Sprintf("%08b", b))
    47  	}
    48  	return strings.Join(bs, "")
    49  }
    50  
    51  /*
    52  Proximity(x, y) returns the proximity order of the MSB distance between x and y
    53  
    54  The distance metric MSB(x, y) of two equal length byte sequences x and y is the
    55  value of the binary integer cast of the x^y, ie., x and y bitwise xor-ed.
    56  the binary cast is big endian: most significant bit first (=MSB).
    57  
    58  Proximity(x, y) is a discrete logarithmic scaling of the MSB distance.
    59  It is defined as the reverse rank of the integer part of the base 2
    60  logarithm of the distance.
    61  It is calculated by counting the number of common leading zeros in the (MSB)
    62  binary representation of the x^y.
    63  
    64  (0 farthest, 255 closest, 256 self)
    65  */
    66  func proximity(one, other Address) (ret int) {
    67  	for i := 0; i < len(one); i++ {
    68  		oxo := one[i] ^ other[i]
    69  		for j := 0; j < 8; j++ {
    70  			if (oxo>>uint8(7-j))&0x01 != 0 {
    71  				return i*8 + j
    72  			}
    73  		}
    74  	}
    75  	return len(one) * 8
    76  }
    77  
    78  // Address.ProxCmp compares the distances a->target and b->target.
    79  // Returns -1 if a is closer to target, 1 if b is closer to target
    80  // and 0 if they are equal.
    81  func (target Address) ProxCmp(a, b Address) int {
    82  	for i := range target {
    83  		da := a[i] ^ target[i]
    84  		db := b[i] ^ target[i]
    85  		if da > db {
    86  			return 1
    87  		} else if da < db {
    88  			return -1
    89  		}
    90  	}
    91  	return 0
    92  }
    93  
    94  // randomAddressAt(address, prox) generates a random address
    95  // at proximity order prox relative to address
    96  // if prox is negative a random address is generated
    97  func RandomAddressAt(self Address, prox int) (addr Address) {
    98  	addr = self
    99  	var pos int
   100  	if prox >= 0 {
   101  		pos = prox / 8
   102  		trans := prox % 8
   103  		transbytea := byte(0)
   104  		for j := 0; j <= trans; j++ {
   105  			transbytea |= 1 << uint8(7-j)
   106  		}
   107  		flipbyte := byte(1 << uint8(7-trans))
   108  		transbyteb := transbytea ^ byte(255)
   109  		randbyte := byte(rand.Intn(255))
   110  		addr[pos] = ((addr[pos] & transbytea) ^ flipbyte) | randbyte&transbyteb
   111  	}
   112  	for i := pos + 1; i < len(addr); i++ {
   113  		addr[i] = byte(rand.Intn(255))
   114  	}
   115  
   116  	return
   117  }
   118  
   119  // KeyRange(a0, a1, proxLimit) returns the address inclusive address
   120  // range that contain addresses closer to one than other
   121  func KeyRange(one, other Address, proxLimit int) (start, stop Address) {
   122  	prox := proximity(one, other)
   123  	if prox >= proxLimit {
   124  		prox = proxLimit
   125  	}
   126  	start = CommonBitsAddrByte(one, other, byte(0x00), prox)
   127  	stop = CommonBitsAddrByte(one, other, byte(0xff), prox)
   128  	return
   129  }
   130  
   131  func CommonBitsAddrF(self, other Address, f func() byte, p int) (addr Address) {
   132  	prox := proximity(self, other)
   133  	var pos int
   134  	if p <= prox {
   135  		prox = p
   136  	}
   137  	pos = prox / 8
   138  	addr = self
   139  	trans := byte(prox % 8)
   140  	var transbytea byte
   141  	if p > prox {
   142  		transbytea = byte(0x7f)
   143  	} else {
   144  		transbytea = byte(0xff)
   145  	}
   146  	transbytea >>= trans
   147  	transbyteb := transbytea ^ byte(0xff)
   148  	addrpos := addr[pos]
   149  	addrpos &= transbyteb
   150  	if p > prox {
   151  		addrpos ^= byte(0x80 >> trans)
   152  	}
   153  	addrpos |= transbytea & f()
   154  	addr[pos] = addrpos
   155  	for i := pos + 1; i < len(addr); i++ {
   156  		addr[i] = f()
   157  	}
   158  
   159  	return
   160  }
   161  
   162  func CommonBitsAddr(self, other Address, prox int) (addr Address) {
   163  	return CommonBitsAddrF(self, other, func() byte { return byte(rand.Intn(255)) }, prox)
   164  }
   165  
   166  func CommonBitsAddrByte(self, other Address, b byte, prox int) (addr Address) {
   167  	return CommonBitsAddrF(self, other, func() byte { return b }, prox)
   168  }
   169  
   170  // randomAddressAt() generates a random address
   171  func RandomAddress() Address {
   172  	return RandomAddressAt(Address{}, -1)
   173  }