diff --git a/bchain/coins/eth/ethparser.go b/bchain/coins/eth/ethparser.go index 4cd78551..f7dc7bfb 100644 --- a/bchain/coins/eth/ethparser.go +++ b/bchain/coins/eth/ethparser.go @@ -2,9 +2,8 @@ package eth import ( "blockbook/bchain" + "encoding/hex" "errors" - - ethcommon "github.com/ethereum/go-ethereum/common" ) type EthParser struct { @@ -18,8 +17,21 @@ func (p *EthParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) { } func (p *EthParser) GetAddrIDFromAddress(address string) ([]byte, error) { - a := ethcommon.HexToAddress(address) - return a.Bytes(), nil + // github.com/ethereum/go-ethereum/common.HexToAddress does not handle address errors, using own decoding + if len(address) > 1 { + if address[0:2] == "0x" || address[0:2] == "0X" { + address = address[2:] + } + } else { + if len(address) == 0 { + return nil, bchain.ErrAddressMissing + } + return nil, errors.New("Invalid address") + } + if len(address)&1 == 1 { + address = "0" + address + } + return hex.DecodeString(address) } func (p *EthParser) AddressToOutputScript(address string) ([]byte, error) { diff --git a/bchain/coins/eth/ethparser_test.go b/bchain/coins/eth/ethparser_test.go new file mode 100644 index 00000000..15dfb832 --- /dev/null +++ b/bchain/coins/eth/ethparser_test.go @@ -0,0 +1,61 @@ +package eth + +import ( + "encoding/hex" + "reflect" + "testing" +) + +func TestEthParser_GetAddrIDFromAddress(t *testing.T) { + type args struct { + address string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "with 0x prefix", + args: args{address: "0x81b7e08f65bdf5648606c89998a9cc8164397647"}, + want: "81b7e08f65bdf5648606c89998a9cc8164397647", + }, + { + name: "without 0x prefix", + args: args{address: "47526228d673e9f079630d6cdaff5a2ed13e0e60"}, + want: "47526228d673e9f079630d6cdaff5a2ed13e0e60", + }, + { + name: "odd address", + args: args{address: "7526228d673e9f079630d6cdaff5a2ed13e0e60"}, + want: "07526228d673e9f079630d6cdaff5a2ed13e0e60", + }, + { + name: "ErrAddressMissing", + args: args{address: ""}, + want: "", + wantErr: true, + }, + { + name: "error - not eth address", + args: args{address: "1JKgN43B9SyLuZH19H5ECvr4KcfrbVHzZ6"}, + want: "", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &EthParser{} + got, err := p.GetAddrIDFromAddress(tt.args.address) + if (err != nil) != tt.wantErr { + t.Errorf("EthParser.GetAddrIDFromAddress() error = %v, wantErr %v", err, tt.wantErr) + return + } + h := hex.EncodeToString(got) + if !reflect.DeepEqual(h, tt.want) { + t.Errorf("EthParser.GetAddrIDFromAddress() = %v, want %v", h, tt.want) + } + }) + } +} diff --git a/bchain/types.go b/bchain/types.go index 2df1baf7..5fa9712b 100644 --- a/bchain/types.go +++ b/bchain/types.go @@ -11,6 +11,9 @@ var ( // either unknown hash or too high height // can be returned from GetBlockHash, GetBlockHeader, GetBlock ErrBlockNotFound = errors.New("Block not found") + // ErrAddressMissing is returned if address is not specified + // for example To address in ethereum can be missing in case of contract transaction + ErrAddressMissing = errors.New("Address missing") ) type ScriptSig struct { diff --git a/db/rocksdb.go b/db/rocksdb.go index 759f3f6b..ac84e00d 100644 --- a/db/rocksdb.go +++ b/db/rocksdb.go @@ -143,6 +143,9 @@ func (d *RocksDB) GetTransactions(address string, lower uint32, higher uint32, f glog.Infof("rocksdb: address get %s %d-%d ", address, lower, higher) } addrID, err := d.chainParser.GetAddrIDFromAddress(address) + if err != nil { + return err + } kstart, err := packOutputKey(addrID, lower) if err != nil { @@ -283,7 +286,10 @@ func (d *RocksDB) writeOutputs(wb *gorocksdb.WriteBatch, block *bchain.Block, op for _, output := range tx.Vout { addrID, err := d.chainParser.GetAddrIDFromVout(&output) if err != nil { - glog.Warningf("rocksdb: addrID: %v - %d %s", err, block.Height, addrID) + // do not log ErrAddressMissing, transactions can be without to address (for example eth contracts) + if err != bchain.ErrAddressMissing { + glog.Warningf("rocksdb: addrID: %v - height %d, tx %v, output %v", err, block.Height, tx.Txid, output) + } continue } err = d.addAddrIDToRecords(op, wb, records, addrID, tx.Txid, int32(output.N), block.Height)