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 }