github.com/ledgerwatch/erigon-lib@v1.0.0/common/address.go (about)

     1  /*
     2     Copyright 2021 Erigon contributors
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package common
    18  
    19  import (
    20  	"bytes"
    21  	"database/sql/driver"
    22  	"encoding/hex"
    23  	"fmt"
    24  	"math/big"
    25  	"reflect"
    26  
    27  	"github.com/ledgerwatch/erigon-lib/common/hexutility"
    28  	"github.com/ledgerwatch/erigon-lib/common/length"
    29  	"github.com/ledgerwatch/erigon-lib/crypto/cryptopool"
    30  )
    31  
    32  var (
    33  	addressT = reflect.TypeOf(Address{})
    34  )
    35  
    36  // Address represents the 20 byte address of an Ethereum account.
    37  type Address [length.Addr]byte
    38  
    39  // BytesToAddress returns Address with value b.
    40  // If b is larger than len(h), b will be cropped from the left.
    41  func BytesToAddress(b []byte) Address {
    42  	var a Address
    43  	a.SetBytes(b)
    44  	return a
    45  }
    46  
    47  // BigToAddress returns Address with byte values of b.
    48  // If b is larger than len(h), b will be cropped from the left.
    49  func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) }
    50  
    51  // HexToAddress returns Address with byte values of s.
    52  // If s is larger than len(h), s will be cropped from the left.
    53  func HexToAddress(s string) Address { return BytesToAddress(hexutility.FromHex(s)) }
    54  
    55  // IsHexAddress verifies whether a string can represent a valid hex-encoded
    56  // Ethereum address or not.
    57  func IsHexAddress(s string) bool {
    58  	if hexutility.Has0xPrefix(s) {
    59  		s = s[2:]
    60  	}
    61  	return len(s) == 2*length.Addr && hexutility.IsHex(s)
    62  }
    63  
    64  // Bytes gets the string representation of the underlying address.
    65  func (a Address) Bytes() []byte { return a[:] }
    66  
    67  // Hash converts an address to a hash by left-padding it with zeros.
    68  func (a Address) Hash() Hash { return BytesToHash(a[:]) }
    69  
    70  // Hex returns an EIP55-compliant hex string representation of the address.
    71  func (a Address) Hex() string {
    72  	return string(a.checksumHex())
    73  }
    74  
    75  // String implements fmt.Stringer.
    76  func (a Address) String() string {
    77  	return a.Hex()
    78  }
    79  
    80  func (a *Address) checksumHex() []byte {
    81  	buf := a.hex()
    82  
    83  	// compute checksum
    84  	sha := cryptopool.GetLegacyKeccak256()
    85  	//nolint:errcheck
    86  	sha.Write(buf[2:])
    87  	hash := sha.Sum(nil)
    88  	cryptopool.ReturnLegacyKeccak256(sha)
    89  
    90  	for i := 2; i < len(buf); i++ {
    91  		hashByte := hash[(i-2)/2]
    92  		if i%2 == 0 {
    93  			hashByte = hashByte >> 4
    94  		} else {
    95  			hashByte &= 0xf
    96  		}
    97  		if buf[i] > '9' && hashByte > 7 {
    98  			buf[i] -= 32
    99  		}
   100  	}
   101  	return buf
   102  }
   103  
   104  func (a Address) hex() []byte {
   105  	var buf [len(a)*2 + 2]byte
   106  	copy(buf[:2], "0x")
   107  	hex.Encode(buf[2:], a[:])
   108  	return buf[:]
   109  }
   110  
   111  // Format implements fmt.Formatter.
   112  // Address supports the %v, %s, %v, %x, %X and %d format verbs.
   113  func (a Address) Format(s fmt.State, c rune) {
   114  	switch c {
   115  	case 'v', 's':
   116  		s.Write(a.checksumHex())
   117  	case 'q':
   118  		q := []byte{'"'}
   119  		s.Write(q)
   120  		s.Write(a.checksumHex())
   121  		s.Write(q)
   122  	case 'x', 'X':
   123  		// %x disables the checksum.
   124  		hex := a.hex()
   125  		if !s.Flag('#') {
   126  			hex = hex[2:]
   127  		}
   128  		if c == 'X' {
   129  			hex = bytes.ToUpper(hex)
   130  		}
   131  		s.Write(hex)
   132  	case 'd':
   133  		fmt.Fprint(s, ([len(a)]byte)(a))
   134  	default:
   135  		fmt.Fprintf(s, "%%!%c(address=%x)", c, a)
   136  	}
   137  }
   138  
   139  // SetBytes sets the address to the value of b.
   140  // If b is larger than len(a), b will be cropped from the left.
   141  func (a *Address) SetBytes(b []byte) {
   142  	if len(b) > len(a) {
   143  		b = b[len(b)-length.Addr:]
   144  	}
   145  	copy(a[length.Addr-len(b):], b)
   146  }
   147  
   148  // MarshalText returns the hex representation of a.
   149  func (a Address) MarshalText() ([]byte, error) {
   150  	b := a[:]
   151  	result := make([]byte, len(b)*2+2)
   152  	copy(result, hexPrefix)
   153  	hex.Encode(result[2:], b)
   154  	return result, nil
   155  }
   156  
   157  // UnmarshalText parses a hash in hex syntax.
   158  func (a *Address) UnmarshalText(input []byte) error {
   159  	return hexutility.UnmarshalFixedText("Address", input, a[:])
   160  }
   161  
   162  // UnmarshalJSON parses a hash in hex syntax.
   163  func (a *Address) UnmarshalJSON(input []byte) error {
   164  	return hexutility.UnmarshalFixedJSON(addressT, input, a[:])
   165  }
   166  
   167  // Scan implements Scanner for database/sql.
   168  func (a *Address) Scan(src interface{}) error {
   169  	srcB, ok := src.([]byte)
   170  	if !ok {
   171  		return fmt.Errorf("can't scan %T into Address", src)
   172  	}
   173  	if len(srcB) != length.Addr {
   174  		return fmt.Errorf("can't scan []byte of len %d into Address, want %d", len(srcB), length.Addr)
   175  	}
   176  	copy(a[:], srcB)
   177  	return nil
   178  }
   179  
   180  // Value implements valuer for database/sql.
   181  func (a Address) Value() (driver.Value, error) {
   182  	return a[:], nil
   183  }