84f8c0cc1f
This commit adds many comments and removes unused code. It also removes the EmptyHash function, which had some uses but was silly.
303 lines
8.9 KiB
Go
303 lines
8.9 KiB
Go
// 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
|
|
}
|