Skip to content

Commit

Permalink
Taproot support (#198)
Browse files Browse the repository at this point in the history
* update with new btcsuite

* taproot pkg

* taproot_test from txscript

* blech32m (blech32 pkg)

* update blech32

* payment and sighash

* improve address pkg support + testing (payment_test)

* witnessHashV1

* bech32m encode segwitv1 addr

* witnessHashV1 input/output type

* taproot integration testing

* add new elements opcodes

* go mod tidy

* cleaning go.mod

* taproot address test cases

* fix FromConfidential for taproot addresses

* handle panics in p2tr + add failing test cases

* import witnesshash v1 fixtures and fix sighash

* improve serialize functions

* comments and cleaning

* compute script in P2TR payments

* use btcd 0.23.1

* go 1.17 in CI

* add go clean

* Revert "add go clean"

This reverts commit ab56c36.

* mutate pset_test.go

* skip TestBroadcastBlindedSwapTx

* Revert "skip TestBroadcastBlindedSwapTx"

This reverts commit 411d466.

* go.mod upgrade

* use btcec/v2 v2.1.3

* delete travis.yml

* checkout v3

* add fetch-depth: 0

* go mod tidy in CI

* bump btcec

* go cache clean

* bump

* ci: pass ref

Co-authored-by: tiero <3596602+tiero@users.noreply.github.com>
  • Loading branch information
louisinger and tiero authored Jun 15, 2022
1 parent 0b18541 commit 64080b6
Show file tree
Hide file tree
Showing 40 changed files with 2,655 additions and 236 deletions.
19 changes: 13 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,27 @@ jobs:
name: Integration Tests
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.14.x
- name: Set up Go 1.17.x
uses: actions/setup-go@v2
with:
go-version: ^1.14
go-version: ^1.17
id: go

- name: Check out code into the Go module directory
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0
# Check out pull request's HEAD commit instead of the merge commit to
# work-around an issue where wrong a commit is being checked out.
# For more details, see:
# https://github.com/actions/checkout/issues/299.
ref: ${{ github.event.pull_request.head.sha }}

- name: Run Nigiri
uses: vulpemventures/nigiri-github-action@v1

- name: Get dependencies
run: go get -v -t -d ./...

- name: Run Nigiri
uses: vulpemventures/nigiri-github-action@v1

- name: Test
run: make test
23 changes: 0 additions & 23 deletions .travis.yml

This file was deleted.

108 changes: 81 additions & 27 deletions address/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"fmt"
"strings"

"github.com/btcsuite/btcd/btcutil/base58"
"github.com/btcsuite/btcd/btcutil/bech32"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcutil/base58"
"github.com/btcsuite/btcutil/bech32"
"github.com/vulpemventures/go-elements/blech32"
"github.com/vulpemventures/go-elements/network"
"golang.org/x/crypto/ripemd160"
Expand All @@ -28,12 +28,15 @@ const (
P2Wsh
ConfidentialP2Wpkh
ConfidentialP2Wsh
P2TR
ConfidentialP2TR

P2PkhScript = 1
P2ShScript = 2
P2MultiSigScript = 3
P2WpkhScript = 4
P2WshScript = 5
P2TRScript = 6
)

// Base58 type defines the structure of a legacy or wrapped segwit address
Expand Down Expand Up @@ -161,9 +164,22 @@ func ToBech32(bc *Bech32) (string, error) {
combined := make([]byte, len(converted)+1)
combined[0] = bc.Version
copy(combined[1:], converted)
bech, err := bech32.Encode(bc.Prefix, combined)
if err != nil {
return "", err

var bech string

switch bc.Version {
case 0:
bech, err = bech32.Encode(bc.Prefix, combined)
if err != nil {
return "", err
}
case 1:
bech, err = bech32.EncodeM(bc.Prefix, combined)
if err != nil {
return "", err
}
default:
return "", errors.New("unsupported witness version")
}

return bech, nil
Expand Down Expand Up @@ -283,7 +299,12 @@ func ToBlech32(bl *Blech32) (string, error) {
combined := make([]byte, len(converted)+1)
combined[0] = bl.Version
copy(combined[1:], converted)
blech32Addr, err := blech32.Encode(bl.Prefix, combined)
enc, err := blech32.EncodingTypeFromSegwitVersion(bl.Version)
if err != nil {
return "", err
}

blech32Addr, err := blech32.Encode(bl.Prefix, combined, enc)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -330,7 +351,7 @@ func FromConfidential(address string) (*ConfidentialAddress, error) {
Address: addr,
BlindingKey: fromBase58.PublicKey,
}, nil
case ConfidentialP2Wpkh, ConfidentialP2Wsh:
case ConfidentialP2Wpkh, ConfidentialP2Wsh, ConfidentialP2TR:
fromBlech32, err := FromBlech32(address)
if err != nil {
return nil, err
Expand Down Expand Up @@ -482,22 +503,34 @@ func ToOutputScript(address string) ([]byte, error) {
AddData(scriptHash).
AddOp(txscript.OP_EQUAL).
Script()
case P2Wpkh, P2Wsh:
case P2Wpkh, P2Wsh, P2TR:
fromBech32, err := FromBech32(address)
if err != nil {
return nil, err
}

versionOpcode := byte(txscript.OP_0)
if fromBech32.Version == 1 {
versionOpcode = txscript.OP_1
}

return txscript.NewScriptBuilder().
AddOp(txscript.OP_0).
AddOp(versionOpcode).
AddData(fromBech32.Program).
Script()
case ConfidentialP2Wpkh, ConfidentialP2Wsh:
case ConfidentialP2Wpkh, ConfidentialP2Wsh, ConfidentialP2TR:
fromBlech32, err := FromBlech32(address)
if err != nil {
return nil, err
}

versionOpcode := byte(txscript.OP_0)
if fromBlech32.Version == 1 {
versionOpcode = txscript.OP_1
}

return txscript.NewScriptBuilder().
AddOp(txscript.OP_0).
AddOp(versionOpcode).
AddData(fromBlech32.Program).
Script()
default:
Expand All @@ -508,11 +541,13 @@ func ToOutputScript(address string) ([]byte, error) {
// GetScriptType returns the type of the given script (p2pkh, p2sh, etc.)
func GetScriptType(script []byte) int {
switch script[0] {
case txscript.OP_0:
case txscript.OP_0: // segwit v0
if len(script[2:]) == 20 {
return P2WpkhScript
}
return P2WshScript
case txscript.OP_1: // segwit v1 (taproot)
return P2TRScript
case txscript.OP_HASH160:
return P2ShScript
case txscript.OP_DUP:
Expand Down Expand Up @@ -548,7 +583,8 @@ func IsConfidential(address string) (bool, error) {
isConfidential := (addressType == ConfidentialP2Pkh ||
addressType == ConfidentialP2Sh ||
addressType == ConfidentialP2Wpkh ||
addressType == ConfidentialP2Wsh)
addressType == ConfidentialP2Wsh ||
addressType == ConfidentialP2TR)

return isConfidential, nil
}
Expand All @@ -562,14 +598,23 @@ func decodeBlech32(address string, net network.Network) (int, error) {
if err != nil {
return 0, err
}
switch len(fromBlech32.Program) {
case 20:
return ConfidentialP2Wpkh, nil
case 32:
return ConfidentialP2Wsh, nil
default:
return 0, errors.New("invalid program Length")

if fromBlech32.Version == 0 {
switch len(fromBlech32.Program) {
case 20:
return ConfidentialP2Wpkh, nil
case 32:
return ConfidentialP2Wsh, nil
default:
return 0, errors.New("invalid program Length")
}
}

if fromBlech32.Version == 1 {
return ConfidentialP2TR, nil
}

return 0, errors.New("invalid segwit version")
}

func isBech32(address string, net network.Network) bool {
Expand All @@ -581,14 +626,23 @@ func decodeBech32(address string, net network.Network) (int, error) {
if err != nil {
return 0, err
}
switch len(fromBech32.Program) {
case 20:
return P2Wpkh, nil
case 32:
return P2Wsh, nil
default:
return 0, errors.New("invalid program Length")

if fromBech32.Version == 0 {
switch len(fromBech32.Program) {
case 20:
return P2Wpkh, nil
case 32:
return P2Wsh, nil
default:
return 0, errors.New("invalid program Length")
}
}

if fromBech32.Version == 1 {
return P2TR, nil
}

return 0, errors.New("invalid segwit version")
}

func decodeBase58(address string, net network.Network) (int, error) {
Expand Down
9 changes: 9 additions & 0 deletions address/address_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ func TestConfidential(t *testing.T) {
"AzppxC5RDs8yB8mabhwS13y4WbsWoS41fLV8GKM4woLUJB5RxNBVfK6wdVX4QVoubRXFKKfbPhEKKTKc",
"el1qqw3e3mk4ng3ks43mh54udznuekaadh9lgwef3mwgzrfzakmdwcvqpe4ppdaa3t44v3zv2u6w56pv6tc666fvgzaclqjnkz0sd",
"el1qqw3e3mk4ng3ks43mh54udznuekaadh9lgwef3mwgzrfzakmdwcvqqve2xzutyaf7vjcap67f28q90uxec2ve95g3rpu5crapcmfr2l9xl5jzazvcpysz",
"el1pqganzlzf78m05czqv9he0pl9gyryvvqxnr6fdk8rj9u40arvcepvanayxug6fkddlywsp2lgh4e9ypyucu8nhlf5tf8lwqypanv8qwjtr8cgsld44ygt",
}

for _, addr := range addresses {
Expand Down Expand Up @@ -135,6 +136,14 @@ func TestDecodeAddressType(t *testing.T) {
address: "lq1qq2akvug2el2rg6lt6aewh9rzy7dglf9ajdmrkknnwwl3jwxgfkh985x3lrzmrq2mc3c6aa85wgxxfm9v8r062qwq4ty579p54pn2q2hqnhgwv394ycf8",
expectedType: ConfidentialP2Wsh,
},
{
address: "el1pqgm2ru230fmqsw9j9q99992rgh7mresgaegyf79predtczelp0nt7e64ytjvjzt8lraeva72tw6gs6snfr2643hlxpgrmcfl96nmhep072dde867cx4u",
expectedType: ConfidentialP2TR,
},
{
address: "ert1pe7jrwydymxklj8gq405t6ujjqjwvwreml5695nlhqzq7ekrs8f9sclaudg",
expectedType: P2TR,
},
}

for _, tt := range tests {
Expand Down
50 changes: 49 additions & 1 deletion address/opcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,52 @@ package address

import "github.com/btcsuite/btcd/txscript"

// elements tapscript opcodes
const (
OP_SHA256INITIALIZE = 0xc4
OP_SHA256UPDATE = 0xc5
OP_SHA256FINALIZE = 0xc6

// Introspection opcodes
// inputs
OP_INSPECTINPUTOUTPOINT = 0xc7
OP_INSPECTINPUTASSET = 0xc8
OP_INSPECTINPUTVALUE = 0xc9
OP_INSPECTINPUTSCRIPTPUBKEY = 0xca
OP_INSPECTINPUTSEQUENCE = 0xcb
OP_INSPECTINPUTISSUANCE = 0xcc
OP_PUSHCURRENTINPUTINDEX = 0xcd

// outputs
OP_INSPECTOUTPUTASSET = 0xce
OP_INSPECTOUTPUTVALUE = 0xcf
OP_INSPECTOUTPUTNONCE = 0xd0
OP_INSPECTOUTPUTSCRIPTPUBKEY = 0xd1

// transaction
OP_INSPECTVERSION = 0xd2
OP_INSPECTLOCKTIME = 0xd3
OP_INSPECTNUMINPUTS = 0xd4
OP_INSPECTNUMOUTPUTS = 0xd5
OP_TXWEIGHT = 0xd6

// Arithmetic opcodes
OP_ADD64 = 0xd7
OP_SUB64 = 0xd8
OP_MUL64 = 0xd9
OP_DIV64 = 0xda
OP_NEG64 = 0xdb
OP_LESSTHAN64 = 0xdc
OP_LESSTHANOREQUAL64 = 0xdd
OP_GREATERTHAN64 = 0xde
OP_GREATERTHANOREQUAL64 = 0xdf

// Conversion opcodes
OP_SCRIPTNUMTOLE64 = 0xe0
OP_LE64TOSCRIPTNUM = 0xe1
OP_LE32TOLE64 = 0xe2
)

// opcodeArray holds details about all possible opcodes such as how many bytes
// the Opcode and any associated Data should take, its human-readable Name, and
// the handler function.
Expand Down Expand Up @@ -209,8 +255,10 @@ var opcodeArray = [256]Opcode{
txscript.OP_NOP9: {txscript.OP_NOP9, "OP_NOP9", 1},
txscript.OP_NOP10: {txscript.OP_NOP10, "OP_NOP10", 1},

// taproot update
txscript.OP_CHECKSIGADD: {txscript.OP_CHECKSIGADD, "OP_CHECKSIGADD", 1},

// Undefined opcodes.
txscript.OP_UNKNOWN186: {txscript.OP_UNKNOWN186, "OP_UNKNOWN186", 1},
txscript.OP_UNKNOWN187: {txscript.OP_UNKNOWN187, "OP_UNKNOWN187", 1},
txscript.OP_UNKNOWN188: {txscript.OP_UNKNOWN188, "OP_UNKNOWN188", 1},
txscript.OP_UNKNOWN189: {txscript.OP_UNKNOWN189, "OP_UNKNOWN189", 1},
Expand Down
Loading

0 comments on commit 64080b6

Please sign in to comment.