@ -25,6 +25,13 @@ var (
// DefaultSweepConfTarget is the default confirmation target we'll use
// DefaultSweepConfTarget is the default confirmation target we'll use
// when sweeping on-chain HTLCs.
// when sweeping on-chain HTLCs.
DefaultSweepConfTarget int32 = 6
DefaultSweepConfTarget int32 = 6
// DefaultSweepConfTargetDelta is the delta of blocks from a Loop Out
// swap's expiration height at which we begin to use the default sweep
// confirmation target.
//
// TODO(wilmer): tune?
DefaultSweepConfTargetDelta int32 = DefaultSweepConfTarget * 2
)
)
// loopOutSwap contains all the in-memory state related to a pending loop out
// loopOutSwap contains all the in-memory state related to a pending loop out
@ -581,22 +588,29 @@ func (s *loopOutSwap) sweep(ctx context.Context,
htlcValue btcutil . Amount ) error {
htlcValue btcutil . Amount ) error {
witnessFunc := func ( sig [ ] byte ) ( wire . TxWitness , error ) {
witnessFunc := func ( sig [ ] byte ) ( wire . TxWitness , error ) {
return s . htlc . GenSuccessWitness (
return s . htlc . GenSuccessWitness ( sig , s . Preimage )
sig , s . Preimage ,
)
}
}
// Calculate sweep tx fee
// Calculate the transaction fee based on the confirmation target
// required to sweep the HTLC before the timeout. We'll use the
// confirmation target provided by the client unless we've come too
// close to the expiration height, in which case we'll use the default
// if it is better than what the client provided.
confTarget := s . SweepConfTarget
if s . CltvExpiry - s . height >= DefaultSweepConfTargetDelta &&
confTarget > DefaultSweepConfTarget {
confTarget = DefaultSweepConfTarget
}
fee , err := s . sweeper . GetSweepFee (
fee , err := s . sweeper . GetSweepFee (
ctx , s . htlc . AddSuccessToEstimator ,
ctx , s . htlc . AddSuccessToEstimator , confTarget ,
s . SweepConfTarget ,
)
)
if err != nil {
if err != nil {
return err
return err
}
}
// Ensure it doesn't exceed our maximum fee allowed.
if fee > s . MaxMinerFee {
if fee > s . MaxMinerFee {
s . log . Warnf ( "Required miner fee %v exceeds max of %v",
s . log . Warnf ( "Required fee %v exceeds max miner fee of %v",
fee , s . MaxMinerFee )
fee , s . MaxMinerFee )
if s . state == loopdb . StatePreimageRevealed {
if s . state == loopdb . StatePreimageRevealed {
@ -612,8 +626,7 @@ func (s *loopOutSwap) sweep(ctx context.Context,
// Create sweep tx.
// Create sweep tx.
sweepTx , err := s . sweeper . CreateSweepTx (
sweepTx , err := s . sweeper . CreateSweepTx (
ctx , s . height , s . htlc , htlcOutpoint ,
ctx , s . height , s . htlc , htlcOutpoint , s . ReceiverKey , witnessFunc ,
s . ReceiverKey , witnessFunc ,
htlcValue , fee , s . DestAddr ,
htlcValue , fee , s . DestAddr ,
)
)
if err != nil {
if err != nil {
@ -690,5 +703,11 @@ func validateLoopOutContract(lnd *lndclient.LndServices,
return ErrExpiryTooSoon
return ErrExpiryTooSoon
}
}
// Ensure the client has provided a sweep confirmation target that does
// not exceed the height at which we revert back to using the default.
if height + request . SweepConfTarget >= response . expiry - DefaultSweepConfTargetDelta {
return ErrSweepConfTargetTooFar
}
return nil
return nil
}
}