Format Ethereum addresses with EIP55 checksum
parent
d3931953d5
commit
ac9a721cc6
|
@ -235,7 +235,7 @@
|
|||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["ripemd160", "sha3"]
|
||||
revision = "d6449816ce06963d9d136eee5a56fca5b0616e7e"
|
||||
revision = "a832865fa7ada6126f4c6124ac49f71be71bff2a"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue