Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: nursery updates #363

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,23 +449,29 @@ func (database *Database) QueryRow(query string, args ...any) *sql.Row {
return database.db.QueryRow(query, args...)
}

func (database *Database) QueryAnySwap(id string) (*Swap, *ReverseSwap, *ChainSwap, error) {
type SomeSwap struct {
Normal *Swap
Reverse *ReverseSwap
Chain *ChainSwap
}

func (database *Database) QueryAnySwap(id string) (*SomeSwap, error) {
swap, err := database.QuerySwap(id)
if err == nil {
return swap, nil, nil, nil
return &SomeSwap{Normal: swap}, nil
}

reverseSwap, err := database.QueryReverseSwap(id)
if err == nil {
return nil, reverseSwap, nil, nil
return &SomeSwap{Reverse: reverseSwap}, nil
}

chainSwap, err := database.QueryChainSwap(id)
if err == nil {
return nil, nil, chainSwap, nil
return &SomeSwap{Chain: chainSwap}, nil
}

return nil, nil, nil, fmt.Errorf("could not find any type of Swap with ID %s", id)
return nil, fmt.Errorf("could not find any type of Swap with ID %s", id)
}

func (database *Database) QueryAllRefundableSwaps(tenantId *Id, currency boltz.Currency, currentHeight uint32) ([]*Swap, []*ChainSwap, error) {
Expand Down
74 changes: 21 additions & 53 deletions nursery/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ func (nursery *Nursery) RegisterChainSwap(chainSwap database.ChainSwap) error {
if err := nursery.registerSwaps([]string{chainSwap.Id}); err != nil {
return err
}
nursery.sendChainSwapUpdate(chainSwap)
return nil
}

Expand Down Expand Up @@ -123,9 +122,6 @@ func (nursery *Nursery) getChainSwapRefundOutput(swap *database.ChainSwap) *Outp
if err := nursery.database.AddChainSwapOnchainFee(swap, fee); err != nil {
return fmt.Errorf("could not add onchain fee in db: %s", err)
}

nursery.sendChainSwapUpdate(*swap)

return nil
},
func(err error) {
Expand All @@ -139,43 +135,35 @@ func (nursery *Nursery) handleChainSwapError(swap *database.ChainSwap, err error
logger.Error(dbErr.Error())
}
logger.Errorf("Chain Swap %s error: %s", swap.Id, err)
nursery.sendChainSwapUpdate(*swap)
}

func (nursery *Nursery) handleChainSwapStatus(swap *database.ChainSwap, status boltz.SwapStatusResponse) {
func (nursery *Nursery) handleChainSwapStatus(tx *database.Transaction, swap *database.ChainSwap, status boltz.SwapStatusResponse) error {
parsedStatus := boltz.ParseEvent(status.Status)

if parsedStatus == swap.Status {
logger.Debugf("Status of Chain Swap %s is %s already", swap.Id, parsedStatus)
return
return nil
}

logger.Infof("Status of Chain Swap %s changed to: %s", swap.Id, parsedStatus)

handleError := func(format string, args ...any) {
nursery.handleChainSwapError(swap, fmt.Errorf(format, args...))
}

if swap.FromData.LockupTransactionId == "" || swap.ToData.LockupTransactionId == "" {
response, err := nursery.boltz.GetChainSwapTransactions(swap.Id)
if err != nil {
var boltzErr boltz.Error
if !errors.As(err, &boltzErr) {
handleError("Could not get lockup tx from boltz: " + err.Error())
return
return fmt.Errorf("get lockup tx from boltz: %w", err)
}
} else {
if swap.FromData.LockupTransactionId == "" && response.UserLock != nil {
if err := nursery.setChainSwapLockupTransaction(swap, swap.FromData, response.UserLock.Transaction.Id); err != nil {
handleError("Could not set lockup transaction in database: " + err.Error())
return
return fmt.Errorf("could not set lockup transaction in database: %w", err)
}
logger.Infof("Found user lockup for Chain Swap %s", swap.Id)
}
if swap.ToData.LockupTransactionId == "" && response.ServerLock != nil {
if err := nursery.setChainSwapLockupTransaction(swap, swap.ToData, response.ServerLock.Transaction.Id); err != nil {
handleError("Could not set lockup transaction in database: " + err.Error())
return
return fmt.Errorf("could not set lockup transaction in database: %w", err)
}
logger.Infof("Found server lockup for Chain Swap %s", swap.Id)
}
Expand All @@ -192,42 +180,30 @@ func (nursery *Nursery) handleChainSwapStatus(swap *database.ChainSwap, status b
// TODO: store error
logger.Warnf("Boltz did not give us a new quote for Chain Swap %s: %v", swap.Id, quoteError)
} else {
handleError("could not get quote: %w", err)
return
return fmt.Errorf("could not get quote: %w", err)
}
}
if quote != nil {
result, err := nursery.onchain.FindOutput(chainOutputArgs(swap.FromData))
if err != nil {
handleError(err.Error())
return
return fmt.Errorf("could not find lockup vout: %w", err)
}

if err := nursery.CheckAmounts(boltz.ChainSwap, swap.Pair, result.Value, quote.Amount, swap.ServiceFeePercent); err != nil {
handleError("quote amounts not correct: %w", err)
return
return fmt.Errorf("quote amounts not correct: %w", err)
}

if err := nursery.boltz.AcceptChainSwapQuote(swap.Id, quote); err != nil {
handleError("could not accept quote: %w", err)
return
return fmt.Errorf("could not accept quote: %w", err)
}

err = nursery.database.RunTx(func(tx *database.Transaction) error {
if err := tx.SetChainSwapAmount(swap.ToData, quote.Amount); err != nil {
return fmt.Errorf("to amount: %w", err)
}

if err := tx.SetChainSwapAmount(swap.FromData, result.Value); err != nil {
return fmt.Errorf("from amount: %w", err)
}
return nil
})
if err != nil {
handleError("could not update chain swap amounts in database: %w", err)
return
if err := tx.SetChainSwapAmount(swap.ToData, quote.Amount); err != nil {
return fmt.Errorf("update to to amount: %w", err)
}

if err := tx.SetChainSwapAmount(swap.FromData, result.Value); err != nil {
return fmt.Errorf("update from from amount: %w", err)
}
}
}

Expand All @@ -238,19 +214,16 @@ func (nursery *Nursery) handleChainSwapStatus(swap *database.ChainSwap, status b

output := nursery.getChainSwapClaimOutput(swap)
if _, err := nursery.createTransaction(swap.Pair.To, []*Output{output}); err != nil {
logger.Infof("Could not claim chain swap output: %s", err)
return
return fmt.Errorf("could not claim chain swap output: %w", err)
}
default:
}

logger.Debugf("Updating status of Chain Swap %s to %s", swap.Id, parsedStatus)

err := nursery.database.UpdateChainSwapStatus(swap, parsedStatus)

if err != nil {
handleError(fmt.Sprintf("Could not update status of Chain Swap %s to %s: %s", swap.Id, parsedStatus, err))
return
return fmt.Errorf("could not update status to %s: %w", parsedStatus, err)
}

if parsedStatus.IsCompletedStatus() {
Expand All @@ -259,13 +232,11 @@ func (nursery *Nursery) handleChainSwapStatus(swap *database.ChainSwap, status b
logger.Infof("Chain Swap service fee: %dsat onchain fee: %dsat", serviceFee, *swap.OnchainFee)

if err := nursery.database.SetChainSwapServiceFee(swap, serviceFee); err != nil {
handleError("Could not set swap service fee in database: " + err.Error())
return
return fmt.Errorf("could not set swap service fee in database: %w", err)
}

if err := nursery.database.UpdateChainSwapState(swap, boltzrpc.SwapState_SUCCESSFUL, ""); err != nil {
handleError(err.Error())
return
return fmt.Errorf("could not update swap state: %w", err)
}
} else if parsedStatus.IsFailedStatus() {
// only set to SERVER_ERROR if we are not eligible for a new quote
Expand All @@ -274,20 +245,17 @@ func (nursery *Nursery) handleChainSwapStatus(swap *database.ChainSwap, status b

if swap.State == boltzrpc.SwapState_PENDING {
if err := nursery.database.UpdateChainSwapState(swap, boltzrpc.SwapState_SERVER_ERROR, ""); err != nil {
handleError(err.Error())
return
return fmt.Errorf("could not update swap state: %w", err)
}
}

if swap.FromData.LockupTransactionId != "" {
if _, err := nursery.RefundSwaps(swap.Pair.From, nil, []*database.ChainSwap{swap}); err != nil {
handleError("Could not refund Swap " + swap.Id + ": " + err.Error())
return
return fmt.Errorf("could not refund swap: %w", err)
}
}

}
}
nursery.sendChainSwapUpdate(*swap)

return nil
}
57 changes: 50 additions & 7 deletions nursery/nursery.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,42 @@ func (nursery *Nursery) recoverSwaps() error {
return nursery.registerSwaps(swapIds)
}

func (nursery *Nursery) setSomeSwapError(swap *database.SomeSwap, err error) {
var dbErr error
if swap.Normal != nil {
dbErr = nursery.database.UpdateSwapState(swap.Normal, boltzrpc.SwapState_ERROR, err.Error())
logger.Errorf("Submarine Swap %s error: %v", swap.Normal.Id, err)
}
if swap.Reverse != nil {
dbErr = nursery.database.UpdateReverseSwapState(swap.Reverse, boltzrpc.SwapState_ERROR, err.Error())
logger.Errorf("Reverse Swap %s error: %v", swap.Reverse.Id, err)
}
if swap.Chain != nil {
dbErr = nursery.database.UpdateChainSwapState(swap.Chain, boltzrpc.SwapState_ERROR, err.Error())
logger.Errorf("Chain Swap %s error: %v", swap.Chain.Id, err)
}
if dbErr != nil {
logger.Error(dbErr.Error())
}
}

func (nursery *Nursery) sendSomeSwapUpdate(swapId string) {
swap, err := nursery.database.QueryAnySwap(swapId)
if err != nil {
logger.Errorf("Could not query swap %s: %v", swapId, err)
return
}
if swap.Normal != nil {
nursery.sendSwapUpdate(*swap.Normal)
}
if swap.Chain != nil {
nursery.sendChainSwapUpdate(*swap.Chain)
}
if swap.Reverse != nil {
nursery.sendReverseSwapUpdate(*swap.Reverse)
}
}

func (nursery *Nursery) startSwapListener() {
logger.Infof("Starting swap update listener")

Expand All @@ -227,7 +263,7 @@ func (nursery *Nursery) startSwapListener() {
for status := range nursery.boltzWs.Updates {
logger.Debugf("Swap %s status update: %s", status.Id, status.Status)

swap, reverseSwap, chainSwap, err := nursery.database.QueryAnySwap(status.Id)
someSwap, err := nursery.database.QueryAnySwap(status.Id)
if err != nil {
logger.Errorf("Could not query swap %s: %v", status.Id, err)
continue
Expand All @@ -236,13 +272,20 @@ func (nursery *Nursery) startSwapListener() {
logger.Warnf("Boltz could not find Swap %s: %s ", status.Id, status.Error)
continue
}
if swap != nil {
nursery.handleSwapStatus(swap, status.SwapStatusResponse)
} else if reverseSwap != nil {
nursery.handleReverseSwapStatus(reverseSwap, status.SwapStatusResponse)
} else if chainSwap != nil {
nursery.handleChainSwapStatus(chainSwap, status.SwapStatusResponse)
err = nursery.database.RunTx(func(tx *database.Transaction) error {
if someSwap.Normal != nil {
return nursery.handleSwapStatus(tx, someSwap.Normal, status.SwapStatusResponse)
} else if someSwap.Reverse != nil {
return nursery.handleReverseSwapStatus(tx, someSwap.Reverse, status.SwapStatusResponse)
} else if someSwap.Chain != nil {
return nursery.handleChainSwapStatus(tx, someSwap.Chain, status.SwapStatusResponse)
}
return nil
})
if err != nil {
nursery.setSomeSwapError(someSwap, err)
}
nursery.sendSomeSwapUpdate(status.Id)
}
nursery.waitGroup.Done()
}()
Expand Down
Loading
Loading