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

Merge new fixes into static-addr-staging #851

Closed
wants to merge 7 commits into from
Closed
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
50 changes: 49 additions & 1 deletion client.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,14 @@ var (
// probeTimeout is the maximum time until a probe is allowed to take.
probeTimeout = 3 * time.Minute

// repushDelay is the delay of (re)adding a sweep to sweepbatcher after
// a block is mined.
repushDelay = 1 * time.Second

// additionalDelay is the delay added on top of repushDelay inside the
// sweepbatcher to publish a sweep transaction.
additionalDelay = 1 * time.Second

// MinerFeeEstimationFailed is a magic number that is returned in a
// quote call as the miner fee if the fee estimation in lnd's wallet
// failed because of insufficient funds.
Expand Down Expand Up @@ -185,13 +191,52 @@ func NewClient(dbDir string, loopDB loopdb.SwapStore,
"NewSweepFetcherFromSwapStore failed: %w", err)
}

// There is circular dependency between executor and sweepbatcher, as
// executor stores sweepbatcher and sweepbatcher depends on
// executor.height() though loopOutSweepFeerateProvider.
var executor *executor

// getHeight returns current height, according to executor.
getHeight := func() int32 {
if executor == nil {
// This must not happen, because executor is set in this
// function, before sweepbatcher.Run is called.
log.Errorf("getHeight called when executor is nil")

return 0
}

return executor.height()
}

loopOutSweepFeerateProvider := newLoopOutSweepFeerateProvider(
sweeper, loopDB, cfg.Lnd.ChainParams, getHeight,
)

batcher := sweepbatcher.NewBatcher(
cfg.Lnd.WalletKit, cfg.Lnd.ChainNotifier, cfg.Lnd.Signer,
swapServerClient.MultiMuSig2SignSweep, verifySchnorrSig,
cfg.Lnd.ChainParams, sweeperDb, sweepStore,

// Disable 100 sats/kw fee bump every block and retarget feerate
// every block according to the current mempool condition.
sweepbatcher.WithCustomFeeRate(
loopOutSweepFeerateProvider.GetMinFeeRate,
),

// Upon new block arrival, republishing is triggered in both
// loopout.go code (waitForHtlcSpendConfirmedV2/ <-timerChan)
// and in sweepbatcher code (batch.Run/case <-timerChan). The
// former updates the fee rate which is used by the later by
// calling AddSweep. Make sure they are ordered, add additional
// delay time to sweepbatcher's handling. The delay used in
// loopout.go is repushDelay.
sweepbatcher.WithPublishDelay(
repushDelay+additionalDelay,
),
)

