github.com/dominant-strategies/go-quai@v0.28.2/common/types.go (about) 1 // Copyright 2015 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 common 18 19 import ( 20 "bytes" 21 "database/sql/driver" 22 "encoding/hex" 23 "encoding/json" 24 "errors" 25 "fmt" 26 "log" 27 "math/big" 28 "math/rand" 29 "reflect" 30 "strconv" 31 "strings" 32 33 "github.com/dominant-strategies/go-quai/common/hexutil" 34 ) 35 36 // Lengths of hashes and addresses in bytes. 37 const ( 38 // HashLength is the expected length of the hash 39 HashLength = 32 40 // AddressLength is the expected length of the address 41 AddressLength = 20 42 43 // Constants to mnemonically index into context arrays 44 PRIME_CTX = 0 45 REGION_CTX = 1 46 ZONE_CTX = 2 47 48 // Depth of the hierarchy of chains 49 NumRegionsInPrime = 3 50 NumZonesInRegion = 3 51 HierarchyDepth = 3 52 NumChains = 1 + NumRegionsInPrime*(1+NumZonesInRegion) // Prime + R regions + RxZ zones 53 ) 54 55 var ( 56 // Default to prime node, but changed at startup by config. 57 NodeLocation = Location{} 58 ) 59 60 var ( 61 hashT = reflect.TypeOf(Hash{}) 62 // The zero address (0x0) 63 ZeroInternal = InternalAddress{} 64 ZeroAddr = Address{&ZeroInternal} 65 ErrInvalidScope = errors.New("address is not in scope") 66 ) 67 68 // Hash represents the 32 byte Keccak256 hash of arbitrary data. 69 type Hash [HashLength]byte 70 71 // BytesToHash sets b to hash. 72 // If b is larger than len(h), b will be cropped from the left. 73 func BytesToHash(b []byte) Hash { 74 var h Hash 75 h.SetBytes(b) 76 return h 77 } 78 79 // BigToHash sets byte representation of b to hash. 80 // If b is larger than len(h), b will be cropped from the left. 81 func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) } 82 83 // HexToHash sets byte representation of s to hash. 84 // If b is larger than len(h), b will be cropped from the left. 85 func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) } 86 87 // Bytes gets the byte representation of the underlying hash. 88 func (h Hash) Bytes() []byte { return h[:] } 89 90 // Big converts a hash to a big integer. 91 func (h Hash) Big() *big.Int { return new(big.Int).SetBytes(h[:]) } 92 93 // Hex converts a hash to a hex string. 94 func (h Hash) Hex() string { return hexutil.Encode(h[:]) } 95 96 // TerminalString implements log.TerminalStringer, formatting a string for console 97 // output during logging. 98 func (h Hash) TerminalString() string { 99 return fmt.Sprintf("%x..%x", h[:3], h[29:]) 100 } 101 102 // String implements the stringer interface and is used also by the logger when 103 // doing full logging into a file. 104 func (h Hash) String() string { 105 return h.Hex() 106 } 107 108 // Format implements fmt.Formatter. 109 // Hash supports the %v, %s, %v, %x, %X and %d format verbs. 110 func (h Hash) Format(s fmt.State, c rune) { 111 hexb := make([]byte, 2+len(h)*2) 112 copy(hexb, "0x") 113 hex.Encode(hexb[2:], h[:]) 114 115 switch c { 116 case 'x', 'X': 117 if !s.Flag('#') { 118 hexb = hexb[2:] 119 } 120 if c == 'X' { 121 hexb = bytes.ToUpper(hexb) 122 } 123 fallthrough 124 case 'v', 's': 125 s.Write(hexb) 126 case 'q': 127 q := []byte{'"'} 128 s.Write(q) 129 s.Write(hexb) 130 s.Write(q) 131 case 'd': 132 fmt.Fprint(s, ([len(h)]byte)(h)) 133 default: 134 fmt.Fprintf(s, "%%!%c(hash=%x)", c, h) 135 } 136 } 137 138 // UnmarshalText parses a hash in hex syntax. 139 func (h *Hash) UnmarshalText(input []byte) error { 140 return hexutil.UnmarshalFixedText("Hash", input, h[:]) 141 } 142 143 // UnmarshalJSON parses a hash in hex syntax. 144 func (h *Hash) UnmarshalJSON(input []byte) error { 145 return hexutil.UnmarshalFixedJSON(hashT, input, h[:]) 146 } 147 148 // MarshalText returns the hex representation of h. 149 func (h Hash) MarshalText() ([]byte, error) { 150 return hexutil.Bytes(h[:]).MarshalText() 151 } 152 153 // SetBytes sets the hash to the value of b. 154 // If b is larger than len(h), b will be cropped from the left. 155 func (h *Hash) SetBytes(b []byte) { 156 if len(b) > len(h) { 157 b = b[len(b)-HashLength:] 158 } 159 160 copy(h[HashLength-len(b):], b) 161 } 162 163 // Generate implements testing/quick.Generator. 164 func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value { 165 m := rand.Intn(len(h)) 166 for i := len(h) - 1; i > m; i-- { 167 h[i] = byte(rand.Uint32()) 168 } 169 return reflect.ValueOf(h) 170 } 171 172 // Scan implements Scanner for database/sql. 173 func (h *Hash) Scan(src interface{}) error { 174 srcB, ok := src.([]byte) 175 if !ok { 176 return fmt.Errorf("can't scan %T into Hash", src) 177 } 178 if len(srcB) != HashLength { 179 return fmt.Errorf("can't scan []byte of len %d into Hash, want %d", len(srcB), HashLength) 180 } 181 copy(h[:], srcB) 182 return nil 183 } 184 185 // Value implements valuer for database/sql. 186 func (h Hash) Value() (driver.Value, error) { 187 return h[:], nil 188 } 189 190 // UnprefixedHash allows marshaling a Hash without 0x prefix. 191 type UnprefixedHash Hash 192 193 // UnmarshalText decodes the hash from hex. The 0x prefix is optional. 194 func (h *UnprefixedHash) UnmarshalText(input []byte) error { 195 return hexutil.UnmarshalFixedUnprefixedText("UnprefixedHash", input, h[:]) 196 } 197 198 // MarshalText encodes the hash as hex. 199 func (h UnprefixedHash) MarshalText() ([]byte, error) { 200 return []byte(hex.EncodeToString(h[:])), nil 201 } 202 203 /////////// Address 204 205 type addrPrefixRange struct { 206 lo uint8 207 hi uint8 208 } 209 210 func NewRange(l, h uint8) addrPrefixRange { 211 return addrPrefixRange{ 212 lo: l, 213 hi: h, 214 } 215 } 216 217 var ( 218 locationToPrefixRange = make(map[string]addrPrefixRange) 219 ) 220 221 func init() { 222 locationToPrefixRange["cyprus1"] = NewRange(0, 29) 223 locationToPrefixRange["cyprus2"] = NewRange(30, 58) 224 locationToPrefixRange["cyprus3"] = NewRange(59, 87) 225 locationToPrefixRange["paxos1"] = NewRange(88, 115) 226 locationToPrefixRange["paxos2"] = NewRange(116, 143) 227 locationToPrefixRange["paxos3"] = NewRange(144, 171) 228 locationToPrefixRange["hydra1"] = NewRange(172, 199) 229 locationToPrefixRange["hydra2"] = NewRange(200, 227) 230 locationToPrefixRange["hydra3"] = NewRange(228, 255) 231 } 232 233 // UnprefixedAddress allows marshaling an Address without 0x prefix. 234 type UnprefixedAddress InternalAddress 235 236 // UnmarshalText decodes the address from hex. The 0x prefix is optional. 237 func (a *UnprefixedAddress) UnmarshalText(input []byte) error { 238 return hexutil.UnmarshalFixedUnprefixedText("UnprefixedAddress", input, a[:]) 239 } 240 241 // MarshalText encodes the address as hex. 242 func (a UnprefixedAddress) MarshalText() ([]byte, error) { 243 return []byte(hex.EncodeToString(a[:])), nil 244 } 245 246 // MixedcaseAddress retains the original string, which may or may not be 247 // correctly checksummed 248 type MixedcaseAddress struct { 249 addr Address 250 original string 251 } 252 253 // NewMixedcaseAddress constructor (mainly for testing) 254 func NewMixedcaseAddress(addr Address) MixedcaseAddress { 255 return MixedcaseAddress{addr: addr, original: addr.inner.Hex()} 256 } 257 258 // NewMixedcaseAddressFromString is mainly meant for unit-testing 259 func NewMixedcaseAddressFromString(hexaddr string) (*MixedcaseAddress, error) { 260 if !IsHexAddress(hexaddr) { 261 return nil, errors.New("invalid address") 262 } 263 a := FromHex(hexaddr) 264 return &MixedcaseAddress{addr: BytesToAddress(a), original: hexaddr}, nil 265 } 266 267 // UnmarshalJSON parses MixedcaseAddress 268 func (ma *MixedcaseAddress) UnmarshalJSON(input []byte) error { 269 var temp [AddressLength]byte 270 271 if err := hexutil.UnmarshalFixedJSON(reflect.TypeOf(InternalAddress{}), input, temp[:]); err != nil { 272 return err 273 } 274 275 ma.addr.inner = Bytes20ToAddress(temp).inner 276 277 return json.Unmarshal(input, &ma.original) 278 } 279 280 // MarshalJSON marshals the original value 281 func (ma *MixedcaseAddress) MarshalJSON() ([]byte, error) { 282 if strings.HasPrefix(ma.original, "0x") || strings.HasPrefix(ma.original, "0X") { 283 return json.Marshal(fmt.Sprintf("0x%s", ma.original[2:])) 284 } 285 return json.Marshal(fmt.Sprintf("0x%s", ma.original)) 286 } 287 288 // Address returns the address 289 func (ma *MixedcaseAddress) Address() Address { 290 return ma.addr 291 } 292 293 // String implements fmt.Stringer 294 func (ma *MixedcaseAddress) String() string { 295 if ma.ValidChecksum() { 296 return fmt.Sprintf("%s [chksum ok]", ma.original) 297 } 298 return fmt.Sprintf("%s [chksum INVALID]", ma.original) 299 } 300 301 // ValidChecksum returns true if the address has valid checksum 302 func (ma *MixedcaseAddress) ValidChecksum() bool { 303 return ma.original == ma.addr.inner.Hex() 304 } 305 306 // Original returns the mixed-case input string 307 func (ma *MixedcaseAddress) Original() string { 308 return ma.original 309 } 310 311 // Location of a chain within the Quai hierarchy 312 // Location is encoded as a path from the root of the tree to the specified 313 // chain. Not all indices need to be populated, e.g: 314 // prime = [] 315 // region[0] = [0] 316 // zone[1,2] = [1, 2] 317 type Location []byte 318 319 func (loc Location) Region() int { 320 if len(loc) >= 1 { 321 return int(loc[REGION_CTX-1]) 322 } else { 323 return -1 324 } 325 } 326 327 func (loc Location) HasRegion() bool { 328 return loc.Region() >= 0 329 } 330 331 func (loc Location) Zone() int { 332 if len(loc) >= 2 { 333 return int(loc[ZONE_CTX-1]) 334 } else { 335 return -1 336 } 337 } 338 339 func (loc Location) HasZone() bool { 340 return loc.Zone() >= 0 341 } 342 343 func (loc Location) AssertValid() { 344 if !loc.HasRegion() && loc.HasZone() { 345 log.Fatal("cannot specify zone without also specifying region.") 346 } 347 if loc.Region() >= NumRegionsInPrime { 348 log.Fatal("region index is not valid.") 349 } 350 if loc.Zone() >= NumZonesInRegion { 351 log.Fatal("zone index is not valid.") 352 } 353 } 354 355 func (loc Location) Context() int { 356 loc.AssertValid() 357 if loc.Zone() >= 0 { 358 return ZONE_CTX 359 } else if loc.Region() >= 0 { 360 return REGION_CTX 361 } else { 362 return PRIME_CTX 363 } 364 } 365 366 // DomLocation returns the location of your dominant chain 367 func (loc Location) DomIndex() int { 368 switch NodeLocation.Context() { 369 case PRIME_CTX: 370 return 0 371 case REGION_CTX: 372 return loc.Region() 373 default: 374 return loc.Zone() 375 } 376 } 377 378 // SubIndex returns the index of the subordinate chain for a given location 379 func (loc Location) SubIndex() int { 380 switch NodeLocation.Context() { 381 case PRIME_CTX: 382 return loc.Region() 383 case REGION_CTX: 384 return loc.Zone() 385 default: 386 return -1 387 } 388 } 389 390 // SubInSlice returns the location of the subordinate chain within the specified 391 // slice. For example: 392 // - if prime calls SubInSlice(Location{0,0}) the result will be Location{0}, 393 // i.e. region-0's location, because Prime's subordinate in that slice is 394 // region-0 395 // - if region-0 calls SubInSlice(Location{0,0}) the result will be 396 // Location{0,0}, i.e. zone-0-0's location, because region-0's subordinate in 397 // that slice is zone-0-0 398 func (loc Location) SubInSlice(slice Location) Location { 399 if len(slice) <= len(loc) { 400 log.Println("cannot determine sub location, because slice location is not deeper than self") 401 return nil 402 } 403 subLoc := append(loc, slice[len(loc)]) 404 return subLoc 405 } 406 407 func (loc Location) InSameSliceAs(cmp Location) bool { 408 // Figure out which location is shorter 409 shorter := loc 410 longer := cmp 411 if len(loc) > len(cmp) { 412 longer = loc 413 shorter = cmp 414 } 415 // Compare bytes up to the shorter depth 416 return shorter.Equal(longer[:len(shorter)]) 417 } 418 419 func (loc Location) Name() string { 420 regionName := "" 421 switch loc.Region() { 422 case 0: 423 regionName = "cyprus" 424 case 1: 425 regionName = "paxos" 426 case 2: 427 regionName = "hydra" 428 default: 429 regionName = "unknownregion" 430 } 431 zoneNum := strconv.Itoa(loc.Zone() + 1) 432 switch loc.Context() { 433 case PRIME_CTX: 434 return "prime" 435 case REGION_CTX: 436 return regionName 437 case ZONE_CTX: 438 return regionName + zoneNum 439 default: 440 log.Println("cannot name invalid location") 441 return "invalid-location" 442 } 443 } 444 445 func (loc Location) Equal(cmp Location) bool { 446 return bytes.Equal(loc, cmp) 447 } 448 449 // CommonDom identifies the highest context chain which exists in both locations 450 // * zone-0-0 & zone-0-1 would share region-0 as their highest context common dom 451 // * zone-0-0 & zone-1-0 would share Prime as their highest context common dom 452 func (loc Location) CommonDom(cmp Location) Location { 453 common := Location{} 454 shorterLen := len(loc) 455 if len(loc) > len(cmp) { 456 shorterLen = len(cmp) 457 } 458 for i := 0; i < shorterLen; i++ { 459 if loc[i] == cmp[i] { 460 common = append(common, loc[i]) 461 } else { 462 break 463 } 464 } 465 return common 466 } 467 468 func (l Location) ContainsAddress(a Address) bool { 469 // ContainAddress can only be called for a zone chain 470 if l.Context() != ZONE_CTX { 471 return false 472 } 473 prefix := a.Bytes()[0] 474 prefixRange, ok := locationToPrefixRange[l.Name()] 475 if !ok { 476 log.Fatal("unable to get address prefix range for location") 477 } 478 // Ranges are fully inclusive 479 return uint8(prefix) >= prefixRange.lo && uint8(prefix) <= prefixRange.hi 480 } 481 482 func (l Location) RPCMarshal() []hexutil.Uint64 { 483 res := make([]hexutil.Uint64, 0) 484 for _, i := range l { 485 res = append(res, hexutil.Uint64(i)) 486 } 487 488 return res 489 } 490 491 func IsInChainScope(b []byte) bool { 492 nodeCtx := NodeLocation.Context() 493 // IsInChainScope only be called for a zone chain 494 if nodeCtx != ZONE_CTX { 495 return false 496 } 497 if BytesToHash(b) == ZeroAddr.Hash() { 498 return true 499 } 500 prefix := b[0] 501 prefixRange, ok := locationToPrefixRange[NodeLocation.Name()] 502 if !ok { 503 log.Fatal("unable to get address prefix range for location") 504 } 505 // Ranges are fully inclusive 506 return uint8(prefix) >= prefixRange.lo && uint8(prefix) <= prefixRange.hi 507 } 508 509 func OrderToString(order int) string { 510 switch order { 511 case PRIME_CTX: 512 return "Prime" 513 case REGION_CTX: 514 return "Region" 515 case ZONE_CTX: 516 return "Zone" 517 default: 518 return "Invalid" 519 } 520 }