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  }