mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
Add a TxOutChecker interface for checking whether a selected deposit outpoint is still available before signing the HTLC transaction. Back the implementation with lnd wallet transaction data so known confirmed and mempool spends mark the outpoint unavailable.
79 lines
2.1 KiB
Go
79 lines
2.1 KiB
Go
package loopin
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/btcsuite/btcd/wire"
|
|
"github.com/lightninglabs/lndclient"
|
|
)
|
|
|
|
// lndTxOutChecker checks outpoint availability using lnd's wallet transaction
|
|
// view. It omits outputs already spent by a wallet-known transaction.
|
|
type lndTxOutChecker struct {
|
|
client lndclient.LightningClient
|
|
}
|
|
|
|
// NewLndTxOutChecker creates a TxOutChecker backed by lnd.
|
|
func NewLndTxOutChecker(client lndclient.LightningClient) TxOutChecker {
|
|
return &lndTxOutChecker{
|
|
client: client,
|
|
}
|
|
}
|
|
|
|
// GetTxOuts returns all requested tx outputs that lnd's transaction view still
|
|
// reports as unspent.
|
|
func (c *lndTxOutChecker) GetTxOuts(ctx context.Context,
|
|
outpoints []wire.OutPoint) (map[wire.OutPoint]*wire.TxOut, error) {
|
|
|
|
outpointByString := make(map[string]wire.OutPoint, len(outpoints))
|
|
outpointsByHash := make(map[string][]wire.OutPoint, len(outpoints))
|
|
for _, outpoint := range outpoints {
|
|
outpointByString[outpoint.String()] = outpoint
|
|
outpointsByHash[outpoint.Hash.String()] = append(
|
|
outpointsByHash[outpoint.Hash.String()], outpoint,
|
|
)
|
|
}
|
|
|
|
// We need lnd's wallet transaction view rather than only the funding
|
|
// transaction: a matching previous outpoint tells us the deposit has
|
|
// already been spent by a wallet-known transaction. Use endHeight=-1 so
|
|
// lnd includes unconfirmed transactions and mempool spends.
|
|
txs, err := c.client.ListTransactions(ctx, 0, -1)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
txOuts := make(map[wire.OutPoint]*wire.TxOut, len(outpoints))
|
|
spent := make(map[wire.OutPoint]struct{}, len(outpoints))
|
|
for _, tx := range txs {
|
|
for _, prevOutpoint := range tx.PreviousOutpoints {
|
|
outpoint, ok := outpointByString[prevOutpoint.GetOutpoint()]
|
|
if ok {
|
|
spent[outpoint] = struct{}{}
|
|
}
|
|
}
|
|
|
|
if tx.Tx == nil {
|
|
continue
|
|
}
|
|
|
|
txHash := tx.TxHash
|
|
if txHash == "" {
|
|
txHash = tx.Tx.TxHash().String()
|
|
}
|
|
|
|
for _, outpoint := range outpointsByHash[txHash] {
|
|
if int(outpoint.Index) >= len(tx.Tx.TxOut) {
|
|
continue
|
|
}
|
|
|
|
txOuts[outpoint] = tx.Tx.TxOut[outpoint.Index]
|
|
}
|
|
}
|
|
|
|
for outpoint := range spent {
|
|
delete(txOuts, outpoint)
|
|
}
|
|
|
|
return txOuts, nil
|
|
}
|