123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- // Copyright 2015 The go-ethereum Authors
- // This file is part of the go-ethereum library.
- //
- // The go-ethereum library is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Lesser General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // The go-ethereum library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Lesser General Public License for more details.
- //
- // You should have received a copy of the GNU Lesser General Public License
- // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
- package common
- import (
- "encoding/hex"
- "encoding/json"
- "fmt"
- "math/big"
- "math/rand"
- "reflect"
- "strings"
- "github.com/ethereum/go-ethereum/common/hexutil"
- "github.com/ethereum/go-ethereum/crypto/sha3"
- )
- const (
- HashLength = 32
- AddressLength = 20
- )
- var (
- hashT = reflect.TypeOf(Hash{})
- addressT = reflect.TypeOf(Address{})
- )
- // Hash represents the 32 byte Keccak256 hash of arbitrary data.
- type Hash [HashLength]byte
- // BytesToHash sets b to hash.
- // If b is larger than len(h), b will be cropped from the left.
- func BytesToHash(b []byte) Hash {
- var h Hash
- h.SetBytes(b)
- return h
- }
- // BigToHash sets byte representation of b to hash.
- // If b is larger than len(h), b will be cropped from the left.
- func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) }
- // HexToHash sets byte representation of s to hash.
- // If b is larger than len(h), b will be cropped from the left.
- func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) }
- // Bytes gets the byte representation of the underlying hash.
- func (h Hash) Bytes() []byte { return h[:] }
- // Big converts a hash to a big integer.
- func (h Hash) Big() *big.Int { return new(big.Int).SetBytes(h[:]) }
- // Hex converts a hash to a hex string.
- func (h Hash) Hex() string { return hexutil.Encode(h[:]) }
- // TerminalString implements log.TerminalStringer, formatting a string for console
- // output during logging.
- func (h Hash) TerminalString() string {
- return fmt.Sprintf("%x…%x", h[:3], h[29:])
- }
- // String implements the stringer interface and is used also by the logger when
- // doing full logging into a file.
- func (h Hash) String() string {
- return h.Hex()
- }
- // Format implements fmt.Formatter, forcing the byte slice to be formatted as is,
- // without going through the stringer interface used for logging.
- func (h Hash) Format(s fmt.State, c rune) {
- fmt.Fprintf(s, "%"+string(c), h[:])
- }
- // UnmarshalText parses a hash in hex syntax.
- func (h *Hash) UnmarshalText(input []byte) error {
- return hexutil.UnmarshalFixedText("Hash", input, h[:])
- }
- // UnmarshalJSON parses a hash in hex syntax.
- func (h *Hash) UnmarshalJSON(input []byte) error {
- return hexutil.UnmarshalFixedJSON(hashT, input, h[:])
- }
- // MarshalText returns the hex representation of h.
- func (h Hash) MarshalText() ([]byte, error) {
- return hexutil.Bytes(h[:]).MarshalText()
- }
- // SetBytes sets the hash to the value of b.
- // If b is larger than len(h), b will be cropped from the left.
- func (h *Hash) SetBytes(b []byte) {
- if len(b) > len(h) {
- b = b[len(b)-HashLength:]
- }
- copy(h[HashLength-len(b):], b)
- }
- // Generate implements testing/quick.Generator.
- func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value {
- m := rand.Intn(len(h))
- for i := len(h) - 1; i > m; i-- {
- h[i] = byte(rand.Uint32())
- }
- return reflect.ValueOf(h)
- }
- // UnprefixedHash allows marshaling a Hash without 0x prefix.
- type UnprefixedHash Hash
- // UnmarshalText decodes the hash from hex. The 0x prefix is optional.
- func (h *UnprefixedHash) UnmarshalText(input []byte) error {
- return hexutil.UnmarshalFixedUnprefixedText("UnprefixedHash", input, h[:])
- }
- // MarshalText encodes the hash as hex.
- func (h UnprefixedHash) MarshalText() ([]byte, error) {
- return []byte(hex.EncodeToString(h[:])), nil
- }
- /////////// Address
- // Address represents the 20 byte address of an Ethereum account.
- type Address [AddressLength]byte
- // BytesToAddress returns Address with value b.
- // If b is larger than len(h), b will be cropped from the left.
- func BytesToAddress(b []byte) Address {
- var a Address
- a.SetBytes(b)
- return a
- }
- // BigToAddress returns Address with byte values of b.
- // If b is larger than len(h), b will be cropped from the left.
- func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) }
- // HexToAddress returns Address with byte values of s.
- // If s is larger than len(h), s will be cropped from the left.
- func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) }
- // IsHexAddress verifies whether a string can represent a valid hex-encoded
- // Ethereum address or not.
- func IsHexAddress(s string) bool {
- if hasHexPrefix(s) {
- s = s[2:]
- }
- return len(s) == 2*AddressLength && isHex(s)
- }
- // Bytes gets the string representation of the underlying address.
- func (a Address) Bytes() []byte { return a[:] }
- // Big converts an address to a big integer.
- func (a Address) Big() *big.Int { return new(big.Int).SetBytes(a[:]) }
- // Hash converts an address to a hash by left-padding it with zeros.
- func (a Address) Hash() Hash { return BytesToHash(a[:]) }
- // Hex returns an EIP55-compliant hex string representation of the address.
- func (a Address) Hex() string {
- unchecksummed := hex.EncodeToString(a[:])
- sha := sha3.NewKeccak256()
- sha.Write([]byte(unchecksummed))
- hash := sha.Sum(nil)
- result := []byte(unchecksummed)
- for i := 0; i < len(result); i++ {
- hashByte := hash[i/2]
- if i%2 == 0 {
- hashByte = hashByte >> 4
- } else {
- hashByte &= 0xf
- }
- if result[i] > '9' && hashByte > 7 {
- result[i] -= 32
- }
- }
- return "0x" + string(result)
- }
- // String implements fmt.Stringer.
- func (a Address) String() string {
- return a.Hex()
- }
- // Format implements fmt.Formatter, forcing the byte slice to be formatted as is,
- // without going through the stringer interface used for logging.
- func (a Address) Format(s fmt.State, c rune) {
- fmt.Fprintf(s, "%"+string(c), a[:])
- }
- // SetBytes sets the address to the value of b.
- // If b is larger than len(a) it will panic.
- func (a *Address) SetBytes(b []byte) {
- if len(b) > len(a) {
- b = b[len(b)-AddressLength:]
- }
- copy(a[AddressLength-len(b):], b)
- }
- // MarshalText returns the hex representation of a.
- func (a Address) MarshalText() ([]byte, error) {
- return hexutil.Bytes(a[:]).MarshalText()
- }
- // UnmarshalText parses a hash in hex syntax.
- func (a *Address) UnmarshalText(input []byte) error {
- return hexutil.UnmarshalFixedText("Address", input, a[:])
- }
- // UnmarshalJSON parses a hash in hex syntax.
- func (a *Address) UnmarshalJSON(input []byte) error {
- return hexutil.UnmarshalFixedJSON(addressT, input, a[:])
- }
- // UnprefixedAddress allows marshaling an Address without 0x prefix.
- type UnprefixedAddress Address
- // UnmarshalText decodes the address from hex. The 0x prefix is optional.
- func (a *UnprefixedAddress) UnmarshalText(input []byte) error {
- return hexutil.UnmarshalFixedUnprefixedText("UnprefixedAddress", input, a[:])
- }
- // MarshalText encodes the address as hex.
- func (a UnprefixedAddress) MarshalText() ([]byte, error) {
- return []byte(hex.EncodeToString(a[:])), nil
- }
- // MixedcaseAddress retains the original string, which may or may not be
- // correctly checksummed
- type MixedcaseAddress struct {
- addr Address
- original string
- }
- // NewMixedcaseAddress constructor (mainly for testing)
- func NewMixedcaseAddress(addr Address) MixedcaseAddress {
- return MixedcaseAddress{addr: addr, original: addr.Hex()}
- }
- // NewMixedcaseAddressFromString is mainly meant for unit-testing
- func NewMixedcaseAddressFromString(hexaddr string) (*MixedcaseAddress, error) {
- if !IsHexAddress(hexaddr) {
- return nil, fmt.Errorf("Invalid address")
- }
- a := FromHex(hexaddr)
- return &MixedcaseAddress{addr: BytesToAddress(a), original: hexaddr}, nil
- }
- // UnmarshalJSON parses MixedcaseAddress
- func (ma *MixedcaseAddress) UnmarshalJSON(input []byte) error {
- if err := hexutil.UnmarshalFixedJSON(addressT, input, ma.addr[:]); err != nil {
- return err
- }
- return json.Unmarshal(input, &ma.original)
- }
- // MarshalJSON marshals the original value
- func (ma *MixedcaseAddress) MarshalJSON() ([]byte, error) {
- if strings.HasPrefix(ma.original, "0x") || strings.HasPrefix(ma.original, "0X") {
- return json.Marshal(fmt.Sprintf("0x%s", ma.original[2:]))
- }
- return json.Marshal(fmt.Sprintf("0x%s", ma.original))
- }
- // Address returns the address
- func (ma *MixedcaseAddress) Address() Address {
- return ma.addr
- }
- // String implements fmt.Stringer
- func (ma *MixedcaseAddress) String() string {
- if ma.ValidChecksum() {
- return fmt.Sprintf("%s [chksum ok]", ma.original)
- }
- return fmt.Sprintf("%s [chksum INVALID]", ma.original)
- }
- // ValidChecksum returns true if the address has valid checksum
- func (ma *MixedcaseAddress) ValidChecksum() bool {
- return ma.original == ma.addr.Hex()
- }
- // Original returns the mixed-case input string
- func (ma *MixedcaseAddress) Original() string {
- return ma.original
- }
|