github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/pot/address.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:44</date> 10 //</624450116119433216> 11 12 13 //包装罐见Go医生 14 package pot 15 16 import ( 17 "encoding/binary" 18 "fmt" 19 "math/rand" 20 "strconv" 21 "strings" 22 23 "github.com/ethereum/go-ethereum/common" 24 ) 25 26 var ( 27 zerosBin = Address{}.Bin() 28 ) 29 30 //地址是common.hash的别名 31 type Address common.Hash 32 33 //newAddressFromBytes从字节片构造地址 34 func NewAddressFromBytes(b []byte) Address { 35 h := common.Hash{} 36 copy(h[:], b) 37 return Address(h) 38 } 39 40 func (a Address) String() string { 41 return fmt.Sprintf("%x", a[:]) 42 } 43 44 //marshaljson地址序列化 45 func (a *Address) MarshalJSON() (out []byte, err error) { 46 return []byte(`"` + a.String() + `"`), nil 47 } 48 49 //取消标记JSON地址反序列化 50 func (a *Address) UnmarshalJSON(value []byte) error { 51 *a = Address(common.HexToHash(string(value[1 : len(value)-1]))) 52 return nil 53 } 54 55 //bin返回地址的二进制表示的字符串形式(仅前8位) 56 func (a Address) Bin() string { 57 return ToBin(a[:]) 58 } 59 60 //Tobin将字节片转换为字符串二进制表示形式 61 func ToBin(a []byte) string { 62 var bs []string 63 for _, b := range a { 64 bs = append(bs, fmt.Sprintf("%08b", b)) 65 } 66 return strings.Join(bs, "") 67 } 68 69 //字节以字节片的形式返回地址 70 func (a Address) Bytes() []byte { 71 return a[:] 72 } 73 74 //procmp比较距离a->target和b->target。 75 //如果a接近目标返回-1,如果b接近目标返回1 76 //如果相等,则为0。 77 func ProxCmp(a, x, y interface{}) int { 78 return proxCmp(ToBytes(a), ToBytes(x), ToBytes(y)) 79 } 80 81 func proxCmp(a, x, y []byte) int { 82 for i := range a { 83 dx := x[i] ^ a[i] 84 dy := y[i] ^ a[i] 85 if dx > dy { 86 return 1 87 } else if dx < dy { 88 return -1 89 } 90 } 91 return 0 92 } 93 94 //randomaddressat(地址,代理)生成随机地址 95 //在接近顺序,相对于地址的代理 96 //如果prox为负,则生成随机地址。 97 func RandomAddressAt(self Address, prox int) (addr Address) { 98 addr = self 99 pos := -1 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 //random address生成随机地址 120 func RandomAddress() Address { 121 return RandomAddressAt(Address{}, -1) 122 } 123 124 //newAddressFromString从二进制表示的字符串创建字节片 125 func NewAddressFromString(s string) []byte { 126 ha := [32]byte{} 127 128 t := s + zerosBin[:len(zerosBin)-len(s)] 129 for i := 0; i < 4; i++ { 130 n, err := strconv.ParseUint(t[i*64:(i+1)*64], 2, 64) 131 if err != nil { 132 panic("wrong format: " + err.Error()) 133 } 134 binary.BigEndian.PutUint64(ha[i*8:(i+1)*8], n) 135 } 136 return ha[:] 137 } 138 139 //BytesAddress是一个接口,用于按字节片寻址的元素 140 type BytesAddress interface { 141 Address() []byte 142 } 143 144 //tobytes将val转换为字节 145 func ToBytes(v Val) []byte { 146 if v == nil { 147 return nil 148 } 149 b, ok := v.([]byte) 150 if !ok { 151 ba, ok := v.(BytesAddress) 152 if !ok { 153 panic(fmt.Sprintf("unsupported value type %T", v)) 154 } 155 b = ba.Address() 156 } 157 return b 158 } 159 160 //defaultpof返回一个接近顺序比较运算符函数 161 func DefaultPof(max int) func(one, other Val, pos int) (int, bool) { 162 return func(one, other Val, pos int) (int, bool) { 163 po, eq := proximityOrder(ToBytes(one), ToBytes(other), pos) 164 if po >= max { 165 eq = true 166 po = max 167 } 168 return po, eq 169 } 170 } 171 172 //接近顺序返回两个参数: 173 //1。一个和另一个参数的相对接近顺序; 174 //2。布尔值,指示是否发生完全匹配(一个=另一个)。 175 func proximityOrder(one, other []byte, pos int) (int, bool) { 176 for i := pos / 8; i < len(one); i++ { 177 if one[i] == other[i] { 178 continue 179 } 180 oxo := one[i] ^ other[i] 181 start := 0 182 if i == pos/8 { 183 start = pos % 8 184 } 185 for j := start; j < 8; j++ { 186 if (oxo>>uint8(7-j))&0x01 != 0 { 187 return i*8 + j, false 188 } 189 } 190 } 191 return len(one) * 8, true 192 } 193 194 //标签以二进制格式显示节点的密钥 195 func Label(v Val) string { 196 if v == nil { 197 return "<nil>" 198 } 199 if s, ok := v.(fmt.Stringer); ok { 200 return s.String() 201 } 202 if b, ok := v.([]byte); ok { 203 return ToBin(b) 204 } 205 panic(fmt.Sprintf("unsupported value type %T", v)) 206 } 207