contractcourt/success_resolver: extract remoteHTLC sweep into resolveRemoteCommitOutput

This move the logic for sweeping the HTLC output on the remote
commitment into its own method.
This commit is contained in:
Johan T. Halseth 2020-12-09 12:24:02 +01:00
parent 9b08ef6d4e
commit 9d33b00082
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26

@ -105,102 +105,7 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) {
// If we don't have a success transaction, then this means that this is // If we don't have a success transaction, then this means that this is
// an output on the remote party's commitment transaction. // an output on the remote party's commitment transaction.
if h.htlcResolution.SignedSuccessTx == nil { if h.htlcResolution.SignedSuccessTx == nil {
// If we don't already have the sweep transaction constructed, return h.resolveRemoteCommitOutput()
// 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[:])
// Before we can craft out sweeping transaction, we
// need to create an input which contains all the items
// required to add this input to a sweeping transaction,
// and generate a witness.
inp := input.MakeHtlcSucceedInput(
&h.htlcResolution.ClaimOutpoint,
&h.htlcResolution.SweepSignDesc,
h.htlcResolution.Preimage[:],
h.broadcastHeight,
h.htlcResolution.CsvDelay,
)
// 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: Set tx lock time to current block height
// instead of zero. Will be taken care of once sweeper
// implementation is complete.
//
// TODO: Use time-based sweeper and result chan.
var err error
h.sweepTx, err = h.Sweeper.CreateSweepTx(
[]input.Input{&inp},
sweep.FeePreference{
ConfTarget: sweepConfTarget,
}, 0,
)
if err != nil {
return nil, err
}
log.Infof("%T(%x): crafted sweep tx=%v", h,
h.htlc.RHash[:], spew.Sdump(h.sweepTx))
// With the sweep transaction signed, we'll now
// Checkpoint our state.
if err := h.Checkpoint(h); err != nil {
log.Errorf("unable to Checkpoint: %v", err)
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)
return nil, err
}
// With the sweep transaction broadcast, we'll wait for its
// confirmation.
sweepTXID := h.sweepTx.TxHash()
sweepScript := h.sweepTx.TxOut[0].PkScript
confNtfn, err := h.Notifier.RegisterConfirmationsNtfn(
&sweepTXID, sweepScript, 1, h.broadcastHeight,
)
if err != nil {
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,
channeldb.ResolverOutcomeClaimed,
)
} }
log.Infof("%T(%x): broadcasting second-layer transition tx: %v", log.Infof("%T(%x): broadcasting second-layer transition tx: %v",
@ -261,6 +166,108 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) {
) )
} }
// resolveRemoteCommitOutput handles sweeping an HTLC output on the remote
// commitment with the preimage. In this case we can sweep the output directly,
// and don't have to broadcast a second-level transaction.
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[:])
// Before we can craft out sweeping transaction, we need to
// create an input which contains all the items required to add
// this input to a sweeping transaction, and generate a
// witness.
inp := input.MakeHtlcSucceedInput(
&h.htlcResolution.ClaimOutpoint,
&h.htlcResolution.SweepSignDesc,
h.htlcResolution.Preimage[:],
h.broadcastHeight,
h.htlcResolution.CsvDelay,
)
// 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: Set tx lock time to current block height instead of
// zero. Will be taken care of once sweeper implementation is
// complete.
//
// TODO: Use time-based sweeper and result chan.
var err error
h.sweepTx, err = h.Sweeper.CreateSweepTx(
[]input.Input{&inp},
sweep.FeePreference{
ConfTarget: sweepConfTarget,
}, 0,
)
if err != nil {
return nil, err
}
log.Infof("%T(%x): crafted sweep tx=%v", h,
h.htlc.RHash[:], spew.Sdump(h.sweepTx))
// With the sweep transaction signed, we'll now Checkpoint our
// state.
if err := h.Checkpoint(h); err != nil {
log.Errorf("unable to Checkpoint: %v", err)
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)
return nil, err
}
// With the sweep transaction broadcast, we'll wait for its
// confirmation.
sweepTXID := h.sweepTx.TxHash()
sweepScript := h.sweepTx.TxOut[0].PkScript
confNtfn, err := h.Notifier.RegisterConfirmationsNtfn(
&sweepTXID, sweepScript, 1, h.broadcastHeight,
)
if err != nil {
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,
channeldb.ResolverOutcomeClaimed,
)
}
// checkpointClaim checkpoints the success resolver with the reports it needs. // checkpointClaim checkpoints the success resolver with the reports it needs.
// If this htlc was claimed two stages, it will write reports for both stages, // If this htlc was claimed two stages, it will write reports for both stages,
// otherwise it will just write for the single htlc claim. // otherwise it will just write for the single htlc claim.