mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
common: improve printing of Hash and Address (#21834)
This commit is contained in:
parent
dd318fc563
commit
c2db0e42d7
2 changed files with 248 additions and 24 deletions
106
common/types.go
106
common/types.go
|
|
@ -130,10 +130,34 @@ 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.
|
||||
// Format implements fmt.Formatter.
|
||||
// Hash supports the %v, %s, %v, %x, %X and %d format verbs.
|
||||
func (h Hash) Format(s fmt.State, c rune) {
|
||||
fmt.Fprintf(s, "%"+string(c), h[:])
|
||||
hexb := make([]byte, 2+len(h)*2)
|
||||
copy(hexb, "0x")
|
||||
hex.Encode(hexb[2:], h[:])
|
||||
|
||||
switch c {
|
||||
case 'x', 'X':
|
||||
if !s.Flag('#') {
|
||||
hexb = hexb[2:]
|
||||
}
|
||||
if c == 'X' {
|
||||
hexb = bytes.ToUpper(hexb)
|
||||
}
|
||||
fallthrough
|
||||
case 'v', 's':
|
||||
s.Write(hexb)
|
||||
case 'q':
|
||||
q := []byte{'"'}
|
||||
s.Write(q)
|
||||
s.Write(hexb)
|
||||
s.Write(q)
|
||||
case 'd':
|
||||
fmt.Fprint(s, ([len(h)]byte)(h))
|
||||
default:
|
||||
fmt.Fprintf(s, "%%!%c(hash=%x)", c, h)
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalText parses a hash in hex syntax.
|
||||
|
|
@ -231,24 +255,8 @@ 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.NewLegacyKeccak256()
|
||||
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 "xdc" + string(result)
|
||||
checksumed := a.checksumHex()
|
||||
return "xdc" + string(checksumed[2:])
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
|
|
@ -256,10 +264,60 @@ 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) checksumHex() []byte {
|
||||
buf := a.hex()
|
||||
|
||||
// compute checksum
|
||||
sha := sha3.NewLegacyKeccak256()
|
||||
sha.Write(buf[2:])
|
||||
hash := sha.Sum(nil)
|
||||
for i := 2; i < len(buf); i++ {
|
||||
hashByte := hash[(i-2)/2]
|
||||
if i%2 == 0 {
|
||||
hashByte = hashByte >> 4
|
||||
} else {
|
||||
hashByte &= 0xf
|
||||
}
|
||||
if buf[i] > '9' && hashByte > 7 {
|
||||
buf[i] -= 32
|
||||
}
|
||||
}
|
||||
return buf[:]
|
||||
}
|
||||
|
||||
func (a Address) hex() []byte {
|
||||
var buf [len(a)*2 + 2]byte
|
||||
copy(buf[:2], "0x")
|
||||
hex.Encode(buf[2:], a[:])
|
||||
return buf[:]
|
||||
}
|
||||
|
||||
// Format implements fmt.Formatter.
|
||||
// Address supports the %v, %s, %q, %x, %X and %d format verbs.
|
||||
func (a Address) Format(s fmt.State, c rune) {
|
||||
fmt.Fprintf(s, "%"+string(c), a[:])
|
||||
switch c {
|
||||
case 'v', 's':
|
||||
s.Write(a.checksumHex())
|
||||
case 'q':
|
||||
q := []byte{'"'}
|
||||
s.Write(q)
|
||||
s.Write(a.checksumHex())
|
||||
s.Write(q)
|
||||
case 'x', 'X':
|
||||
// %x disables the checksum.
|
||||
hex := a.hex()
|
||||
if !s.Flag('#') {
|
||||
hex = hex[2:]
|
||||
}
|
||||
if c == 'X' {
|
||||
hex = bytes.ToUpper(hex)
|
||||
}
|
||||
s.Write(hex)
|
||||
case 'd':
|
||||
fmt.Fprint(s, ([len(a)]byte)(a))
|
||||
default:
|
||||
fmt.Fprintf(s, "%%!%c(address=%x)", c, a)
|
||||
}
|
||||
}
|
||||
|
||||
// SetBytes sets the address to the value of b.
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
"testing"
|
||||
|
|
@ -156,6 +158,170 @@ func BenchmarkAddressHex(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAddress_Format(t *testing.T) {
|
||||
b := []byte{
|
||||
0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
|
||||
0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
|
||||
}
|
||||
var addr Address
|
||||
addr.SetBytes(b)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
out string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "println",
|
||||
out: fmt.Sprintln(addr),
|
||||
want: "0xB26f2b342AAb24BCF63ea218c6A9274D30Ab9A15\n",
|
||||
},
|
||||
{
|
||||
name: "print",
|
||||
out: fmt.Sprint(addr),
|
||||
want: "0xB26f2b342AAb24BCF63ea218c6A9274D30Ab9A15",
|
||||
},
|
||||
{
|
||||
name: "printf-s",
|
||||
out: func() string {
|
||||
buf := new(bytes.Buffer)
|
||||
fmt.Fprintf(buf, "%s", addr)
|
||||
return buf.String()
|
||||
}(),
|
||||
want: "0xB26f2b342AAb24BCF63ea218c6A9274D30Ab9A15",
|
||||
},
|
||||
{
|
||||
name: "printf-q",
|
||||
out: fmt.Sprintf("%q", addr),
|
||||
want: `"0xB26f2b342AAb24BCF63ea218c6A9274D30Ab9A15"`,
|
||||
},
|
||||
{
|
||||
name: "printf-x",
|
||||
out: fmt.Sprintf("%x", addr),
|
||||
want: "b26f2b342aab24bcf63ea218c6a9274d30ab9a15",
|
||||
},
|
||||
{
|
||||
name: "printf-X",
|
||||
out: fmt.Sprintf("%X", addr),
|
||||
want: "B26F2B342AAB24BCF63EA218C6A9274D30AB9A15",
|
||||
},
|
||||
{
|
||||
name: "printf-#x",
|
||||
out: fmt.Sprintf("%#x", addr),
|
||||
want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15",
|
||||
},
|
||||
{
|
||||
name: "printf-v",
|
||||
out: fmt.Sprintf("%v", addr),
|
||||
want: "0xB26f2b342AAb24BCF63ea218c6A9274D30Ab9A15",
|
||||
},
|
||||
// The original default formatter for byte slice
|
||||
{
|
||||
name: "printf-d",
|
||||
out: fmt.Sprintf("%d", addr),
|
||||
want: "[178 111 43 52 42 171 36 188 246 62 162 24 198 169 39 77 48 171 154 21]",
|
||||
},
|
||||
// Invalid format char.
|
||||
{
|
||||
name: "printf-t",
|
||||
out: fmt.Sprintf("%t", addr),
|
||||
want: "%!t(address=b26f2b342aab24bcf63ea218c6a9274d30ab9a15)",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.out != tt.want {
|
||||
t.Errorf("%s does not render as expected:\n got %s\nwant %s", tt.name, tt.out, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHash_Format(t *testing.T) {
|
||||
var hash Hash
|
||||
hash.SetBytes([]byte{
|
||||
0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
|
||||
0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
|
||||
0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
|
||||
0x10, 0x00,
|
||||
})
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
out string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "println",
|
||||
out: fmt.Sprintln(hash),
|
||||
want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000\n",
|
||||
},
|
||||
{
|
||||
name: "print",
|
||||
out: fmt.Sprint(hash),
|
||||
want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000",
|
||||
},
|
||||
{
|
||||
name: "printf-s",
|
||||
out: func() string {
|
||||
buf := new(bytes.Buffer)
|
||||
fmt.Fprintf(buf, "%s", hash)
|
||||
return buf.String()
|
||||
}(),
|
||||
want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000",
|
||||
},
|
||||
{
|
||||
name: "printf-q",
|
||||
out: fmt.Sprintf("%q", hash),
|
||||
want: `"0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000"`,
|
||||
},
|
||||
{
|
||||
name: "printf-x",
|
||||
out: fmt.Sprintf("%x", hash),
|
||||
want: "b26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000",
|
||||
},
|
||||
{
|
||||
name: "printf-X",
|
||||
out: fmt.Sprintf("%X", hash),
|
||||
want: "B26F2B342AAB24BCF63EA218C6A9274D30AB9A15A218C6A9274D30AB9A151000",
|
||||
},
|
||||
{
|
||||
name: "printf-#x",
|
||||
out: fmt.Sprintf("%#x", hash),
|
||||
want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000",
|
||||
},
|
||||
{
|
||||
name: "printf-#X",
|
||||
out: fmt.Sprintf("%#X", hash),
|
||||
want: "0XB26F2B342AAB24BCF63EA218C6A9274D30AB9A15A218C6A9274D30AB9A151000",
|
||||
},
|
||||
{
|
||||
name: "printf-v",
|
||||
out: fmt.Sprintf("%v", hash),
|
||||
want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000",
|
||||
},
|
||||
// The original default formatter for byte slice
|
||||
{
|
||||
name: "printf-d",
|
||||
out: fmt.Sprintf("%d", hash),
|
||||
want: "[178 111 43 52 42 171 36 188 246 62 162 24 198 169 39 77 48 171 154 21 162 24 198 169 39 77 48 171 154 21 16 0]",
|
||||
},
|
||||
// Invalid format char.
|
||||
{
|
||||
name: "printf-t",
|
||||
out: fmt.Sprintf("%t", hash),
|
||||
want: "%!t(hash=b26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000)",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.out != tt.want {
|
||||
t.Errorf("%s does not render as expected:\n got %s\nwant %s", tt.name, tt.out, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveItemInArray(t *testing.T) {
|
||||
array := []Address{HexToAddress("0x0000003"), HexToAddress("0x0000001"), HexToAddress("0x0000002"), HexToAddress("0x0000003")}
|
||||
remove := []Address{HexToAddress("0x0000002"), HexToAddress("0x0000004"), HexToAddress("0x0000003")}
|
||||
|
|
|
|||
Loading…
Reference in a new issue