Format Ethereum addresses with EIP55 checksum

fiatRates
Martin Boehm 2019-09-30 17:11:17 +02:00
parent d3931953d5
commit ac9a721cc6
5 changed files with 62 additions and 23 deletions

2
Gopkg.lock generated
View File

@ -235,7 +235,7 @@
branch = "master"
name = "golang.org/x/crypto"
packages = ["ripemd160", "sha3"]
revision = "d6449816ce06963d9d136eee5a56fca5b0616e7e"
revision = "a832865fa7ada6126f4c6124ac49f71be71bff2a"
[[projects]]
branch = "master"

View File

@ -9,7 +9,6 @@ import (
"sync"
ethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/golang/glog"
"github.com/juju/errors"
)
@ -165,7 +164,7 @@ func (b *EthereumRPC) EthereumTypeGetErc20ContractInfo(contractDesc bchain.Addre
contract, found := cachedContracts[cds]
cachedContractsMux.Unlock()
if !found {
address := hexutil.Encode(contractDesc)
address := EIP55Address(contractDesc)
data, err := b.ethCall(erc20NameSignature, address)
if err != nil {
return nil, err
@ -204,8 +203,8 @@ func (b *EthereumRPC) EthereumTypeGetErc20ContractInfo(contractDesc bchain.Addre
// EthereumTypeGetErc20ContractBalance returns balance of ERC20 contract for given address
func (b *EthereumRPC) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc bchain.AddressDescriptor) (*big.Int, error) {
addr := hexutil.Encode(addrDesc)
contract := hexutil.Encode(contractDesc)
addr := EIP55Address(addrDesc)
contract := EIP55Address(contractDesc)
req := erc20BalanceOf + "0000000000000000000000000000000000000000000000000000000000000000"[len(addr)-2:] + addr[2:]
data, err := b.ethCall(req, contract)
if err != nil {

View File

@ -9,6 +9,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/golang/protobuf/proto"
"github.com/juju/errors"
"golang.org/x/crypto/sha3"
)
// EthereumTypeAddressDescriptorLen - in case of EthereumType, the AddressDescriptor has fixed length
@ -176,9 +177,34 @@ func (p *EthereumParser) GetAddrDescFromAddress(address string) (bchain.AddressD
return hex.DecodeString(address)
}
// EIP55Address returns an EIP55-compliant hex string representation of the address
func EIP55Address(addrDesc bchain.AddressDescriptor) string {
raw := hexutil.Encode(addrDesc)
if len(raw) != 42 {
return raw
}
sha := sha3.NewLegacyKeccak256()
result := []byte(raw)
sha.Write(result[2:])
hash := sha.Sum(nil)
for i := 2; i < len(result); i++ {
hashByte := hash[(i-2)>>1]
if i%2 == 0 {
hashByte = hashByte >> 4
} else {
hashByte &= 0xf
}
if result[i] > '9' && hashByte > 7 {
result[i] -= 32
}
}
return string(result)
}
// GetAddressesFromAddrDesc returns addresses for given address descriptor with flag if the addresses are searchable
func (p *EthereumParser) GetAddressesFromAddrDesc(addrDesc bchain.AddressDescriptor) ([]string, bool, error) {
return []string{hexutil.Encode(addrDesc)}, true, nil
return []string{EIP55Address(addrDesc)}, true, nil
}
// GetScriptFromAddrDesc returns output script for given address descriptor
@ -308,7 +334,7 @@ func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
rt := rpcTransaction{
AccountNonce: hexutil.EncodeUint64(pt.Tx.AccountNonce),
BlockNumber: hexutil.EncodeUint64(uint64(pt.BlockNumber)),
From: hexutil.Encode(pt.Tx.From),
From: EIP55Address(pt.Tx.From),
GasLimit: hexutil.EncodeUint64(pt.Tx.GasLimit),
Hash: hexutil.Encode(pt.Tx.Hash),
Payload: hexutil.Encode(pt.Tx.Payload),
@ -316,7 +342,7 @@ func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
// R: hexEncodeBig(pt.R),
// S: hexEncodeBig(pt.S),
// V: hexEncodeBig(pt.V),
To: hexutil.Encode(pt.Tx.To),
To: EIP55Address(pt.Tx.To),
TransactionIndex: hexutil.EncodeUint64(uint64(pt.Tx.TransactionIndex)),
Value: hexEncodeBig(pt.Tx.Value),
}
@ -329,7 +355,7 @@ func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
topics[j] = hexutil.Encode(t)
}
logs[i] = &rpcLog{
Address: hexutil.Encode(l.Address),
Address: EIP55Address(l.Address),
Data: hexutil.Encode(l.Data),
Topics: topics,
}

View File

@ -77,14 +77,14 @@ func init() {
Txid: "0xcd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b",
Vin: []bchain.Vin{
{
Addresses: []string{"0x3e3a3d69dc66ba10737f531ed088954a9ec89d97"},
Addresses: []string{"0x3E3a3D69dc66bA10737F531ed088954a9EC89d97"},
},
},
Vout: []bchain.Vout{
{
ValueSat: *big.NewInt(1999622000000000000),
ScriptPubKey: bchain.ScriptPubKey{
Addresses: []string{"0x555ee11fbddc0e49a9bab358a8941ad95ffdb48f"},
Addresses: []string{"0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f"},
},
},
},
@ -93,12 +93,12 @@ func init() {
AccountNonce: "0xb26c",
GasPrice: "0x430e23400",
GasLimit: "0x5208",
To: "0x555ee11fbddc0e49a9bab358a8941ad95ffdb48f",
To: "0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f",
Value: "0x1bc0159d530e6000",
Payload: "0x",
Hash: "0xcd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b",
BlockNumber: "0x41eee8",
From: "0x3e3a3d69dc66ba10737f531ed088954a9ec89d97",
From: "0x3E3a3D69dc66bA10737F531ed088954a9EC89d97",
TransactionIndex: "0xa",
},
Receipt: &rpcReceipt{
@ -115,14 +115,14 @@ func init() {
Txid: "0xa9cd088aba2131000da6f38a33c20169baee476218deea6b78720700b895b101",
Vin: []bchain.Vin{
{
Addresses: []string{"0x20cd153de35d469ba46127a0c8f18626b59a256a"},
Addresses: []string{"0x20cD153de35D469BA46127A0C8F18626b59a256A"},
},
},
Vout: []bchain.Vout{
{
ValueSat: *big.NewInt(0),
ScriptPubKey: bchain.ScriptPubKey{
Addresses: []string{"0x4af4114f73d1c1c903ac9e0361b379d1291808a2"},
Addresses: []string{"0x4af4114F73d1c1C903aC9E0361b379D1291808A2"},
},
},
},
@ -131,19 +131,19 @@ func init() {
AccountNonce: "0xd0",
GasPrice: "0x9502f9000",
GasLimit: "0x130d5",
To: "0x4af4114f73d1c1c903ac9e0361b379d1291808a2",
To: "0x4af4114F73d1c1C903aC9E0361b379D1291808A2",
Value: "0x0",
Payload: "0xa9059cbb000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f00000000000000000000000000000000000000000000021e19e0c9bab2400000",
Hash: "0xa9cd088aba2131000da6f38a33c20169baee476218deea6b78720700b895b101",
BlockNumber: "0x41eee8",
From: "0x20cd153de35d469ba46127a0c8f18626b59a256a",
From: "0x20cD153de35D469BA46127A0C8F18626b59a256A",
TransactionIndex: "0x0"},
Receipt: &rpcReceipt{
GasUsed: "0xcb39",
Status: "0x1",
Logs: []*rpcLog{
{
Address: "0x4af4114f73d1c1c903ac9e0361b379d1291808a2",
Address: "0x4af4114F73d1c1C903aC9E0361b379D1291808A2",
Data: "0x00000000000000000000000000000000000000000000021e19e0c9bab2400000",
Topics: []string{
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",

View File

@ -8,6 +8,7 @@ import (
"io/ioutil"
"path/filepath"
"reflect"
"strings"
"testing"
"time"
@ -177,8 +178,8 @@ func testGetTransaction(t *testing.T, h *TestHandler) {
// CoinSpecificData are not specified in the fixtures
got.CoinSpecificData = nil
normalizeEmptyAddresses(want)
normalizeEmptyAddresses(got)
normalizeAddresses(want, h.Chain.GetChainParser())
normalizeAddresses(got, h.Chain.GetChainParser())
if !reflect.DeepEqual(got, want) {
t.Errorf("GetTransaction() got %+#v, want %+#v", got, want)
@ -196,8 +197,8 @@ func testGetTransactionForMempool(t *testing.T, h *TestHandler) {
t.Fatal(err)
}
normalizeEmptyAddresses(want)
normalizeEmptyAddresses(got)
normalizeAddresses(want, h.Chain.GetChainParser())
normalizeAddresses(got, h.Chain.GetChainParser())
// transactions parsed from JSON may contain additional data
got.Confirmations, got.Blocktime, got.Time, got.CoinSpecificData = 0, 0, 0, nil
@ -208,15 +209,28 @@ func testGetTransactionForMempool(t *testing.T, h *TestHandler) {
}
// empty slice can be either []slice{} or nil; reflect.DeepEqual treats them as different value
func normalizeEmptyAddresses(tx *bchain.Tx) {
// remove checksums from ethereum addresses
func normalizeAddresses(tx *bchain.Tx, parser bchain.BlockChainParser) {
for i := range tx.Vin {
if len(tx.Vin[i].Addresses) == 0 {
tx.Vin[i].Addresses = nil
} else {
if parser.GetChainType() == bchain.ChainEthereumType {
for j := range tx.Vin[i].Addresses {
tx.Vin[i].Addresses[j] = strings.ToLower(tx.Vin[i].Addresses[j])
}
}
}
}
for i := range tx.Vout {
if len(tx.Vout[i].ScriptPubKey.Addresses) == 0 {
tx.Vout[i].ScriptPubKey.Addresses = nil
} else {
if parser.GetChainType() == bchain.ChainEthereumType {
for j := range tx.Vout[i].ScriptPubKey.Addresses {
tx.Vout[i].ScriptPubKey.Addresses[j] = strings.ToLower(tx.Vout[i].ScriptPubKey.Addresses[j])
}
}
}
}
}