mirror of
https://github.com/aljazceru/ark.git
synced 2026-01-27 07:14:21 +01:00
New boarding protocol (#279)
* [domain] add reverse boarding inputs in Payment struct * [tx-builder] support reverse boarding script * [wallet] add GetTransaction * [api-spec][application] add reverse boarding support in covenantless * [config] add reverse boarding config * [api-spec] add ReverseBoardingAddress RPC * [domain][application] support empty forfeits txs in EndFinalization events * [tx-builder] optional connector output in round tx * [btc-embedded] fix getTx and taproot finalizer * whitelist ReverseBoardingAddress RPC * [test] add reverse boarding integration test * [client] support reverse boarding * [sdk] support reverse boarding * [e2e] add sleep time after faucet * [test] run using bitcoin-core RPC * [tx-builder] fix GetSweepInput * [application][tx-builder] support reverse onboarding in covenant * [cli] support reverse onboarding in covenant CLI * [test] rework integration tests * [sdk] remove onchain wallet, replace by onboarding address * remove old onboarding protocols * [sdk] Fix RegisterPayment * [e2e] add more funds to covenant ASP * [e2e] add sleeping time * several fixes * descriptor boarding * remove boarding delay from info * [sdk] implement descriptor boarding * go mod tidy * fixes and revert error msgs * move descriptor pkg to common * add replace in go.mod * [sdk] fix unit tests * rename DescriptorInput --> BoardingInput * genrest in SDK * remove boarding input from domain * remove all "reverse boarding" * rename "onboarding" ==> "boarding" * remove outdate payment unit test * use tmpfs docker volument for compose testing files * several fixes
This commit is contained in:
@@ -9,12 +9,12 @@ import (
|
||||
|
||||
"github.com/ark-network/ark/common"
|
||||
"github.com/ark-network/ark/common/bitcointree"
|
||||
"github.com/ark-network/ark/common/descriptor"
|
||||
"github.com/ark-network/ark/pkg/client-sdk/explorer"
|
||||
"github.com/ark-network/ark/pkg/client-sdk/internal/utils"
|
||||
"github.com/ark-network/ark/pkg/client-sdk/store"
|
||||
"github.com/ark-network/ark/pkg/client-sdk/wallet"
|
||||
walletstore "github.com/ark-network/ark/pkg/client-sdk/wallet/singlekey/store"
|
||||
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
||||
"github.com/btcsuite/btcd/btcec/v2/schnorr"
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/btcutil/psbt"
|
||||
@@ -41,42 +41,42 @@ func NewBitcoinWallet(
|
||||
func (w *bitcoinWallet) GetAddresses(
|
||||
ctx context.Context,
|
||||
) ([]string, []string, []string, error) {
|
||||
offchainAddr, onchainAddr, redemptionAddr, err := w.getAddress(ctx)
|
||||
offchainAddr, boardingAddr, redemptionAddr, err := w.getAddress(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
offchainAddrs := []string{offchainAddr}
|
||||
onchainAddrs := []string{onchainAddr}
|
||||
boardingAddrs := []string{boardingAddr}
|
||||
redemptionAddrs := []string{redemptionAddr}
|
||||
return offchainAddrs, onchainAddrs, redemptionAddrs, nil
|
||||
return offchainAddrs, boardingAddrs, redemptionAddrs, nil
|
||||
}
|
||||
|
||||
func (w *bitcoinWallet) NewAddress(
|
||||
ctx context.Context, _ bool,
|
||||
) (string, string, error) {
|
||||
offchainAddr, onchainAddr, _, err := w.getAddress(ctx)
|
||||
offchainAddr, boardingAddr, _, err := w.getAddress(ctx)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return offchainAddr, onchainAddr, nil
|
||||
return offchainAddr, boardingAddr, nil
|
||||
}
|
||||
|
||||
func (w *bitcoinWallet) NewAddresses(
|
||||
ctx context.Context, _ bool, num int,
|
||||
) ([]string, []string, error) {
|
||||
offchainAddr, onchainAddr, _, err := w.getAddress(ctx)
|
||||
offchainAddr, boardingAddr, _, err := w.getAddress(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
offchainAddrs := make([]string, 0, num)
|
||||
onchainAddrs := make([]string, 0, num)
|
||||
boardingAddrs := make([]string, 0, num)
|
||||
for i := 0; i < num; i++ {
|
||||
offchainAddrs = append(offchainAddrs, offchainAddr)
|
||||
onchainAddrs = append(onchainAddrs, onchainAddr)
|
||||
boardingAddrs = append(boardingAddrs, boardingAddr)
|
||||
}
|
||||
return offchainAddrs, onchainAddrs, nil
|
||||
return offchainAddrs, boardingAddrs, nil
|
||||
}
|
||||
|
||||
func (s *bitcoinWallet) SignTransaction(
|
||||
@@ -92,11 +92,6 @@ func (s *bitcoinWallet) SignTransaction(
|
||||
return "", err
|
||||
}
|
||||
|
||||
data, err := s.configStore.GetData(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for i, input := range updater.Upsbt.UnsignedTx.TxIn {
|
||||
if updater.Upsbt.Inputs[i].WitnessUtxo != nil {
|
||||
continue
|
||||
@@ -122,28 +117,11 @@ func (s *bitcoinWallet) SignTransaction(
|
||||
return "", err
|
||||
}
|
||||
|
||||
sighashType := txscript.SigHashAll
|
||||
|
||||
if utxo.PkScript[0] == txscript.OP_1 {
|
||||
sighashType = txscript.SigHashDefault
|
||||
}
|
||||
|
||||
if err := updater.AddInSighashType(sighashType, i); err != nil {
|
||||
if err := updater.AddInSighashType(txscript.SigHashDefault, i); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
_, onchainAddr, _, err := s.getAddress(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
net := utils.ToBitcoinNetwork(data.Network)
|
||||
addr, _ := btcutil.DecodeAddress(onchainAddr, &net)
|
||||
onchainWalletScript, err := txscript.PayToAddrScript(addr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
prevouts := make(map[wire.OutPoint]*wire.TxOut)
|
||||
|
||||
for i, input := range updater.Upsbt.Inputs {
|
||||
@@ -158,36 +136,6 @@ func (s *bitcoinWallet) SignTransaction(
|
||||
txsighashes := txscript.NewTxSigHashes(updater.Upsbt.UnsignedTx, prevoutFetcher)
|
||||
|
||||
for i, input := range ptx.Inputs {
|
||||
if bytes.Equal(input.WitnessUtxo.PkScript, onchainWalletScript) {
|
||||
if err := updater.AddInSighashType(txscript.SigHashAll, i); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
preimage, err := txscript.CalcWitnessSigHash(
|
||||
input.WitnessUtxo.PkScript,
|
||||
txsighashes,
|
||||
txscript.SigHashAll,
|
||||
updater.Upsbt.UnsignedTx,
|
||||
i,
|
||||
int64(input.WitnessUtxo.Value),
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
sig := ecdsa.Sign(s.privateKey, preimage)
|
||||
signatureWithSighashType := append(sig.Serialize(), byte(txscript.SigHashAll))
|
||||
|
||||
updater.Upsbt.Inputs[i].PartialSigs = []*psbt.PartialSig{
|
||||
{
|
||||
PubKey: s.walletData.Pubkey.SerializeCompressed(),
|
||||
Signature: signatureWithSighashType,
|
||||
},
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if len(input.TaprootLeafScript) > 0 {
|
||||
pubkey := s.walletData.Pubkey
|
||||
for _, leaf := range input.TaprootLeafScript {
|
||||
@@ -269,11 +217,6 @@ func (w *bitcoinWallet) getAddress(
|
||||
|
||||
netParams := utils.ToBitcoinNetwork(data.Network)
|
||||
|
||||
onchainAddr, err := btcutil.NewAddressWitnessPubKeyHash(btcutil.Hash160(w.walletData.Pubkey.SerializeCompressed()), &netParams)
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
vtxoTapKey, _, err := bitcointree.ComputeVtxoTaprootScript(
|
||||
w.walletData.Pubkey, data.AspPubkey, uint(data.UnilateralExitDelay),
|
||||
)
|
||||
@@ -289,5 +232,35 @@ func (w *bitcoinWallet) getAddress(
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
return offchainAddr, onchainAddr.EncodeAddress(), redemptionAddr.EncodeAddress(), nil
|
||||
myPubkeyStr := hex.EncodeToString(schnorr.SerializePubKey(w.walletData.Pubkey))
|
||||
descriptorStr := strings.ReplaceAll(
|
||||
data.BoardingDescriptorTemplate, "USER", myPubkeyStr,
|
||||
)
|
||||
|
||||
desc, err := descriptor.ParseTaprootDescriptor(descriptorStr)
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
_, boardingTimeout, err := descriptor.ParseBoardingDescriptor(*desc)
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
boardingTapKey, _, err := bitcointree.ComputeVtxoTaprootScript(
|
||||
w.walletData.Pubkey, data.AspPubkey, boardingTimeout,
|
||||
)
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
boardingAddr, err := btcutil.NewAddressTaproot(
|
||||
schnorr.SerializePubKey(boardingTapKey),
|
||||
&netParams,
|
||||
)
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
return offchainAddr, boardingAddr.EncodeAddress(), redemptionAddr.EncodeAddress(), nil
|
||||
}
|
||||
|
||||
@@ -3,20 +3,21 @@ package singlekeywallet
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ark-network/ark/common"
|
||||
"github.com/ark-network/ark/common/descriptor"
|
||||
"github.com/ark-network/ark/common/tree"
|
||||
"github.com/ark-network/ark/pkg/client-sdk/explorer"
|
||||
"github.com/ark-network/ark/pkg/client-sdk/internal/utils"
|
||||
"github.com/ark-network/ark/pkg/client-sdk/store"
|
||||
"github.com/ark-network/ark/pkg/client-sdk/wallet"
|
||||
walletstore "github.com/ark-network/ark/pkg/client-sdk/wallet/singlekey/store"
|
||||
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
||||
"github.com/btcsuite/btcd/btcec/v2/schnorr"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/vulpemventures/go-elements/payment"
|
||||
"github.com/vulpemventures/go-elements/psetv2"
|
||||
"github.com/vulpemventures/go-elements/transaction"
|
||||
)
|
||||
@@ -40,42 +41,42 @@ func NewLiquidWallet(
|
||||
func (w *liquidWallet) GetAddresses(
|
||||
ctx context.Context,
|
||||
) ([]string, []string, []string, error) {
|
||||
offchainAddr, onchainAddr, redemptionAddr, err := w.getAddress(ctx)
|
||||
offchainAddr, boardingAddr, redemptionAddr, err := w.getAddress(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
offchainAddrs := []string{offchainAddr}
|
||||
onchainAddrs := []string{onchainAddr}
|
||||
boardingAddrs := []string{boardingAddr}
|
||||
redemptionAddrs := []string{redemptionAddr}
|
||||
return offchainAddrs, onchainAddrs, redemptionAddrs, nil
|
||||
return offchainAddrs, boardingAddrs, redemptionAddrs, nil
|
||||
}
|
||||
|
||||
func (w *liquidWallet) NewAddress(
|
||||
ctx context.Context, _ bool,
|
||||
) (string, string, error) {
|
||||
offchainAddr, onchainAddr, _, err := w.getAddress(ctx)
|
||||
offchainAddr, boardingAddr, _, err := w.getAddress(ctx)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return offchainAddr, onchainAddr, nil
|
||||
return offchainAddr, boardingAddr, nil
|
||||
}
|
||||
|
||||
func (w *liquidWallet) NewAddresses(
|
||||
ctx context.Context, _ bool, num int,
|
||||
) ([]string, []string, error) {
|
||||
offchainAddr, onchainAddr, _, err := w.getAddress(ctx)
|
||||
offchainAddr, boardingAddr, _, err := w.getAddress(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
offchainAddrs := make([]string, 0, num)
|
||||
onchainAddrs := make([]string, 0, num)
|
||||
boardingAddrs := make([]string, 0, num)
|
||||
for i := 0; i < num; i++ {
|
||||
offchainAddrs = append(offchainAddrs, offchainAddr)
|
||||
onchainAddrs = append(onchainAddrs, onchainAddr)
|
||||
boardingAddrs = append(boardingAddrs, boardingAddr)
|
||||
}
|
||||
return offchainAddrs, onchainAddrs, nil
|
||||
return offchainAddrs, boardingAddrs, nil
|
||||
}
|
||||
|
||||
func (s *liquidWallet) SignTransaction(
|
||||
@@ -114,13 +115,7 @@ func (s *liquidWallet) SignTransaction(
|
||||
return "", err
|
||||
}
|
||||
|
||||
sighashType := txscript.SigHashAll
|
||||
|
||||
if utxo.Script[0] == txscript.OP_1 {
|
||||
sighashType = txscript.SigHashDefault
|
||||
}
|
||||
|
||||
if err := updater.AddInSighashType(i, sighashType); err != nil {
|
||||
if err := updater.AddInSighashType(i, txscript.SigHashDefault); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
@@ -135,8 +130,6 @@ func (s *liquidWallet) SignTransaction(
|
||||
return "", err
|
||||
}
|
||||
liquidNet := utils.ToElementsNetwork(storeData.Network)
|
||||
p2wpkh := payment.FromPublicKey(s.walletData.Pubkey, &liquidNet, nil)
|
||||
onchainWalletScript := p2wpkh.WitnessScript
|
||||
|
||||
utx, err := pset.UnsignedTx()
|
||||
if err != nil {
|
||||
@@ -156,33 +149,6 @@ func (s *liquidWallet) SignTransaction(
|
||||
serializedPubKey := s.walletData.Pubkey.SerializeCompressed()
|
||||
|
||||
for i, input := range pset.Inputs {
|
||||
prevout := input.GetUtxo()
|
||||
|
||||
if bytes.Equal(prevout.Script, onchainWalletScript) {
|
||||
p, err := payment.FromScript(prevout.Script, &liquidNet, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
preimage := utx.HashForWitnessV0(
|
||||
i, p.Script, prevout.Value, txscript.SigHashAll,
|
||||
)
|
||||
|
||||
sig := ecdsa.Sign(s.privateKey, preimage[:])
|
||||
|
||||
signatureWithSighashType := append(
|
||||
sig.Serialize(), byte(txscript.SigHashAll),
|
||||
)
|
||||
|
||||
err = signer.SignInput(
|
||||
i, signatureWithSighashType, serializedPubKey, nil, nil,
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if len(input.TapLeafScript) > 0 {
|
||||
genesis, err := chainhash.NewHashFromStr(liquidNet.GenesisBlockHash)
|
||||
if err != nil {
|
||||
@@ -276,12 +242,6 @@ func (w *liquidWallet) getAddress(
|
||||
|
||||
liquidNet := utils.ToElementsNetwork(data.Network)
|
||||
|
||||
p2wpkh := payment.FromPublicKey(w.walletData.Pubkey, &liquidNet, nil)
|
||||
onchainAddr, err := p2wpkh.WitnessPubKeyHash()
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
_, _, _, redemptionAddr, err := tree.ComputeVtxoTaprootScript(
|
||||
w.walletData.Pubkey, data.AspPubkey, uint(data.UnilateralExitDelay), liquidNet,
|
||||
)
|
||||
@@ -289,5 +249,27 @@ func (w *liquidWallet) getAddress(
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
return offchainAddr, onchainAddr, redemptionAddr, nil
|
||||
myPubkeyStr := hex.EncodeToString(schnorr.SerializePubKey(w.walletData.Pubkey))
|
||||
descriptorStr := strings.ReplaceAll(
|
||||
data.BoardingDescriptorTemplate, "USER", myPubkeyStr,
|
||||
)
|
||||
|
||||
desc, err := descriptor.ParseTaprootDescriptor(descriptorStr)
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
_, boardingTimeout, err := descriptor.ParseBoardingDescriptor(*desc)
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
_, _, _, boardingAddr, err := tree.ComputeVtxoTaprootScript(
|
||||
w.walletData.Pubkey, data.AspPubkey, boardingTimeout, liquidNet,
|
||||
)
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
return offchainAddr, boardingAddr, redemptionAddr, nil
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ type WalletService interface {
|
||||
IsLocked() bool
|
||||
GetAddresses(
|
||||
ctx context.Context,
|
||||
) (offchainAddresses, onchainAddresses, redemptionAddresses []string, err error)
|
||||
) (offchainAddresses, boardingAddresses, redemptionAddresses []string, err error)
|
||||
NewAddress(
|
||||
ctx context.Context, change bool,
|
||||
) (offchainAddr, onchainAddr string, err error)
|
||||
@@ -29,5 +29,5 @@ type WalletService interface {
|
||||
) (offchainAddresses, onchainAddresses []string, err error)
|
||||
SignTransaction(
|
||||
ctx context.Context, explorerSvc explorer.Explorer, tx string,
|
||||
) (singedTx string, err error)
|
||||
) (signedTx string, err error)
|
||||
}
|
||||
|
||||
@@ -21,14 +21,15 @@ func TestWallet(t *testing.T) {
|
||||
key, _ := btcec.NewPrivateKey()
|
||||
password := "password"
|
||||
testStoreData := store.StoreData{
|
||||
AspUrl: "localhost:7070",
|
||||
AspPubkey: key.PubKey(),
|
||||
WalletType: wallet.SingleKeyWallet,
|
||||
ClientType: client.GrpcClient,
|
||||
Network: common.LiquidRegTest,
|
||||
RoundLifetime: 512,
|
||||
UnilateralExitDelay: 512,
|
||||
MinRelayFee: 300,
|
||||
AspUrl: "localhost:7070",
|
||||
AspPubkey: key.PubKey(),
|
||||
WalletType: wallet.SingleKeyWallet,
|
||||
ClientType: client.GrpcClient,
|
||||
Network: common.LiquidRegTest,
|
||||
RoundLifetime: 512,
|
||||
UnilateralExitDelay: 512,
|
||||
MinRelayFee: 300,
|
||||
BoardingDescriptorTemplate: "tr(0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0,{ and(pk(873079a0091c9b16abd1f8c508320b07f0d50144d09ccd792ce9c915dac60465), pk(USER)), and(older(604672), pk(USER)) })",
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
Reference in New Issue
Block a user