mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-04 09:48:19 +01:00
contractcourt+sweep: offer direct-preimage spend via SweepInput
This commit removes the method `CreateSweepTx` and makes sure when sweeping the htlc output via the direct-preimage spend, it's offered via the `SweepInput` interface.
This commit is contained in:
parent
9c1e6941c3
commit
dc7d90c16f
6 changed files with 56 additions and 155 deletions
|
@ -331,7 +331,6 @@ func TestContractInsertionRetrieval(t *testing.T) {
|
|||
htlc: channeldb.HTLC{
|
||||
RHash: testPreimage,
|
||||
},
|
||||
sweepTx: nil,
|
||||
}
|
||||
resolvers := []ContractResolver{
|
||||
&timeoutResolver,
|
||||
|
|
|
@ -156,14 +156,6 @@ func (s *mockSweeper) SweepInput(input input.Input, params sweep.Params) (
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (s *mockSweeper) CreateSweepTx(inputs []input.Input,
|
||||
feePref sweep.FeeEstimateInfo) (*wire.MsgTx, error) {
|
||||
|
||||
// We will wait for the test to supply the sweep tx to return.
|
||||
sweepTx := <-s.createSweepTxChan
|
||||
return sweepTx, nil
|
||||
}
|
||||
|
||||
func (s *mockSweeper) RelayFeePerKW() chainfee.SatPerKWeight {
|
||||
return 253
|
||||
}
|
||||
|
|
|
@ -51,13 +51,6 @@ type htlcSuccessResolver struct {
|
|||
// historical queries to the chain for spends/confirmations.
|
||||
broadcastHeight uint32
|
||||
|
||||
// sweepTx will be non-nil if we've already crafted a transaction to
|
||||
// sweep a direct HTLC output. This is only a concern if we're sweeping
|
||||
// from the commitment transaction of the remote party.
|
||||
//
|
||||
// TODO(roasbeef): send off to utxobundler
|
||||
sweepTx *wire.MsgTx
|
||||
|
||||
// htlc contains information on the htlc that we are resolving on-chain.
|
||||
htlc channeldb.HTLC
|
||||
|
||||
|
@ -427,12 +420,6 @@ func (h *htlcSuccessResolver) broadcastReSignedSuccessTx() (
|
|||
func (h *htlcSuccessResolver) resolveRemoteCommitOutput() (
|
||||
ContractResolver, error) {
|
||||
|
||||
// If we don't already have the sweep transaction constructed, we'll do
|
||||
// so and broadcast it.
|
||||
if h.sweepTx == nil {
|
||||
log.Infof("%T(%x): crafting sweep tx for incoming+remote "+
|
||||
"htlc confirmed", h, h.htlc.RHash[:])
|
||||
|
||||
isTaproot := txscript.IsPayToTaproot(
|
||||
h.htlcResolution.SweepSignDesc.Output.PkScript,
|
||||
)
|
||||
|
@ -460,75 +447,48 @@ func (h *htlcSuccessResolver) resolveRemoteCommitOutput() (
|
|||
))
|
||||
}
|
||||
|
||||
// With the input created, we can now generate the full sweep
|
||||
// transaction, that we'll use to move these coins back into
|
||||
// the backing wallet.
|
||||
//
|
||||
// TODO: Use time-based sweeper and result chan.
|
||||
var err error
|
||||
h.sweepTx, err = h.Sweeper.CreateSweepTx(
|
||||
[]input.Input{inp},
|
||||
sweep.FeeEstimateInfo{
|
||||
ConfTarget: sweepConfTarget,
|
||||
// Calculate the budget for this sweep.
|
||||
budget := calculateBudget(
|
||||
btcutil.Amount(inp.SignDesc().Output.Value),
|
||||
h.Budget.DeadlineHTLCRatio,
|
||||
h.Budget.DeadlineHTLC,
|
||||
)
|
||||
|
||||
deadline := fn.Some(int32(h.htlc.RefundTimeout))
|
||||
|
||||
log.Infof("%T(%x): offering direct-preimage HTLC output to sweeper "+
|
||||
"with deadline=%v, budget=%v", h, h.htlc.RHash[:],
|
||||
h.htlc.RefundTimeout, budget)
|
||||
|
||||
// We'll now offer the direct preimage HTLC to the sweeper.
|
||||
_, err := h.Sweeper.SweepInput(
|
||||
inp,
|
||||
sweep.Params{
|
||||
Budget: budget,
|
||||
DeadlineHeight: deadline,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Infof("%T(%x): crafted sweep tx=%v", h,
|
||||
h.htlc.RHash[:], spew.Sdump(h.sweepTx))
|
||||
|
||||
// TODO(halseth): should checkpoint sweep tx to DB? Since after
|
||||
// a restart we might create a different tx, that will conflict
|
||||
// with the published one.
|
||||
}
|
||||
|
||||
// Register the confirmation notification before broadcasting the sweep
|
||||
// transaction.
|
||||
sweepTXID := h.sweepTx.TxHash()
|
||||
sweepScript := h.sweepTx.TxOut[0].PkScript
|
||||
confNtfn, err := h.Notifier.RegisterConfirmationsNtfn(
|
||||
&sweepTXID, sweepScript, 1, h.broadcastHeight,
|
||||
// Wait for the direct-preimage HTLC sweep tx to confirm.
|
||||
sweepTxDetails, err := waitForSpend(
|
||||
&h.htlcResolution.ClaimOutpoint,
|
||||
h.htlcResolution.SweepSignDesc.Output.PkScript,
|
||||
h.broadcastHeight, h.Notifier, h.quit,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Regardless of whether an existing transaction was found or newly
|
||||
// constructed, we'll broadcast the sweep transaction to the network.
|
||||
label := labels.MakeLabel(
|
||||
labels.LabelTypeChannelClose, &h.ShortChanID,
|
||||
)
|
||||
err = h.PublishTx(h.sweepTx, label)
|
||||
if err != nil {
|
||||
log.Infof("%T(%x): unable to publish tx: %v",
|
||||
h, h.htlc.RHash[:], err)
|
||||
confNtfn.Cancel()
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Infof("%T(%x): waiting for sweep tx (txid=%v) to be confirmed", h,
|
||||
h.htlc.RHash[:], sweepTXID)
|
||||
|
||||
select {
|
||||
case _, ok := <-confNtfn.Confirmed:
|
||||
if !ok {
|
||||
return nil, errResolverShuttingDown
|
||||
}
|
||||
|
||||
case <-h.quit:
|
||||
return nil, errResolverShuttingDown
|
||||
}
|
||||
|
||||
// Once the transaction has received a sufficient number of
|
||||
// confirmations, we'll mark ourselves as fully resolved and exit.
|
||||
h.resolved = true
|
||||
|
||||
// Checkpoint the resolver, and write the outcome to disk.
|
||||
return nil, h.checkpointClaim(
|
||||
&sweepTXID,
|
||||
sweepTxDetails.SpenderTxHash,
|
||||
channeldb.ResolverOutcomeClaimed,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -181,17 +181,14 @@ func TestHtlcSuccessSingleStage(t *testing.T) {
|
|||
// that our sweep succeeded.
|
||||
preCheckpoint: func(ctx *htlcResolverTestContext,
|
||||
_ bool) error {
|
||||
// The resolver will create and publish a sweep
|
||||
// tx.
|
||||
resolver := ctx.resolver.(*htlcSuccessResolver)
|
||||
resolver.Sweeper.(*mockSweeper).
|
||||
createSweepTxChan <- sweepTx
|
||||
|
||||
// Confirm the sweep, which should resolve it.
|
||||
ctx.notifier.ConfChan <- &chainntnfs.TxConfirmation{
|
||||
Tx: sweepTx,
|
||||
BlockHeight: testInitialBlockHeight - 1,
|
||||
// The resolver will offer the input to the
|
||||
// sweeper.
|
||||
details := &chainntnfs.SpendDetail{
|
||||
SpendingTx: sweepTx,
|
||||
SpenderTxHash: &sweepTxid,
|
||||
}
|
||||
ctx.notifier.SpendChan <- details
|
||||
|
||||
return nil
|
||||
},
|
||||
|
|
|
@ -50,12 +50,6 @@ type UtxoSweeper interface {
|
|||
SweepInput(input input.Input, params sweep.Params) (chan sweep.Result,
|
||||
error)
|
||||
|
||||
// CreateSweepTx accepts a list of inputs and signs and generates a txn
|
||||
// that spends from them. This method also makes an accurate fee
|
||||
// estimate before generating the required witnesses.
|
||||
CreateSweepTx(inputs []input.Input,
|
||||
feePref sweep.FeeEstimateInfo) (*wire.MsgTx, error)
|
||||
|
||||
// RelayFeePerKW returns the minimum fee rate required for transactions
|
||||
// to be relayed.
|
||||
RelayFeePerKW() chainfee.SatPerKWeight
|
||||
|
|
|
@ -1159,47 +1159,6 @@ func (s *UtxoSweeper) handleUpdateReq(req *updateReq) (
|
|||
return resultChan, nil
|
||||
}
|
||||
|
||||
// CreateSweepTx accepts a list of inputs and signs and generates a txn that
|
||||
// spends from them. This method also makes an accurate fee estimate before
|
||||
// generating the required witnesses.
|
||||
//
|
||||
// The created transaction has a single output sending all the funds back to
|
||||
// the source wallet, after accounting for the fee estimate.
|
||||
//
|
||||
// The value of currentBlockHeight argument will be set as the tx locktime.
|
||||
// This function assumes that all CLTV inputs will be unlocked after
|
||||
// currentBlockHeight. Reasons not to use the maximum of all actual CLTV expiry
|
||||
// values of the inputs:
|
||||
//
|
||||
// - Make handling re-orgs easier.
|
||||
// - Thwart future possible fee sniping attempts.
|
||||
// - Make us blend in with the bitcoind wallet.
|
||||
//
|
||||
// TODO(yy): remove this method and only allow sweeping via requests.
|
||||
func (s *UtxoSweeper) CreateSweepTx(inputs []input.Input,
|
||||
feePref FeeEstimateInfo) (*wire.MsgTx, error) {
|
||||
|
||||
feePerKw, err := feePref.Estimate(
|
||||
s.cfg.FeeEstimator, s.cfg.MaxFeeRate.FeePerKWeight(),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Generate the receiving script to which the funds will be swept.
|
||||
pkScript, err := s.cfg.GenSweepScript()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tx, _, err := createSweepTx(
|
||||
inputs, nil, pkScript, uint32(s.currentHeight), feePerKw,
|
||||
s.cfg.MaxFeeRate.FeePerKWeight(), s.cfg.Signer,
|
||||
)
|
||||
|
||||
return tx, err
|
||||
}
|
||||
|
||||
// ListSweeps returns a list of the sweeps recorded by the sweep store.
|
||||
func (s *UtxoSweeper) ListSweeps() ([]chainhash.Hash, error) {
|
||||
return s.cfg.Store.ListSweeps()
|
||||
|
|
Loading…
Add table
Reference in a new issue