diff --git a/Gopkg.lock b/Gopkg.lock index eeff3942..24370914 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -89,7 +89,7 @@ branch = "master" name = "github.com/jakm/btcutil" packages = [".","base58","bech32","chaincfg","txscript"] - revision = "90ef4c720a6c3b3f9974dd6a6c6c339906236c35" + revision = "83dfbb3d0b20916f89b36b95c6ca580e3a785856" [[projects]] branch = "master" diff --git a/bchain/coins/bch/bcashparser.go b/bchain/coins/bch/bcashparser.go index 033af920..83411081 100644 --- a/bchain/coins/bch/bcashparser.go +++ b/bchain/coins/bch/bcashparser.go @@ -150,29 +150,22 @@ func isCashAddr(addr string) bool { // outputScriptToAddresses converts ScriptPubKey to bitcoin addresses func (p *BCashParser) outputScriptToAddresses(script []byte) ([]string, bool, error) { + // convert possible P2PK script to P2PK, which bchutil can process + var err error + script, err = txscript.ConvertP2PKtoP2PKH(script) + if err != nil { + return nil, false, err + } 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 bitcoin parser to parse P2PK scripts - kind of hack as bchutil does not support pay-to-pubkey - _, addresses, _, err := txscript.ExtractPkScriptAddrs(script, p.Params) - if err == nil && len(addresses) == 1 { - // convert the address back to output script and back to get from bitcoin to bcash - s, err := p.addressToOutputScript(addresses[0].EncodeAddress()) - if err == nil { - a, err = bchutil.ExtractPkScriptAddrs(s, p.Params) - if err != nil { - return []string{}, false, nil - } - } - } else { - // try OP_RETURN script - or := btc.TryParseOPReturn(script) - if or != "" { - return []string{or}, false, nil - } - return []string{}, false, nil + // try OP_RETURN script + or := btc.TryParseOPReturn(script) + if or != "" { + return []string{or}, false, nil } + return []string{}, false, nil } else { return nil, false, err } diff --git a/bchain/coins/btc/bitcoinparser.go b/bchain/coins/btc/bitcoinparser.go index e148440a..38084c6b 100644 --- a/bchain/coins/btc/bitcoinparser.go +++ b/bchain/coins/btc/bitcoinparser.go @@ -56,7 +56,13 @@ func GetChainParams(chain string) *chaincfg.Params { // GetAddrDescFromVout returns internal address representation (descriptor) of given transaction output func (p *BitcoinParser) GetAddrDescFromVout(output *bchain.Vout) (bchain.AddressDescriptor, error) { - return hex.DecodeString(output.ScriptPubKey.Hex) + ad, err := hex.DecodeString(output.ScriptPubKey.Hex) + if err != nil { + return ad, err + } + // convert possible P2PK script to P2PKH + // so that all transactions by given public key are indexed together + return txscript.ConvertP2PKtoP2PKH(ad) } // GetAddrDescFromAddress returns internal address representation (descriptor) of given address diff --git a/bchain/coins/btc/bitcoinparser_test.go b/bchain/coins/btc/bitcoinparser_test.go index eef8b02c..d1fc4940 100644 --- a/bchain/coins/btc/bitcoinparser_test.go +++ b/bchain/coins/btc/bitcoinparser_test.go @@ -35,6 +35,12 @@ func Test_GetAddrDescFromAddress(t *testing.T) { want: "76a914be027bf3eac907bd4ac8cb9c5293b6f37662722088ac", wantErr: false, }, + { + name: "P2PKH from P2PK", + args: args{address: "1HY6bKYhFH7HF3F48ikvziPHLrEWPGwXcE"}, + want: "76a914b563933904dceba5c234e978bea0e9eb8b7e721b88ac", + wantErr: false, + }, { name: "P2SH", args: args{address: "321x69Cb9HZLWwAWGiUBT1U81r1zPLnEjL"}, @@ -71,6 +77,70 @@ func Test_GetAddrDescFromAddress(t *testing.T) { } } +func Test_GetAddrDescFromVout(t *testing.T) { + type args struct { + vout bchain.Vout + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "P2PKH", + args: args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "76a914be027bf3eac907bd4ac8cb9c5293b6f37662722088ac"}}}, + want: "76a914be027bf3eac907bd4ac8cb9c5293b6f37662722088ac", + wantErr: false, + }, + { + name: "P2PK compressed 1P3rU1Nk1pmc2BiWC8dEy9bZa1ZbMp5jfg", + args: args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "21020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9ac"}}}, + want: "76a914f1dce4182fce875748c4986b240ff7d7bc3fffb088ac", + wantErr: false, + }, + { + name: "P2PK uncompressed 1HY6bKYhFH7HF3F48ikvziPHLrEWPGwXcE", + args: args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "41041057356b91bfd3efeff5fc0fa8b865faafafb67bd653c5da2cd16ce15c7b86db0e622c8e1e135f68918a23601eb49208c1ac72c7b64a4ee99c396cf788da16ccac"}}}, + want: "76a914b563933904dceba5c234e978bea0e9eb8b7e721b88ac", + wantErr: false, + }, + { + name: "P2SH", + args: args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "a9140394b3cf9a44782c10105b93962daa8dba304d7f87"}}}, + want: "a9140394b3cf9a44782c10105b93962daa8dba304d7f87", + wantErr: false, + }, + { + name: "P2WPKH", + args: args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "00141c12afc6b2602607fdbc209f2a053c54ecd2c673"}}}, + want: "00141c12afc6b2602607fdbc209f2a053c54ecd2c673", + wantErr: false, + }, + { + name: "P2WSH", + args: args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29"}}}, + want: "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29", + wantErr: false, + }, + } + parser := NewBitcoinParser(GetChainParams("main"), &Configuration{}) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parser.GetAddrDescFromVout(&tt.args.vout) + if (err != nil) != tt.wantErr { + t.Errorf("GetAddrDescFromVout() error = %v, wantErr %v", err, tt.wantErr) + return + } + h := hex.EncodeToString(got) + if !reflect.DeepEqual(h, tt.want) { + t.Errorf("GetAddrDescFromVout() = %v, want %v", h, tt.want) + } + }) + } +} + func Test_GetAddressesFromAddrDesc(t *testing.T) { type args struct { script string @@ -89,6 +159,20 @@ func Test_GetAddressesFromAddrDesc(t *testing.T) { want2: true, wantErr: false, }, + { + name: "P2PK compressed", + args: args{script: "21020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9ac"}, + want: []string{"1P3rU1Nk1pmc2BiWC8dEy9bZa1ZbMp5jfg"}, + want2: false, + wantErr: false, + }, + { + name: "P2PK uncompressed", + args: args{script: "41041057356b91bfd3efeff5fc0fa8b865faafafb67bd653c5da2cd16ce15c7b86db0e622c8e1e135f68918a23601eb49208c1ac72c7b64a4ee99c396cf788da16ccac"}, + want: []string{"1HY6bKYhFH7HF3F48ikvziPHLrEWPGwXcE"}, + want2: false, + wantErr: false, + }, { name: "P2SH", args: args{script: "a9140394b3cf9a44782c10105b93962daa8dba304d7f87"},