executor := newExecutor(&executorConfig{
executor = newExecutor(&executorConfig{
lnd: cfg.Lnd,
store: loopDB,
sweeper: sweeper,
Expand Down Expand Up @@ -570,8 +615,11 @@ func (s *Client) getLoopOutSweepFee(ctx context.Context, confTarget int32) (
htlc = swap.QuoteHtlcP2WSH
}

label := "loopout-quote"

return s.sweeper.GetSweepFee(
ctx, htlc.AddSuccessToEstimator, p2wshAddress, confTarget,
label,
)
}

Expand Down
4 changes: 2 additions & 2 deletions liquidity/liquidity.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,13 @@ const (
// time we reach timeout. We set this to a high estimate so that we can
// account for worst-case fees, (1250 * 4 / 1000) = 50 sat/byte.
defaultLoopInSweepFee = chainfee.SatPerKWeight(1250)
)

var (
// defaultHtlcConfTarget is the default confirmation target we use for
// loop in swap htlcs, set to the same default at the client.
defaultHtlcConfTarget = loop.DefaultHtlcConfTarget
)

var (
// defaultBudget is the default autoloop budget we set. This budget will
// only be used for automatically dispatched swaps if autoloop is
// explicitly enabled, so we are happy to set a non-zero value here. The
Expand Down
4 changes: 4 additions & 0 deletions loopd/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/lightninglabs/loop/liquidity"
"github.com/lightninglabs/loop/loopdb"
"github.com/lightninglabs/loop/notifications"
"github.com/lightninglabs/loop/sweep"
"github.com/lightninglabs/loop/sweepbatcher"
"github.com/lightningnetwork/lnd"
"github.com/lightningnetwork/lnd/build"
Expand Down Expand Up @@ -52,6 +53,9 @@ func SetupLoggers(root *build.RotatingLogWriter, intercept signal.Interceptor) {
lnd.AddSubLogger(
root, notifications.Subsystem, intercept, notifications.UseLogger,
)
lnd.AddSubLogger(
root, sweep.Subsystem, intercept, sweep.UseLogger,
)
}

// genSubLogger creates a logger for a subsystem. We provide an instance of
Expand Down
4 changes: 3 additions & 1 deletion loopin.go
Original file line number Diff line number Diff line change
Expand Up @@ -1077,10 +1077,12 @@ func (s *loopInSwap) publishTimeoutTx(ctx context.Context,
}
}

label := fmt.Sprintf("loopin-timeout-%x", s.hash[:6])

// Calculate sweep tx fee.
fee, err := s.sweeper.GetSweepFee(
ctx, s.htlc.AddTimeoutToEstimator, s.timeoutAddr,
TimeoutTxConfTarget,
TimeoutTxConfTarget, label,
)
if err != nil {
return 0, err
Expand Down
4 changes: 3 additions & 1 deletion loopin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,11 +312,13 @@ func handleHtlcExpiry(t *testing.T, ctx *loopInTestContext, inSwap *loopInSwap,
// Expect timeout tx to be published.
timeoutTx := <-ctx.lnd.TxPublishChannel

label := fmt.Sprintf("loopin-timeout-%x", inSwap.hash[:6])

// We can just get our sweep fee as we would in the swap code because
// our estimate is static.
fee, err := inSwap.sweeper.GetSweepFee(
context.Background(), inSwap.htlc.AddTimeoutToEstimator,
inSwap.timeoutAddr, TimeoutTxConfTarget,
inSwap.timeoutAddr, TimeoutTxConfTarget, label,
)
require.NoError(t, err)
cost.Onchain += fee
Expand Down
52 changes: 23 additions & 29 deletions loopout.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,33 @@ const (
// We'll try to sweep with MuSig2 at most 10 times. If that fails we'll
// fail back to using standard scriptspend sweep.
maxMusigSweepRetries = 10
)

var (
// MinLoopOutPreimageRevealDelta configures the minimum number of
// remaining blocks before htlc expiry required to reveal preimage.
MinLoopOutPreimageRevealDelta int32 = 20
MinLoopOutPreimageRevealDelta = 20

// DefaultSweepConfTarget is the default confirmation target we'll use
// when sweeping on-chain HTLCs.
DefaultSweepConfTarget int32 = 9
DefaultSweepConfTarget = 9

// DefaultHtlcConfTarget is the default confirmation target we'll use
// for on-chain htlcs published by the swap client for Loop In.
DefaultHtlcConfTarget int32 = 6
DefaultHtlcConfTarget = 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 = DefaultSweepConfTarget * 2
// swap's expiration height at which we begin to cap the sweep
// confirmation target with urgentSweepConfTarget and multiply feerate
// by factor urgentSweepConfTargetFactor.
DefaultSweepConfTargetDelta = 10

// urgentSweepConfTarget is the confirmation target we'll use when the
// loop-out swap is about to expire (<= DefaultSweepConfTargetDelta
// blocks to expire).
urgentSweepConfTarget = 3

// urgentSweepConfTargetFactor is the factor we apply to feerate of
// loop-out sweep if it is about to expire.
urgentSweepConfTargetFactor = 1.1
)

// loopOutSwap contains all the in-memory state related to a pending loop out
Expand Down Expand Up @@ -1169,12 +1175,12 @@ func (s *loopOutSwap) waitForHtlcSpendConfirmedV2(globalCtx context.Context,
timerChan = s.timerFactory(repushDelay)

case <-timerChan:
// sweepConfTarget will return false if the preimage is
// canSweep will return false if the preimage is
// not revealed yet but the conf target is closer than
// 20 blocks. In this case to be sure we won't attempt
// to sweep at all and we won't reveal the preimage
// either.
_, canSweep := s.sweepConfTarget()
canSweep := s.canSweep()
if !canSweep {
s.log.Infof("Aborting swap, timed " +
"out on-chain")
Expand Down Expand Up @@ -1375,9 +1381,9 @@ func validateLoopOutContract(lnd *lndclient.LndServices, request *OutRequest,
return nil
}

// sweepConfTarget returns the confirmation target for the htlc sweep or false
// if we're too late.
func (s *loopOutSwap) sweepConfTarget() (int32, bool) {
// canSweep will return false if the preimage is not revealed yet but the conf
// target is closer than 20 blocks (i.e. it is too late to reveal the preimage).
func (s *loopOutSwap) canSweep() bool {
remainingBlocks := s.CltvExpiry - s.height
blocksToLastReveal := remainingBlocks - MinLoopOutPreimageRevealDelta
preimageRevealed := s.state == loopdb.StatePreimageRevealed
Expand All @@ -1393,20 +1399,8 @@ func (s *loopOutSwap) sweepConfTarget() (int32, bool) {
s.height)

s.state = loopdb.StateFailTimeout
return 0, false
}

// 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 remainingBlocks <= DefaultSweepConfTargetDelta &&
confTarget > DefaultSweepConfTarget {

confTarget = DefaultSweepConfTarget
return false
}

return confTarget, true
return true
}
Loading
Loading