Delay unilateral exit and support send to onchain address (#117)

* add delay on redeem close + forfeit close

* increase default round lifetime (16 minutes min)

* add sequence to final pset

* update CLI and server to support delayed vtxos oncahin

* rename future to "locked"

* add configurable EXIT_DELAY variable

* renaming

* rename "close" --> "closure"

* rename "close" to "closure"

* error message config.go
This commit is contained in:
Louis Singer
2024-02-22 16:47:52 +01:00
committed by GitHub
parent 7c8ee7ab12
commit a95a829b20
30 changed files with 1244 additions and 719 deletions

View File

@@ -37,7 +37,7 @@ type Service interface {
GetEventsChannel(ctx context.Context) <-chan domain.RoundEvent
UpdatePaymentStatus(ctx context.Context, id string) error
ListVtxos(ctx context.Context, pubkey *secp256k1.PublicKey) ([]domain.Vtxo, error)
GetPubkey(ctx context.Context) (string, error)
GetInfo(ctx context.Context) (string, int64, int64, error)
}
type service struct {
@@ -47,6 +47,7 @@ type service struct {
roundLifetime int64
roundInterval int64
minRelayFee uint64
exitDelay int64
wallet ports.WalletService
repoManager ports.RepoManager
@@ -62,7 +63,7 @@ type service struct {
func NewService(
network common.Network, onchainNetwork network.Network,
roundInterval, roundLifetime int64, minRelayFee uint64,
roundInterval, roundLifetime int64, exitDelay int64, minRelayFee uint64,
walletSvc ports.WalletService, repoManager ports.RepoManager,
builder ports.TxBuilder, scanner ports.BlockchainScanner,
scheduler ports.SchedulerService,
@@ -81,7 +82,7 @@ func NewService(
svc := &service{
network, onchainNetwork, pubkey,
roundLifetime, roundInterval, minRelayFee,
roundLifetime, roundInterval, minRelayFee, exitDelay,
walletSvc, repoManager, builder, scanner, sweeper,
paymentRequests, forfeitTxs, eventsCh,
}
@@ -218,8 +219,8 @@ func (s *service) GetRoundByTxid(ctx context.Context, poolTxid string) (*domain.
return s.repoManager.Rounds().GetRoundWithTxid(ctx, poolTxid)
}
func (s *service) GetPubkey(ctx context.Context) (string, error) {
return hex.EncodeToString(s.pubkey.SerializeCompressed()), nil
func (s *service) GetInfo(ctx context.Context) (string, int64, int64, error) {
return hex.EncodeToString(s.pubkey.SerializeCompressed()), s.roundLifetime, s.exitDelay, nil
}
func (s *service) start() {

View File

@@ -2,7 +2,6 @@ package application
import (
"context"
"encoding/hex"
"fmt"
"time"
@@ -10,7 +9,6 @@ import (
"github.com/ark-network/ark/internal/core/domain"
"github.com/ark-network/ark/internal/core/ports"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
log "github.com/sirupsen/logrus"
"github.com/vulpemventures/go-elements/psetv2"
)
@@ -326,17 +324,6 @@ func (s *sweeper) findSweepableOutputs(
newNodesToCheck = append(newNodesToCheck, children...)
continue
}
// if the node is a leaf, the vtxos outputs should added as onchain outputs if they are not swept yet
vtxoExpiration, sweepInput, err := s.leafToSweepInput(ctx, blocktime, node)
if err != nil {
return nil, err
}
if sweepInput != nil {
expirationTime = vtxoExpiration
sweepInputs = []ports.SweepInput{*sweepInput}
}
}
if _, ok := sweepableOutputs[expirationTime]; !ok {
@@ -351,62 +338,6 @@ func (s *sweeper) findSweepableOutputs(
return sweepableOutputs, nil
}
func (s *sweeper) leafToSweepInput(ctx context.Context, txBlocktime int64, node tree.Node) (int64, *ports.SweepInput, error) {
pset, err := psetv2.NewPsetFromBase64(node.Tx)
if err != nil {
return -1, nil, err
}
vtxo, err := extractVtxoOutpoint(pset)
if err != nil {
return -1, nil, err
}
fromRepo, err := s.repoManager.Vtxos().GetVtxos(ctx, []domain.VtxoKey{*vtxo})
if err != nil {
return -1, nil, err
}
if len(fromRepo) == 0 {
return -1, nil, fmt.Errorf("vtxo not found")
}
if fromRepo[0].Swept {
return -1, nil, nil
}
if fromRepo[0].Redeemed {
return -1, nil, nil
}
// if the vtxo is not swept or redeemed, add it to the onchain outputs
pubKeyBytes, err := hex.DecodeString(fromRepo[0].Pubkey)
if err != nil {
return -1, nil, err
}
pubKey, err := secp256k1.ParsePubKey(pubKeyBytes)
if err != nil {
return -1, nil, err
}
sweepLeaf, lifetime, err := s.builder.GetLeafSweepClosure(node, pubKey)
if err != nil {
return -1, nil, err
}
sweepInput := ports.SweepInput{
InputArgs: psetv2.InputArgs{
Txid: vtxo.Txid,
TxIndex: vtxo.VOut,
},
SweepLeaf: *sweepLeaf,
Amount: fromRepo[0].Amount,
}
return txBlocktime + lifetime, &sweepInput, nil
}
func (s *sweeper) nodeToSweepInputs(parentBlocktime int64, node tree.Node) (int64, []ports.SweepInput, error) {
pset, err := psetv2.NewPsetFromBase64(node.Tx)
if err != nil {
@@ -543,14 +474,14 @@ func containsTree(tr0 tree.CongestionTree, tr1 tree.CongestionTree) (bool, error
// given a congestion tree input, searches and returns the sweep leaf and its lifetime in seconds
func extractSweepLeaf(input psetv2.Input) (sweepLeaf *psetv2.TapLeafScript, lifetime int64, err error) {
for _, leaf := range input.TapLeafScript {
isSweep, _, seconds, err := tree.DecodeSweepScript(leaf.Script)
closure := &tree.CSVSigClosure{}
valid, err := closure.Decode(leaf.Script)
if err != nil {
return nil, 0, err
}
if isSweep {
lifetime = int64(seconds)
if valid && closure.Seconds > uint(lifetime) {
sweepLeaf = &leaf
break
lifetime = int64(closure.Seconds)
}
}