diff --git a/cmd/geth/accountcmd_test.go b/cmd/geth/accountcmd_test.go index e146323eeb..66e3e02a4e 100644 --- a/cmd/geth/accountcmd_test.go +++ b/cmd/geth/accountcmd_test.go @@ -146,7 +146,7 @@ Passphrase: {{.InputLine "foobar"}} wantMessages := []string{ "Unlocked account", - "=0xf466859ead1932d743d622cb74fc058882e8648a", + "=0xf466859eAD1932D743d622CB74FC058882E8648A", } for _, m := range wantMessages { if !strings.Contains(geth.StderrText(), m) { @@ -191,8 +191,8 @@ Passphrase: {{.InputLine "foobar"}} wantMessages := []string{ "Unlocked account", - "=0x7ef5a6135f1fd6a02593eedc869c6d41d934aef8", - "=0x289d485d9771714cce91d3393d764e1311907acc", + "=0x7EF5A6135f1FD6a02593eEdC869c6D41D934aef8", + "=0x289d485D9771714CCe91D3393D764E1311907ACc", } for _, m := range wantMessages { if !strings.Contains(geth.StderrText(), m) { @@ -211,8 +211,8 @@ func TestUnlockFlagPasswordFile(t *testing.T) { wantMessages := []string{ "Unlocked account", - "=0x7ef5a6135f1fd6a02593eedc869c6d41d934aef8", - "=0x289d485d9771714cce91d3393d764e1311907acc", + "=0x7EF5A6135f1FD6a02593eEdC869c6D41D934aef8", + "=0x289d485D9771714CCe91D3393D764E1311907ACc", } for _, m := range wantMessages { 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{ "Unlocked account", - "=0xf466859ead1932d743d622cb74fc058882e8648a", + "=0xf466859eAD1932D743d622CB74FC058882E8648A", } for _, m := range wantMessages { if !strings.Contains(geth.StderrText(), m) { diff --git a/common/types.go b/common/types.go index 8037266349..eaf8352fbc 100644 --- a/common/types.go +++ b/common/types.go @@ -24,6 +24,7 @@ import ( "reflect" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto/sha3" ) const ( @@ -163,7 +164,28 @@ func (a Address) Str() string { return string(a[:]) } func (a Address) Bytes() []byte { return a[:] } func (a Address) Big() *big.Int { return new(big.Int).SetBytes(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. func (a Address) String() string { diff --git a/common/types_test.go b/common/types_test.go index 154c330632..6f3b315761 100644 --- a/common/types_test.go +++ b/common/types_test.go @@ -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() + } +}