diff --git a/api/worker.go b/api/worker.go index 695f9747..05a9aca9 100644 --- a/api/worker.go +++ b/api/worker.go @@ -223,7 +223,7 @@ func (w *Worker) txFromTxAddress(txid string, ta *db.TxAddresses, bi *db.BlockIn valInSat.Add(&valInSat, &vin.ValueSat) vin.Addresses, vin.Searchable, err = tai.Addresses(w.chainParser) if err != nil { - glog.Errorf("tai.Addresses error %v, tx %v, input %v", err, txid, i) + glog.Errorf("tai.Addresses error %v, tx %v, input %v, tai %+v", err, txid, i, tai) } } vouts := make([]Vout, len(ta.Outputs)) @@ -236,7 +236,7 @@ func (w *Worker) txFromTxAddress(txid string, ta *db.TxAddresses, bi *db.BlockIn valOutSat.Add(&valOutSat, &vout.ValueSat) vout.ScriptPubKey.Addresses, vout.ScriptPubKey.Searchable, err = tao.Addresses(w.chainParser) if err != nil { - glog.Errorf("tai.Addresses error %v, tx %v, output %v", err, txid, i) + glog.Errorf("tai.Addresses error %v, tx %v, output %v, tao %+v", err, txid, i, tao) } } // for coinbase transactions valIn is 0 diff --git a/bchain/coins/bch/bcashparser.go b/bchain/coins/bch/bcashparser.go index 62f4c6b2..428e80b4 100644 --- a/bchain/coins/bch/bcashparser.go +++ b/bchain/coins/bch/bcashparser.go @@ -126,6 +126,15 @@ func isCashAddr(addr string) bool { func (p *BCashParser) outputScriptToAddresses(script []byte) ([]string, bool, error) { a, err := bchutil.ExtractPkScriptAddrs(script, p.Params) if err != nil { + // do not return unknown script type error as error + if err.Error() == "unknown script type" { + // try OP_RETURN script + or := btc.TryParseOPReturn(script) + if or != "" { + return []string{or}, false, nil + } + return []string{}, false, nil + } return nil, false, err } // EncodeAddress returns CashAddr address diff --git a/bchain/coins/bch/bcashparser_test.go b/bchain/coins/bch/bcashparser_test.go index 4b3a0e68..7d98cea6 100644 --- a/bchain/coins/bch/bcashparser_test.go +++ b/bchain/coins/bch/bcashparser_test.go @@ -82,53 +82,85 @@ func Test_GetAddrDescFromAddress(t *testing.T) { func Test_GetAddressesFromAddrDesc(t *testing.T) { mainParserCashAddr, mainParserLegacy, testParserCashAddr, testParserLegacy := setupParsers(t) tests := []struct { - name string - parser *BCashParser - addresses []string - hex string - wantErr bool + name string + parser *BCashParser + addresses []string + searchable bool + hex string + wantErr bool }{ { - name: "test-P2PKH-0", - parser: testParserLegacy, - addresses: []string{"mnnAKPTSrWjgoi3uEYaQkHA1QEC5btFeBr"}, - hex: "76a9144fa927fd3bcf57d4e3c582c3d2eb2bd3df8df47c88ac", - wantErr: false, + name: "test-P2PKH-0", + parser: testParserLegacy, + addresses: []string{"mnnAKPTSrWjgoi3uEYaQkHA1QEC5btFeBr"}, + searchable: true, + hex: "76a9144fa927fd3bcf57d4e3c582c3d2eb2bd3df8df47c88ac", + + wantErr: false, }, { - name: "test-P2PKH-1", - parser: testParserCashAddr, - addresses: []string{"bchtest:qp86jfla8084048rckpv85ht90falr050s03ejaesm"}, - hex: "76a9144fa927fd3bcf57d4e3c582c3d2eb2bd3df8df47c88ac", - wantErr: false, + name: "test-P2PKH-1", + parser: testParserCashAddr, + addresses: []string{"bchtest:qp86jfla8084048rckpv85ht90falr050s03ejaesm"}, + searchable: true, + hex: "76a9144fa927fd3bcf57d4e3c582c3d2eb2bd3df8df47c88ac", + wantErr: false, }, { - name: "main-P2PKH-0", - parser: mainParserLegacy, - addresses: []string{"129HiRqekqPVucKy2M8zsqvafGgKypciPp"}, - hex: "76a9140c8967e6382c7a2ca64d8e850bfc99b7736e1a0d88ac", - wantErr: false, + name: "main-P2PKH-0", + parser: mainParserLegacy, + addresses: []string{"129HiRqekqPVucKy2M8zsqvafGgKypciPp"}, + searchable: true, + hex: "76a9140c8967e6382c7a2ca64d8e850bfc99b7736e1a0d88ac", + wantErr: false, }, { - name: "main-P2PKH-0", - parser: mainParserCashAddr, - addresses: []string{"bitcoincash:qqxgjelx8qk85t9xfk8g2zlunxmhxms6p55xarv2r5"}, - hex: "76a9140c8967e6382c7a2ca64d8e850bfc99b7736e1a0d88ac", - wantErr: false, + name: "main-P2PKH-0", + parser: mainParserCashAddr, + addresses: []string{"bitcoincash:qqxgjelx8qk85t9xfk8g2zlunxmhxms6p55xarv2r5"}, + searchable: true, + hex: "76a9140c8967e6382c7a2ca64d8e850bfc99b7736e1a0d88ac", + wantErr: false, }, { - name: "main-P2SH-0", - parser: mainParserLegacy, - addresses: []string{"3EBEFWPtDYWCNszQ7etoqtWmmygccayLiH"}, - hex: "a91488f772450c830a30eddfdc08a93d5f2ae1a30e1787", - wantErr: false, + name: "main-P2SH-0", + parser: mainParserLegacy, + addresses: []string{"3EBEFWPtDYWCNszQ7etoqtWmmygccayLiH"}, + searchable: true, + hex: "a91488f772450c830a30eddfdc08a93d5f2ae1a30e1787", + wantErr: false, }, { - name: "main-P2SH-1", - parser: mainParserCashAddr, - addresses: []string{"bitcoincash:pzy0wuj9pjps5v8dmlwq32fatu4wrgcwzuayq5nfhh"}, - hex: "a91488f772450c830a30eddfdc08a93d5f2ae1a30e1787", - wantErr: false, + name: "main-P2SH-1", + parser: mainParserCashAddr, + addresses: []string{"bitcoincash:pzy0wuj9pjps5v8dmlwq32fatu4wrgcwzuayq5nfhh"}, + searchable: true, + hex: "a91488f772450c830a30eddfdc08a93d5f2ae1a30e1787", + wantErr: false, + }, + { + name: "OP_RETURN ascii", + parser: mainParserCashAddr, + addresses: []string{"OP_RETURN (ahoj)"}, + searchable: false, + hex: "6a0461686f6a", + wantErr: false, + }, + { + name: "OP_RETURN hex", + parser: mainParserCashAddr, + addresses: []string{"OP_RETURN 07 2020f1686f6a20"}, + searchable: false, + hex: "6a072020f1686f6a20", + wantErr: false, + }, + { + name: "empty", + parser: mainParserCashAddr, + addresses: []string{}, + searchable: false, + hex: "", + wantErr: false, }, } @@ -143,8 +175,8 @@ func Test_GetAddressesFromAddrDesc(t *testing.T) { if !reflect.DeepEqual(got, tt.addresses) { t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got, tt.addresses) } - if !reflect.DeepEqual(got2, true) { - t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got2, true) + if !reflect.DeepEqual(got2, tt.searchable) { + t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got2, tt.searchable) } }) } diff --git a/bchain/coins/btc/bitcoinparser.go b/bchain/coins/btc/bitcoinparser.go index a4745be0..d995a735 100644 --- a/bchain/coins/btc/bitcoinparser.go +++ b/bchain/coins/btc/bitcoinparser.go @@ -84,6 +84,31 @@ func (p *BitcoinParser) addressToOutputScript(address string) ([]byte, error) { return script, nil } +// TryParseOPReturn tries to process OP_RETURN script and return its string representation +func TryParseOPReturn(script []byte) string { + if len(script) > 1 && script[0] == txscript.OP_RETURN { + l := int(script[1]) + data := script[2:] + if l == len(data) { + isASCII := true + for _, c := range data { + if c < 32 || c > 127 { + isASCII = false + break + } + } + var ed string + if isASCII { + ed = "(" + string(data) + ")" + } else { + ed = hex.EncodeToString([]byte{byte(l)}) + " " + hex.EncodeToString(data) + } + return "OP_RETURN " + ed + } + } + return "" +} + // outputScriptToAddresses converts ScriptPubKey to bitcoin addresses func (p *BitcoinParser) outputScriptToAddresses(script []byte) ([]string, bool, error) { sc, addresses, _, err := txscript.ExtractPkScriptAddrs(script, p.Params) @@ -97,26 +122,10 @@ func (p *BitcoinParser) outputScriptToAddresses(script []byte) ([]string, bool, var s bool if sc != txscript.NonStandardTy && sc != txscript.NullDataTy { s = true - } else { - if len(script) > 1 && script[0] == txscript.OP_RETURN && len(rv) == 0 { - l := int(script[1]) - data := script[2:] - if l == len(data) { - isASCII := true - for _, c := range data { - if c < 32 || c > 127 { - isASCII = false - break - } - } - var ed string - if isASCII { - ed = "(" + string(data) + ")" - } else { - ed = hex.EncodeToString([]byte{byte(l)}) + " " + hex.EncodeToString(data) - } - rv = []string{"OP_RETURN " + ed} - } + } else if len(rv) == 0 { + or := TryParseOPReturn(script) + if or != "" { + rv = []string{or} } } return rv, s, nil