github.com/chain5j/chain5j-pkg@v1.0.7/types/address.go (about)

     1  // Package types
     2  // 
     3  // @author: xwc1125
     4  package types
     5  
     6  import (
     7  	"database/sql/driver"
     8  	"encoding/hex"
     9  	"encoding/json"
    10  	"fmt"
    11  	"math/big"
    12  	"reflect"
    13  	"strings"
    14  
    15  	"github.com/chain5j/chain5j-pkg/crypto/hashalg/sha3"
    16  	"github.com/chain5j/chain5j-pkg/util/hexutil"
    17  )
    18  
    19  const AddressLength = 20
    20  
    21  var addressT = reflect.TypeOf(Address{})
    22  
    23  var (
    24  	EmptyAddress = Address{}
    25  )
    26  
    27  // Address represents the 20 byte address of an  account.
    28  type Address [AddressLength]byte
    29  
    30  // BytesToAddress returns Address with value b.
    31  // If b is larger than len(h), b will be cropped from the left.
    32  func BytesToAddress(b []byte) Address {
    33  	var a Address
    34  	a.SetBytes(b)
    35  	return a
    36  }
    37  
    38  func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) }
    39  
    40  // BigToAddress returns Address with byte values of b.
    41  // If b is larger than len(h), b will be cropped from the left.
    42  func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) }
    43  
    44  // HexToAddress returns Address with byte values of s.
    45  // If s is larger than len(h), s will be cropped from the left.
    46  func HexToAddress(s string) Address { return BytesToAddress(hexutil.MustDecode(s)) }
    47  
    48  // IsHexAddress verifies whether a string can represent a valid hex-encoded
    49  // SuperChain address or not.
    50  func IsHexAddress(s string) bool {
    51  	if hexutil.HasHexPrefix(s) {
    52  		s = s[2:]
    53  	}
    54  	return len(s) == 2*AddressLength && hexutil.IsHex(s)
    55  }
    56  
    57  func (a Address) Len() int { return AddressLength }
    58  
    59  // Bytes gets the string representation of the underlying address.
    60  func (a Address) Bytes() []byte { return a[:] }
    61  
    62  // Big converts an address to a big integer.
    63  func (a Address) Big() *big.Int { return new(big.Int).SetBytes(a[:]) }
    64  
    65  // Hash converts an address to a hash by left-padding it with zeros.
    66  func (a Address) Hash() Hash { return BytesToHash(a[:]) }
    67  
    68  // Hex returns an EIP55-compliant hex string representation of the address.
    69  func (a Address) Hex() string {
    70  	unchecksummed := hex.EncodeToString(a[:])
    71  	sha := sha3.NewKeccak256()
    72  	sha.Write([]byte(unchecksummed))
    73  	hash := sha.Sum(nil)
    74  
    75  	result := []byte(unchecksummed)
    76  	for i := 0; i < len(result); i++ {
    77  		hashByte := hash[i/2]
    78  		if i%2 == 0 {
    79  			hashByte = hashByte >> 4
    80  		} else {
    81  			hashByte &= 0xf
    82  		}
    83  		if result[i] > '9' && hashByte > 7 {
    84  			result[i] -= 32
    85  		}
    86  	}
    87  	return "0x" + string(result)
    88  }
    89  
    90  // String implements fmt.Stringer.
    91  func (a Address) String() string {
    92  	return a.Hex()
    93  }
    94  
    95  func (a Address) FromBytes(b []byte) (Addr, error) {
    96  	return BytesToAddress(b), nil
    97  }
    98  
    99  func (a Address) FromStr(addr string) (Addr, error) {
   100  	return HexToAddress(addr), nil
   101  }
   102  
   103  func (a Address) Validate(addr string) bool {
   104  	return true
   105  }
   106  
   107  // TerminalString String implements fmt.Stringer.
   108  func (a Address) TerminalString() string {
   109  	return a.Hex()
   110  }
   111  
   112  // Format implements fmt.Formatter, forcing the byte slice to be formatted as is,
   113  // without going through the stringer interface used for logging.
   114  func (a Address) Format(s fmt.State, c rune) {
   115  	fmt.Fprintf(s, "%"+string(c), a[:])
   116  }
   117  
   118  // SetBytes sets the address to the value of b.
   119  // If b is larger than len(a) it will panic.
   120  func (a *Address) SetBytes(b []byte) {
   121  	if len(b) > len(a) {
   122  		b = b[len(b)-AddressLength:]
   123  	}
   124  	copy(a[AddressLength-len(b):], b)
   125  }
   126  
   127  // MarshalText returns the hex representation of a.
   128  func (a Address) MarshalText() ([]byte, error) {
   129  	return hexutil.Bytes(a[:]).MarshalText()
   130  }
   131  
   132  // UnmarshalText parses a hash in hex syntax.
   133  func (a *Address) UnmarshalText(input []byte) error {
   134  	return hexutil.UnmarshalFixedText("Address", input, a[:])
   135  }
   136  
   137  // UnmarshalJSON parses a hash in hex syntax.
   138  func (a *Address) UnmarshalJSON(input []byte) error {
   139  	return hexutil.UnmarshalFixedJSON(addressT, input, a[:])
   140  }
   141  
   142  // Scan implements Scanner for database/sql.
   143  func (a *Address) Scan(src interface{}) error {
   144  	srcB, ok := src.([]byte)
   145  	if !ok {
   146  		return fmt.Errorf("can't scan %T into Address", src)
   147  	}
   148  	if len(srcB) != AddressLength {
   149  		return fmt.Errorf("can't scan []byte of len %d into Address, want %d", len(srcB), AddressLength)
   150  	}
   151  	copy(a[:], srcB)
   152  	return nil
   153  }
   154  
   155  // Value implements valuer for database/sql.
   156  func (a Address) Value() (driver.Value, error) {
   157  	return a[:], nil
   158  }
   159  
   160  func (a Address) Nil() bool {
   161  	return a == Address{}
   162  }
   163  
   164  // UnprefixedAddress allows marshaling an Address without 0x prefix.
   165  type UnprefixedAddress Address
   166  
   167  // UnmarshalText decodes the address from hex. The 0x prefix is optional.
   168  func (a *UnprefixedAddress) UnmarshalText(input []byte) error {
   169  	return hexutil.UnmarshalFixedUnprefixedText("UnprefixedAddress", input, a[:])
   170  }
   171  
   172  // MarshalText encodes the address as hex.
   173  func (a UnprefixedAddress) MarshalText() ([]byte, error) {
   174  	return []byte(hex.EncodeToString(a[:])), nil
   175  }
   176  
   177  // MixedcaseAddress retains the original string, which may or may not be
   178  // correctly checksummed
   179  type MixedcaseAddress struct {
   180  	addr     Address
   181  	original string
   182  }
   183  
   184  // NewMixedcaseAddress constructor (mainly for testing)
   185  func NewMixedcaseAddress(addr Address) MixedcaseAddress {
   186  	return MixedcaseAddress{addr: addr, original: addr.Hex()}
   187  }
   188  
   189  // NewMixedcaseAddressFromString is mainly meant for unit-testing
   190  func NewMixedcaseAddressFromString(hexaddr string) (*MixedcaseAddress, error) {
   191  	if !IsHexAddress(hexaddr) {
   192  		return nil, fmt.Errorf("Invalid address")
   193  	}
   194  	a := hexutil.MustDecode(hexaddr)
   195  	return &MixedcaseAddress{addr: BytesToAddress(a), original: hexaddr}, nil
   196  }
   197  
   198  // UnmarshalJSON parses MixedcaseAddress
   199  func (ma *MixedcaseAddress) UnmarshalJSON(input []byte) error {
   200  	if err := hexutil.UnmarshalFixedJSON(addressT, input, ma.addr[:]); err != nil {
   201  		return err
   202  	}
   203  	return json.Unmarshal(input, &ma.original)
   204  }
   205  
   206  // MarshalJSON marshals the original value
   207  func (ma *MixedcaseAddress) MarshalJSON() ([]byte, error) {
   208  	if strings.HasPrefix(ma.original, "0x") || strings.HasPrefix(ma.original, "0X") {
   209  		return json.Marshal(fmt.Sprintf("0x%s", ma.original[2:]))
   210  	}
   211  	return json.Marshal(fmt.Sprintf("0x%s", ma.original))
   212  }
   213  
   214  // Address returns the address
   215  func (ma *MixedcaseAddress) Address() Address {
   216  	return ma.addr
   217  }
   218  
   219  // String implements fmt.Stringer
   220  func (ma *MixedcaseAddress) String() string {
   221  	if ma.ValidChecksum() {
   222  		return fmt.Sprintf("%s [chksum ok]", ma.original)
   223  	}
   224  	return fmt.Sprintf("%s [chksum INVALID]", ma.original)
   225  }
   226  
   227  // ValidChecksum returns true if the address has valid checksum
   228  func (ma *MixedcaseAddress) ValidChecksum() bool {
   229  	return ma.original == ma.addr.Hex()
   230  }
   231  
   232  // Original returns the mixed-case input string
   233  func (ma *MixedcaseAddress) Original() string {
   234  	return ma.original
   235  }