common: EIP55-compliant Address.Hex() (#14815)
This patch updates the Address type in common/types.go so that the Hex function provides an EIP55-compliant output string. The implementation is pretty lightweight; on my laptop the benchmark gives 1100ns/op, with the majority of that value due to the Keccak hash.
This commit is contained in:
commit
bdf98b4fcd
@ -146,7 +146,7 @@ Passphrase: {{.InputLine "foobar"}}
|
|||||||
|
|
||||||
wantMessages := []string{
|
wantMessages := []string{
|
||||||
"Unlocked account",
|
"Unlocked account",
|
||||||
"=0xf466859ead1932d743d622cb74fc058882e8648a",
|
"=0xf466859eAD1932D743d622CB74FC058882E8648A",
|
||||||
}
|
}
|
||||||
for _, m := range wantMessages {
|
for _, m := range wantMessages {
|
||||||
if !strings.Contains(geth.StderrText(), m) {
|
if !strings.Contains(geth.StderrText(), m) {
|
||||||
@ -191,8 +191,8 @@ Passphrase: {{.InputLine "foobar"}}
|
|||||||
|
|
||||||
wantMessages := []string{
|
wantMessages := []string{
|
||||||
"Unlocked account",
|
"Unlocked account",
|
||||||
"=0x7ef5a6135f1fd6a02593eedc869c6d41d934aef8",
|
"=0x7EF5A6135f1FD6a02593eEdC869c6D41D934aef8",
|
||||||
"=0x289d485d9771714cce91d3393d764e1311907acc",
|
"=0x289d485D9771714CCe91D3393D764E1311907ACc",
|
||||||
}
|
}
|
||||||
for _, m := range wantMessages {
|
for _, m := range wantMessages {
|
||||||
if !strings.Contains(geth.StderrText(), m) {
|
if !strings.Contains(geth.StderrText(), m) {
|
||||||
@ -211,8 +211,8 @@ func TestUnlockFlagPasswordFile(t *testing.T) {
|
|||||||
|
|
||||||
wantMessages := []string{
|
wantMessages := []string{
|
||||||
"Unlocked account",
|
"Unlocked account",
|
||||||
"=0x7ef5a6135f1fd6a02593eedc869c6d41d934aef8",
|
"=0x7EF5A6135f1FD6a02593eEdC869c6D41D934aef8",
|
||||||
"=0x289d485d9771714cce91d3393d764e1311907acc",
|
"=0x289d485D9771714CCe91D3393D764E1311907ACc",
|
||||||
}
|
}
|
||||||
for _, m := range wantMessages {
|
for _, m := range wantMessages {
|
||||||
if !strings.Contains(geth.StderrText(), m) {
|
if !strings.Contains(geth.StderrText(), m) {
|
||||||
@ -261,7 +261,7 @@ In order to avoid this warning, you need to remove the following duplicate key f
|
|||||||
|
|
||||||
wantMessages := []string{
|
wantMessages := []string{
|
||||||
"Unlocked account",
|
"Unlocked account",
|
||||||
"=0xf466859ead1932d743d622cb74fc058882e8648a",
|
"=0xf466859eAD1932D743d622CB74FC058882E8648A",
|
||||||
}
|
}
|
||||||
for _, m := range wantMessages {
|
for _, m := range wantMessages {
|
||||||
if !strings.Contains(geth.StderrText(), m) {
|
if !strings.Contains(geth.StderrText(), m) {
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -163,7 +164,28 @@ func (a Address) Str() string { return string(a[:]) }
|
|||||||
func (a Address) Bytes() []byte { return a[:] }
|
func (a Address) Bytes() []byte { return a[:] }
|
||||||
func (a Address) Big() *big.Int { return new(big.Int).SetBytes(a[:]) }
|
func (a Address) Big() *big.Int { return new(big.Int).SetBytes(a[:]) }
|
||||||
func (a Address) Hash() Hash { return BytesToHash(a[:]) }
|
func (a Address) Hash() Hash { return BytesToHash(a[:]) }
|
||||||
func (a Address) Hex() string { return hexutil.Encode(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 the stringer interface and is used also by the logger.
|
// String implements the stringer interface and is used also by the logger.
|
||||||
func (a Address) String() string {
|
func (a Address) String() string {
|
||||||
|
@ -94,3 +94,34 @@ func TestAddressUnmarshalJSON(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAddressHexChecksum(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
Input string
|
||||||
|
Output string
|
||||||
|
}{
|
||||||
|
// Test cases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md#specification
|
||||||
|
{"0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed", "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"},
|
||||||
|
{"0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359", "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359"},
|
||||||
|
{"0xdbf03b407c01e7cd3cbea99509d93f8dddc8c6fb", "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB"},
|
||||||
|
{"0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb", "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb"},
|
||||||
|
// Ensure that non-standard length input values are handled correctly
|
||||||
|
{"0xa", "0x000000000000000000000000000000000000000A"},
|
||||||
|
{"0x0a", "0x000000000000000000000000000000000000000A"},
|
||||||
|
{"0x00a", "0x000000000000000000000000000000000000000A"},
|
||||||
|
{"0x000000000000000000000000000000000000000a", "0x000000000000000000000000000000000000000A"},
|
||||||
|
}
|
||||||
|
for i, test := range tests {
|
||||||
|
output := HexToAddress(test.Input).Hex()
|
||||||
|
if output != test.Output {
|
||||||
|
t.Errorf("test #%d: failed to match when it should (%s != %s)", i, output, test.Output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAddressHex(b *testing.B) {
|
||||||
|
testAddr := HexToAddress("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed")
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
testAddr.Hex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user