mirror of
https://github.com/aljazceru/ark.git
synced 2025-12-18 12:44:19 +01:00
Rename folders (#97)
* Rename arkd folder & drop cli * Rename ark cli folder & update docs * Update readme * Fix * scripts: add build-all * Add target to build cli for all platforms * Update build scripts --------- Co-authored-by: tiero <3596602+tiero@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
0d8c7bffb2
commit
dc00d60585
185
client/unilateral_redeem.go
Normal file
185
client/unilateral_redeem.go
Normal file
@@ -0,0 +1,185 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ark-network/ark/common/tree"
|
||||
"github.com/btcsuite/btcd/btcec/v2/schnorr"
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/vulpemventures/go-elements/psetv2"
|
||||
"github.com/vulpemventures/go-elements/taproot"
|
||||
)
|
||||
|
||||
type RedeemBranch interface {
|
||||
// UpdatePath checks for transactions of the branch onchain and updates the branch accordingly
|
||||
UpdatePath() error
|
||||
// Redeem will sign the branch of the tree and return the associated signed pset + the vtxo input
|
||||
RedeemPath() ([]string, error)
|
||||
// AddInput adds the vtxo input created by the branch
|
||||
AddVtxoInput(updater *psetv2.Updater) error
|
||||
}
|
||||
|
||||
type redeemBranch struct {
|
||||
vtxo *vtxo
|
||||
branch []*psetv2.Pset
|
||||
internalKey *secp256k1.PublicKey
|
||||
sweepClosure *taproot.TapElementsLeaf
|
||||
}
|
||||
|
||||
func newRedeemBranch(ctx *cli.Context, congestionTree tree.CongestionTree, vtxo vtxo) (RedeemBranch, error) {
|
||||
sweepClosure, _, err := findSweepClosure(congestionTree)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nodes, err := congestionTree.Branch(vtxo.txid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
branch := make([]*psetv2.Pset, 0, len(nodes))
|
||||
for _, node := range nodes {
|
||||
pset, err := psetv2.NewPsetFromBase64(node.Tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
branch = append(branch, pset)
|
||||
}
|
||||
|
||||
xOnlyKey := branch[0].Inputs[0].TapInternalKey
|
||||
internalKey, err := schnorr.ParsePubKey(xOnlyKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &redeemBranch{
|
||||
vtxo: &vtxo,
|
||||
branch: branch,
|
||||
internalKey: internalKey,
|
||||
sweepClosure: sweepClosure,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdatePath checks for transactions of the branch onchain and updates the branch accordingly
|
||||
func (r *redeemBranch) UpdatePath() error {
|
||||
for i := len(r.branch) - 1; i >= 0; i-- {
|
||||
pset := r.branch[i]
|
||||
unsignedTx, err := pset.UnsignedTx()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
txHash := unsignedTx.TxHash().String()
|
||||
|
||||
_, err = getTxHex(txHash)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// if no error, the tx exists onchain, so we can remove it (+ the parents) from the branch
|
||||
if i == len(r.branch)-1 {
|
||||
r.branch = []*psetv2.Pset{}
|
||||
} else {
|
||||
r.branch = r.branch[i+1:]
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RedeemPath returns the list of transactions to broadcast in order to access the vtxo output
|
||||
func (r *redeemBranch) RedeemPath() ([]string, error) {
|
||||
transactions := make([]string, 0, len(r.branch))
|
||||
|
||||
for _, pset := range r.branch {
|
||||
for i, input := range pset.Inputs {
|
||||
if len(input.TapLeafScript) == 0 {
|
||||
return nil, fmt.Errorf("tap leaf script not found on input #%d", i)
|
||||
}
|
||||
|
||||
for _, leaf := range input.TapLeafScript {
|
||||
isSweep, _, _, err := tree.DecodeSweepScript(leaf.Script)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if isSweep {
|
||||
continue
|
||||
}
|
||||
|
||||
controlBlock, err := leaf.ControlBlock.ToBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
unsignedTx, err := pset.UnsignedTx()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
unsignedTx.Inputs[i].Witness = [][]byte{
|
||||
leaf.Script,
|
||||
controlBlock[:],
|
||||
}
|
||||
|
||||
hex, err := unsignedTx.ToHex()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
transactions = append(transactions, hex)
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return transactions, nil
|
||||
}
|
||||
|
||||
// AddVtxoInput is a wrapper around psetv2.Updater adding a taproot input letting to spend the vtxo output
|
||||
func (r *redeemBranch) AddVtxoInput(updater *psetv2.Updater) error {
|
||||
walletPubkey, err := getWalletPublicKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nextInputIndex := len(updater.Pset.Inputs)
|
||||
if err := updater.AddInputs([]psetv2.InputArgs{
|
||||
{
|
||||
Txid: r.vtxo.txid,
|
||||
TxIndex: r.vtxo.vout,
|
||||
},
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add taproot tree letting to spend the vtxo
|
||||
checksigLeaf, err := tree.VtxoScript(walletPubkey)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
vtxoTaprootTree := taproot.AssembleTaprootScriptTree(
|
||||
*checksigLeaf,
|
||||
*r.sweepClosure,
|
||||
)
|
||||
|
||||
proofIndex := vtxoTaprootTree.LeafProofIndex[checksigLeaf.TapHash()]
|
||||
|
||||
if err := updater.AddInTapLeafScript(
|
||||
nextInputIndex,
|
||||
psetv2.NewTapLeafScript(
|
||||
vtxoTaprootTree.LeafMerkleProofs[proofIndex],
|
||||
r.internalKey,
|
||||
),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user