Handle Bitcoin taproot addresses
This commit is contained in:
parent
dff928456d
commit
ba75e60950
@ -186,7 +186,7 @@ func (p *BitcoinLikeParser) outputScriptToAddresses(script []byte) ([]string, bo
|
||||
rv[i] = a.EncodeAddress()
|
||||
}
|
||||
var s bool
|
||||
if sc == txscript.PubKeyHashTy || sc == txscript.WitnessV0PubKeyHashTy || sc == txscript.ScriptHashTy || sc == txscript.WitnessV0ScriptHashTy {
|
||||
if sc == txscript.PubKeyHashTy || sc == txscript.WitnessV0PubKeyHashTy || sc == txscript.ScriptHashTy || sc == txscript.WitnessV0ScriptHashTy || sc == txscript.WitnessV1TaprootTy {
|
||||
s = true
|
||||
} else if len(rv) == 0 {
|
||||
or := p.TryParseOPReturn(script)
|
||||
@ -345,13 +345,13 @@ func (p *BitcoinLikeParser) DeriveAddressDescriptors(xpub string, change uint32,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changeExtKey, err := extKey.Child(change)
|
||||
changeExtKey, err := extKey.Derive(change)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ad := make([]bchain.AddressDescriptor, len(indexes))
|
||||
for i, index := range indexes {
|
||||
indexExtKey, err := changeExtKey.Child(index)
|
||||
indexExtKey, err := changeExtKey.Derive(index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -372,13 +372,13 @@ func (p *BitcoinLikeParser) DeriveAddressDescriptorsFromTo(xpub string, change u
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changeExtKey, err := extKey.Child(change)
|
||||
changeExtKey, err := extKey.Derive(change)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ad := make([]bchain.AddressDescriptor, toIndex-fromIndex)
|
||||
for index := fromIndex; index < toIndex; index++ {
|
||||
indexExtKey, err := changeExtKey.Child(index)
|
||||
indexExtKey, err := changeExtKey.Derive(index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
//go:build unittest
|
||||
// +build unittest
|
||||
|
||||
package btc
|
||||
@ -59,6 +60,18 @@ func TestGetAddrDescFromAddress(t *testing.T) {
|
||||
want: "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: " witness_unknown v1",
|
||||
args: args{address: "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y"},
|
||||
want: "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: " witness_unknown v16",
|
||||
args: args{address: "bc1sw50qgdz25j"},
|
||||
want: "6002751e",
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
parser := NewBitcoinParser(GetChainParams("main"), &Configuration{})
|
||||
|
||||
@ -77,6 +90,64 @@ func TestGetAddrDescFromAddress(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAddrDescFromAddressTestnet(t *testing.T) {
|
||||
type args struct {
|
||||
address string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "pubkeyhash",
|
||||
args: args{address: "mtkbaiLiUH3fvGJeSzuN3kUgmJzqinLejJ"},
|
||||
want: "76a914912e2b234f941f30b18afbb4fa46171214bf66c888ac",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "scripthash",
|
||||
args: args{address: "2Mv28xcUJdFXBTfGMtja6fVBMCEbsH3r2AW"},
|
||||
want: "a9141e6ec5a1d12912b396d77d98dcb000e91f517fa487",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "witness_v0_keyhash",
|
||||
args: args{address: "tb1qupjdck20as3y4l95cd5wepkv0grcz0p7d8rd5s"},
|
||||
want: "0014e064dc594fec224afcb4c368ec86cc7a07813c3e",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "witness_v0_scripthash",
|
||||
args: args{address: "tb1qqwtn5s8vjnqdzrm0du885c46ypzt05vakmljhasx28shlv5a355seu0fjv"},
|
||||
want: "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "witness_v1_taproot",
|
||||
args: args{address: "tb1pqsv2qyp8hsma46422ecfd3ek02jayumkkzjx7vkf3cqpmfd4ucpsx0cc9h"},
|
||||
want: "51200418a01027bc37daeaaa567096c7367aa5d27376b0a46f32c98e001da5b5e603",
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
parser := NewBitcoinParser(GetChainParams("test"), &Configuration{})
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parser.GetAddrDescFromAddress(tt.args.address)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("GetAddrDescFromAddress() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
h := hex.EncodeToString(got)
|
||||
if !reflect.DeepEqual(h, tt.want) {
|
||||
t.Errorf("GetAddrDescFromAddress() = %v, want %v", h, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAddrDescFromVout(t *testing.T) {
|
||||
type args struct {
|
||||
vout bchain.Vout
|
||||
@ -307,6 +378,95 @@ We know the game and we're gonna play it (TO FRONT)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAddressesFromAddrDescTestnet(t *testing.T) {
|
||||
type args struct {
|
||||
script string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []string
|
||||
want2 bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "pubkeyhash",
|
||||
args: args{script: "76a914912e2b234f941f30b18afbb4fa46171214bf66c888ac"},
|
||||
want: []string{"mtkbaiLiUH3fvGJeSzuN3kUgmJzqinLejJ"},
|
||||
want2: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "pubkey compressed",
|
||||
args: args{script: "2102a741071164b40b01c4ad28913c4aa2a1015cc5b064f0c802272552f17ae08750ac"},
|
||||
want: []string{"mkMe1fsfCWFext2qxf4bk3yiruBTvnici4"},
|
||||
want2: false,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "pubkey uncompressed",
|
||||
args: args{script: "41041057356b91bfd3efeff5fc0fa8b865faafafb67bd653c5da2cd16ce15c7b86db0e622c8e1e135f68918a23601eb49208c1ac72c7b64a4ee99c396cf788da16ccac"},
|
||||
want: []string{"mx43tNdg4JYY29ifrHjJpdbcCqqDGVSng5"},
|
||||
want2: false,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "scripthash",
|
||||
args: args{script: "a9141e6ec5a1d12912b396d77d98dcb000e91f517fa487"},
|
||||
want: []string{"2Mv28xcUJdFXBTfGMtja6fVBMCEbsH3r2AW"},
|
||||
want2: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "witness_v0_keyhash",
|
||||
args: args{script: "0014e064dc594fec224afcb4c368ec86cc7a07813c3e"},
|
||||
want: []string{"tb1qupjdck20as3y4l95cd5wepkv0grcz0p7d8rd5s"},
|
||||
want2: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "witness_v0_scripthash",
|
||||
args: args{script: "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29"},
|
||||
want: []string{"tb1qqwtn5s8vjnqdzrm0du885c46ypzt05vakmljhasx28shlv5a355seu0fjv"},
|
||||
want2: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "witness_v1_taproot",
|
||||
args: args{script: "51200418a01027bc37daeaaa567096c7367aa5d27376b0a46f32c98e001da5b5e603"},
|
||||
want: []string{"tb1pqsv2qyp8hsma46422ecfd3ek02jayumkkzjx7vkf3cqpmfd4ucpsx0cc9h"},
|
||||
want2: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "OP_RETURN ascii",
|
||||
args: args{script: "6a0461686f6a"},
|
||||
want: []string{"OP_RETURN (ahoj)"},
|
||||
want2: false,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
parser := NewBitcoinParser(GetChainParams("test"), &Configuration{})
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
b, _ := hex.DecodeString(tt.args.script)
|
||||
got, got2, err := parser.GetAddressesFromAddrDesc(b)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("TestGetAddressesFromAddrDesc_Testnet() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("TestGetAddressesFromAddrDesc_Testnet() = %v, want %v", got, tt.want)
|
||||
}
|
||||
if !reflect.DeepEqual(got2, tt.want2) {
|
||||
t.Errorf("TestGetAddressesFromAddrDesc_Testnet() = %v, want %v", got2, tt.want2)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
testTx1, testTx2, testTx3 bchain.Tx
|
||||
|
||||
|
||||
@ -678,10 +678,8 @@ func (b *BitcoinRPC) GetMempoolTransactions() ([]string, error) {
|
||||
|
||||
// IsMissingTx return true if error means missing tx
|
||||
func IsMissingTx(err *bchain.RPCError) bool {
|
||||
if err.Code == -5 { // "No such mempool or blockchain transaction"
|
||||
return true
|
||||
}
|
||||
return false
|
||||
// err.Code == -5 "No such mempool or blockchain transaction"
|
||||
return err.Code == -5
|
||||
}
|
||||
|
||||
// GetTransactionForMempool returns a transaction by the transaction ID
|
||||
|
||||
@ -169,13 +169,13 @@ func (p *NulsParser) DeriveAddressDescriptorsFromTo(xpub string, change uint32,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changeExtKey, err := extKey.Child(change)
|
||||
changeExtKey, err := extKey.Derive(change)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ad := make([]bchain.AddressDescriptor, toIndex-fromIndex)
|
||||
for index := fromIndex; index < toIndex; index++ {
|
||||
indexExtKey, err := changeExtKey.Child(index)
|
||||
indexExtKey, err := changeExtKey.Derive(index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
//go:build unittest
|
||||
// +build unittest
|
||||
|
||||
package nuls
|
||||
@ -359,13 +360,13 @@ func TestDeriveAddressDescriptorsFromTo(t *testing.T) {
|
||||
t.Errorf("DeriveAddressDescriptorsFromTo() error = %v", err)
|
||||
return
|
||||
}
|
||||
changeExtKey, err := extKey.Child(0)
|
||||
changeExtKey, err := extKey.Derive(0)
|
||||
if err != nil {
|
||||
t.Errorf("DeriveAddressDescriptorsFromTo() error = %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
key1, _ := changeExtKey.Child(0)
|
||||
key1, _ := changeExtKey.Derive(0)
|
||||
priKey1, _ := key1.ECPrivKey()
|
||||
wantPriKey1 := "0x995c98115809359eb57a5e179558faddd55ef88f88e5cf58617a5f9f3d6bb3a1"
|
||||
if !reflect.DeepEqual(hexutil.MustDecode(wantPriKey1), priKey1.Serialize()) {
|
||||
@ -379,7 +380,7 @@ func TestDeriveAddressDescriptorsFromTo(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
key2, _ := changeExtKey.Child(1)
|
||||
key2, _ := changeExtKey.Derive(1)
|
||||
priKey2, _ := key2.ECPrivKey()
|
||||
wantPriKey2 := "0x0f65dee42d3c974c1a4bcc79f141be89715dc8d6406faa9ad4f1f55ca95fabc8"
|
||||
if !reflect.DeepEqual(hexutil.MustDecode(wantPriKey2), priKey2.Serialize()) {
|
||||
@ -393,7 +394,7 @@ func TestDeriveAddressDescriptorsFromTo(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
key3, _ := changeExtKey.Child(2)
|
||||
key3, _ := changeExtKey.Derive(2)
|
||||
priKey3, _ := key3.ECPrivKey()
|
||||
wantPriKey3 := "0x6fd98d1d9c3f3ac1ff61bbf3f20e89f00ffa8d43a554f2a7d73fd464b6666f45"
|
||||
if !reflect.DeepEqual(hexutil.MustDecode(wantPriKey3), priKey3.Serialize()) {
|
||||
@ -407,7 +408,7 @@ func TestDeriveAddressDescriptorsFromTo(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
key4, _ := changeExtKey.Child(3)
|
||||
key4, _ := changeExtKey.Derive(3)
|
||||
priKey4, _ := key4.ECPrivKey()
|
||||
wantPriKey4 := "0x21412d9e33aba493faf4bc7d408ed5290bea5b36a7beec554b858051f8d4bff3"
|
||||
if !reflect.DeepEqual(hexutil.MustDecode(wantPriKey4), priKey4.Serialize()) {
|
||||
@ -421,7 +422,7 @@ func TestDeriveAddressDescriptorsFromTo(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
key5, _ := changeExtKey.Child(4)
|
||||
key5, _ := changeExtKey.Derive(4)
|
||||
priKey5, _ := key5.ECPrivKey()
|
||||
wantPriKey5 := "0xdc3d290e32a4e0f38bc26c25a78ceb1c8779110883d9cb0be54629043c1f8724"
|
||||
if !reflect.DeepEqual(hexutil.MustDecode(wantPriKey5), priKey5.Serialize()) {
|
||||
|
||||
2
go.mod
2
go.mod
@ -29,7 +29,7 @@ require (
|
||||
github.com/juju/testing v0.0.0-20191001232224-ce9dec17d28b // indirect
|
||||
github.com/martinboehm/bchutil v0.0.0-20190104112650-6373f11b6efe
|
||||
github.com/martinboehm/btcd v0.0.0-20200313230603-83af86142d93
|
||||
github.com/martinboehm/btcutil v0.0.0-20200229134221-d7706467ae8f
|
||||
github.com/martinboehm/btcutil v0.0.0-20210922221517-e83b0c752949
|
||||
github.com/martinboehm/golang-socketio v0.0.0-20180414165752-f60b0a8befde
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
|
||||
10
go.sum
10
go.sum
@ -378,6 +378,7 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/kkdai/bstream v0.0.0-20171226095907-f71540b9dfdc/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=
|
||||
@ -401,11 +402,16 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/martinboehm/bchutil v0.0.0-20190104112650-6373f11b6efe h1:khZWpHuxJNh2EGzBbaS6EQ2d6KxgK31WeG0TnlTMUD4=
|
||||
github.com/martinboehm/bchutil v0.0.0-20190104112650-6373f11b6efe/go.mod h1:0hw4tpGU+9slqN/DrevhjTMb0iR9esxzpCdx8I6/UzU=
|
||||
github.com/martinboehm/btcd v0.0.0-20190104121910-8e7c0427fee5/go.mod h1:rKQj/jGwFruYjpM6vN+syReFoR0DsLQaajhyH/5mwUE=
|
||||
github.com/martinboehm/btcd v0.0.0-20200313230603-83af86142d93 h1:SBXxF9UMEPAswVhAt3Y275Lx59Do8C/rpAmg6k73HYY=
|
||||
github.com/martinboehm/btcd v0.0.0-20200313230603-83af86142d93/go.mod h1:rKQj/jGwFruYjpM6vN+syReFoR0DsLQaajhyH/5mwUE=
|
||||
github.com/martinboehm/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:NIviPmxe43yBgIB4HGB4w4kv9/s5kaDa/pi+wZAAxQo=
|
||||
github.com/martinboehm/btcutil v0.0.0-20200229134221-d7706467ae8f h1:MMI9XvVjNHkqQDDyud0Ll0qd/w4jAhgkLZMY8q6KbR8=
|
||||
github.com/martinboehm/btcutil v0.0.0-20200229134221-d7706467ae8f/go.mod h1:NIviPmxe43yBgIB4HGB4w4kv9/s5kaDa/pi+wZAAxQo=
|
||||
github.com/martinboehm/btcutil v0.0.0-20210914231321-8ece5dcd9f5f h1:zDEDlafs4y1CjDqcowXFzcttj/wt6N2wV9U2NihjgcU=
|
||||
github.com/martinboehm/btcutil v0.0.0-20210914231321-8ece5dcd9f5f/go.mod h1:8iJaVY/VHW6lnojpTXf5X4gF2dx81Xtj2R6lJp2colA=
|
||||
github.com/martinboehm/btcutil v0.0.0-20210922133746-0042eb304b5b h1:xm/0cKQ6PffWGXfPyfanJaZ7skZo/6uT6pb+mtVEU1o=
|
||||
github.com/martinboehm/btcutil v0.0.0-20210922133746-0042eb304b5b/go.mod h1:8iJaVY/VHW6lnojpTXf5X4gF2dx81Xtj2R6lJp2colA=
|
||||
github.com/martinboehm/btcutil v0.0.0-20210922221517-e83b0c752949 h1:GdmOPmno0QNl9jVMJZOTj7ekgGA9zRG6gn1X9jutrkU=
|
||||
github.com/martinboehm/btcutil v0.0.0-20210922221517-e83b0c752949/go.mod h1:8iJaVY/VHW6lnojpTXf5X4gF2dx81Xtj2R6lJp2colA=
|
||||
github.com/martinboehm/golang-socketio v0.0.0-20180414165752-f60b0a8befde h1:Tz7WkXgQjeQVymqSQkEapbe/ZuzKCvb6GANFHnl0uAE=
|
||||
github.com/martinboehm/golang-socketio v0.0.0-20180414165752-f60b0a8befde/go.mod h1:p35TWcm7GkAwvPcUCEq4H+yTm0gA8Aq7UvGnbK6olQk=
|
||||
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
||||
|
||||
Loading…
Reference in New Issue
Block a user