[Client] Add vtxo expiration details to balance & Fix coin selection

* add expiry details in balance command

* coin selection: sort vtxos by olderFirst

* rename type

* balance: add next expiration

* add next expiration in offchain_balance json

* print duration in nextExpiration

* fix dust coin selection

* refactor sort
This commit is contained in:
Louis Singer
2024-02-20 17:10:18 +01:00
committed by GitHub
parent 10c19dd7d9
commit b8e0914ba9
10 changed files with 378 additions and 140 deletions

View File

@@ -2,6 +2,7 @@ package main
import (
"fmt"
"time"
"github.com/ark-network/ark/common/tree"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
@@ -12,12 +13,12 @@ import (
)
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 returns the list of transactions to broadcast in order to access the vtxo output
RedeemPath() ([]string, error)
// AddInput adds the vtxo input created by the branch
AddVtxoInput(updater *psetv2.Updater) error
// ExpireAt returns the expiration time of the branch
ExpireAt() (*time.Time, error)
}
type redeemBranch struct {
@@ -25,10 +26,22 @@ type redeemBranch struct {
branch []*psetv2.Pset
internalKey *secp256k1.PublicKey
sweepClosure *taproot.TapElementsLeaf
lifetime time.Duration
explorer Explorer
}
func newRedeemBranch(ctx *cli.Context, congestionTree tree.CongestionTree, vtxo vtxo) (RedeemBranch, error) {
sweepClosure, _, err := findSweepClosure(congestionTree)
func newRedeemBranch(
ctx *cli.Context,
explorer Explorer,
congestionTree tree.CongestionTree,
vtxo vtxo,
) (RedeemBranch, error) {
sweepClosure, seconds, err := findSweepClosure(congestionTree)
if err != nil {
return nil, err
}
lifetime, err := time.ParseDuration(fmt.Sprintf("%ds", seconds))
if err != nil {
return nil, err
}
@@ -58,43 +71,21 @@ func newRedeemBranch(ctx *cli.Context, congestionTree tree.CongestionTree, vtxo
branch: branch,
internalKey: internalKey,
sweepClosure: sweepClosure,
lifetime: lifetime,
explorer: explorer,
}, 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 {
offchainPath, err := r.offchainPath()
if err != nil {
return nil, err
}
for _, pset := range offchainPath {
for i, input := range pset.Inputs {
if len(input.TapLeafScript) == 0 {
return nil, fmt.Errorf("tap leaf script not found on input #%d", i)
@@ -183,3 +174,68 @@ func (r *redeemBranch) AddVtxoInput(updater *psetv2.Updater) error {
return nil
}
func (r *redeemBranch) ExpireAt() (*time.Time, error) {
lastKnownBlocktime := int64(0)
confirmed, blocktime, _ := getTxBlocktime(r.vtxo.poolTxid)
if confirmed {
lastKnownBlocktime = blocktime
} else {
expirationFromNow := time.Now().Add(time.Minute).Add(r.lifetime)
return &expirationFromNow, nil
}
for _, pset := range r.branch {
utx, _ := pset.UnsignedTx()
txid := utx.TxHash().String()
confirmed, blocktime, err := getTxBlocktime(txid)
if err != nil {
break
}
if confirmed {
lastKnownBlocktime = blocktime
continue
}
break
}
t := time.Unix(lastKnownBlocktime, 0).Add(r.lifetime)
return &t, nil
}
// offchainPath checks for transactions of the branch onchain and returns only the offchain part
func (r *redeemBranch) offchainPath() ([]*psetv2.Pset, error) {
offchainPath := append([]*psetv2.Pset{}, r.branch...)
for i := len(r.branch) - 1; i >= 0; i-- {
pset := r.branch[i]
unsignedTx, err := pset.UnsignedTx()
if err != nil {
fmt.Println("error", err)
return nil, err
}
txHash := unsignedTx.TxHash().String()
_, err = r.explorer.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 {
offchainPath = []*psetv2.Pset{}
} else {
offchainPath = r.branch[i+1:]
}
break
}
return offchainPath, nil
}