github.com/aaa256/atlantis@v0.0.0-20210707112435-42ee889287a2/swarm/pot/address.go (about)

     1  // Copyright 2017 The go-athereum Authors
     2  // This file is part of the go-athereum library.
     3  //
     4  // The go-athereum 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-athereum 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-athereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package pot see doc.go
    18  package pot
    19  
    20  import (
    21  	"encoding/binary"
    22  	"fmt"
    23  	"math/rand"
    24  	"strconv"
    25  	"strings"
    26  
    27  	"github.com/athereum/go-athereum/common"
    28  )
    29  
    30  var (
    31  	zerosBin = Address{}.Bin()
    32  )
    33  
    34  // Address is an alias for common.Hash
    35  type Address common.Hash
    36  
    37  // NewAddressFromBytes constructs an Address from a byte slice
    38  func NewAddressFromBytes(b []byte) Address {
    39  	h := common.Hash{}
    40  	copy(h[:], b)
    41  	return Address(h)
    42  }
    43  
    44  func (a Address) IsZero() bool {
    45  	return a.Bin() == zerosBin
    46  }
    47  
    48  func (a Address) String() string {
    49  	return fmt.Sprintf("%x", a[:])
    50  }
    51  
    52  // MarshalJSON Address serialisation
    53  func (a *Address) MarshalJSON() (out []byte, err error) {
    54  	return []byte(`"` + a.String() + `"`), nil
    55  }
    56  
    57  // UnmarshalJSON Address deserialisation
    58  func (a *Address) UnmarshalJSON(value []byte) error {
    59  	*a = Address(common.HexToHash(string(value[1 : len(value)-1])))
    60  	return nil
    61  }
    62  
    63  // Bin returns the string form of the binary representation of an address (only first 8 bits)
    64  func (a Address) Bin() string {
    65  	return ToBin(a[:])
    66  }
    67  
    68  // ToBin converts a byteslice to the string binary representation
    69  func ToBin(a []byte) string {
    70  	var bs []string
    71  	for _, b := range a {
    72  		bs = append(bs, fmt.Sprintf("%08b", b))
    73  	}
    74  	return strings.Join(bs, "")
    75  }
    76  
    77  // Bytes returns the Address as a byte slice
    78  func (a Address) Bytes() []byte {
    79  	return a[:]
    80  }
    81  
    82  /*
    83  Proximity(x, y) returns the proximity order of the MSB distance between x and y
    84  
    85  The distance metric MSB(x, y) of two equal length byte sequences x an y is the
    86  value of the binary integer cast of the x^y, ie., x and y bitwise xor-ed.
    87  the binary cast is big endian: most significant bit first (=MSB).
    88  
    89  Proximity(x, y) is a discrete logarithmic scaling of the MSB distance.
    90  It is defined as the reverse rank of the integer part of the base 2
    91  logarithm of the distance.
    92  It is calculated by counting the number of common leading zeros in the (MSB)
    93  binary representation of the x^y.
    94  
    95  (0 farthest, 255 closest, 256 self)
    96  */
    97  func proximity(one, other Address) (ret int, eq bool) {
    98  	return posProximity(one, other, 0)
    99  }
   100  
   101  // posProximity(a, b, pos) returns proximity order of b wrt a (symmetric) pretending
   102  // the first pos bits match, checking only bits index >= pos
   103  func posProximity(one, other Address, pos int) (ret int, eq bool) {
   104  	for i := pos / 8; i < len(one); i++ {
   105  		if one[i] == other[i] {
   106  			continue
   107  		}
   108  		oxo := one[i] ^ other[i]
   109  		start := 0
   110  		if i == pos/8 {
   111  			start = pos % 8
   112  		}
   113  		for j := start; j < 8; j++ {
   114  			if (oxo>>uint8(7-j))&0x01 != 0 {
   115  				return i*8 + j, false
   116  			}
   117  		}
   118  	}
   119  	return len(one) * 8, true
   120  }
   121  
   122  // ProxCmp compares the distances a->target and b->target.
   123  // Returns -1 if a is closer to target, 1 if b is closer to target
   124  // and 0 if they are equal.
   125  func ProxCmp(a, x, y interface{}) int {
   126  	return proxCmp(ToBytes(a), ToBytes(x), ToBytes(y))
   127  }
   128  
   129  func proxCmp(a, x, y []byte) int {
   130  	for i := range a {
   131  		dx := x[i] ^ a[i]
   132  		dy := y[i] ^ a[i]
   133  		if dx > dy {
   134  			return 1
   135  		} else if dx < dy {
   136  			return -1
   137  		}
   138  	}
   139  	return 0
   140  }
   141  
   142  // RandomAddressAt (address, prox) generates a random address
   143  // at proximity order prox relative to address
   144  // if prox is negative a random address is generated
   145  func RandomAddressAt(self Address, prox int) (addr Address) {
   146  	addr = self
   147  	pos := -1
   148  	if prox >= 0 {
   149  		pos = prox / 8
   150  		trans := prox % 8
   151  		transbytea := byte(0)
   152  		for j := 0; j <= trans; j++ {
   153  			transbytea |= 1 << uint8(7-j)
   154  		}
   155  		flipbyte := byte(1 << uint8(7-trans))
   156  		transbyteb := transbytea ^ byte(255)
   157  		randbyte := byte(rand.Intn(255))
   158  		addr[pos] = ((addr[pos] & transbytea) ^ flipbyte) | randbyte&transbyteb
   159  	}
   160  	for i := pos + 1; i < len(addr); i++ {
   161  		addr[i] = byte(rand.Intn(255))
   162  	}
   163  
   164  	return
   165  }
   166  
   167  // RandomAddress generates a random address
   168  func RandomAddress() Address {
   169  	return RandomAddressAt(Address{}, -1)
   170  }
   171  
   172  // NewAddressFromString creates a byte slice from a string in binary representation
   173  func NewAddressFromString(s string) []byte {
   174  	ha := [32]byte{}
   175  
   176  	t := s + zerosBin[:len(zerosBin)-len(s)]
   177  	for i := 0; i < 4; i++ {
   178  		n, err := strconv.ParseUint(t[i*64:(i+1)*64], 2, 64)
   179  		if err != nil {
   180  			panic("wrong format: " + err.Error())
   181  		}
   182  		binary.BigEndian.PutUint64(ha[i*8:(i+1)*8], n)
   183  	}
   184  	return ha[:]
   185  }
   186  
   187  // BytesAddress is an interface for elements addressable by a byte slice
   188  type BytesAddress interface {
   189  	Address() []byte
   190  }
   191  
   192  // ToBytes turns the Val into bytes
   193  func ToBytes(v Val) []byte {
   194  	if v == nil {
   195  		return nil
   196  	}
   197  	b, ok := v.([]byte)
   198  	if !ok {
   199  		ba, ok := v.(BytesAddress)
   200  		if !ok {
   201  			panic(fmt.Sprintf("unsupported value type %T", v))
   202  		}
   203  		b = ba.Address()
   204  	}
   205  	return b
   206  }
   207  
   208  // DefaultPof returns a proximity order comparison operator function
   209  // where all
   210  func DefaultPof(max int) func(one, other Val, pos int) (int, bool) {
   211  	return func(one, other Val, pos int) (int, bool) {
   212  		po, eq := proximityOrder(ToBytes(one), ToBytes(other), pos)
   213  		if po >= max {
   214  			eq = true
   215  			po = max
   216  		}
   217  		return po, eq
   218  	}
   219  }
   220  
   221  func proximityOrder(one, other []byte, pos int) (int, bool) {
   222  	for i := pos / 8; i < len(one); i++ {
   223  		if one[i] == other[i] {
   224  			continue
   225  		}
   226  		oxo := one[i] ^ other[i]
   227  		start := 0
   228  		if i == pos/8 {
   229  			start = pos % 8
   230  		}
   231  		for j := start; j < 8; j++ {
   232  			if (oxo>>uint8(7-j))&0x01 != 0 {
   233  				return i*8 + j, false
   234  			}
   235  		}
   236  	}
   237  	return len(one) * 8, true
   238  }
   239  
   240  // Label displays the node's key in binary format
   241  func Label(v Val) string {
   242  	if v == nil {
   243  		return "<nil>"
   244  	}
   245  	if s, ok := v.(fmt.Stringer); ok {
   246  		return s.String()
   247  	}
   248  	if b, ok := v.([]byte); ok {
   249  		return ToBin(b)
   250  	}
   251  	panic(fmt.Sprintf("unsupported value type %T", v))
   252  }