github.com/decred/dcrlnd@v0.7.6/contractcourt/htlc_timeout_resolver.go (about)

     1  package contractcourt
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"io"
     7  	"math"
     8  	"sync"
     9  
    10  	"github.com/davecgh/go-spew/spew"
    11  	"github.com/decred/dcrd/dcrutil/v4"
    12  	"github.com/decred/dcrd/wire"
    13  	"github.com/decred/dcrlnd/chainntnfs"
    14  	"github.com/decred/dcrlnd/channeldb"
    15  	"github.com/decred/dcrlnd/input"
    16  	"github.com/decred/dcrlnd/lntypes"
    17  	"github.com/decred/dcrlnd/lnwallet"
    18  	"github.com/decred/dcrlnd/lnwire"
    19  	"github.com/decred/dcrlnd/sweep"
    20  )
    21  
    22  // htlcTimeoutResolver is a ContractResolver that's capable of resolving an
    23  // outgoing HTLC. The HTLC may be on our commitment transaction, or on the
    24  // commitment transaction of the remote party. An output on our commitment
    25  // transaction is considered fully resolved once the second-level transaction
    26  // has been confirmed (and reached a sufficient depth). An output on the
    27  // commitment transaction of the remote party is resolved once we detect a
    28  // spend of the direct HTLC output using the timeout clause.
    29  type htlcTimeoutResolver struct {
    30  	// htlcResolution contains all the information required to properly
    31  	// resolve this outgoing HTLC.
    32  	htlcResolution lnwallet.OutgoingHtlcResolution
    33  
    34  	// outputIncubating returns true if we've sent the output to the output
    35  	// incubator (utxo nursery).
    36  	outputIncubating bool
    37  
    38  	// resolved reflects if the contract has been fully resolved or not.
    39  	resolved bool
    40  
    41  	// broadcastHeight is the height that the original contract was
    42  	// broadcast to the main-chain at. We'll use this value to bound any
    43  	// historical queries to the chain for spends/confirmations.
    44  	//
    45  	// TODO(roasbeef): wrap above into definite resolution embedding?
    46  	broadcastHeight uint32
    47  
    48  	// htlc contains information on the htlc that we are resolving
    49  	// on-chain.
    50  	htlc channeldb.HTLC
    51  
    52  	// channelInitiator denotes whether the party responsible for resolving
    53  	// the contract initiated the channel.
    54  	channelInitiator bool
    55  
    56  	// leaseExpiry denotes the additional waiting period the contract must
    57  	// hold until it can be resolved. This waiting period is known as the
    58  	// expiration of a script-enforced leased channel and only applies to
    59  	// the channel initiator.
    60  	//
    61  	// NOTE: This value should only be set when the contract belongs to a
    62  	// leased channel.
    63  	leaseExpiry uint32
    64  
    65  	// currentReport stores the current state of the resolver for reporting
    66  	// over the rpc interface. This should only be reported in case we have
    67  	// a non-nil SignDetails on the htlcResolution, otherwise the nursery
    68  	// will produce reports.
    69  	currentReport ContractReport
    70  
    71  	// reportLock prevents concurrent access to the resolver report.
    72  	reportLock sync.Mutex
    73  
    74  	contractResolverKit
    75  }
    76  
    77  // newTimeoutResolver instantiates a new timeout htlc resolver.
    78  func newTimeoutResolver(res lnwallet.OutgoingHtlcResolution,
    79  	broadcastHeight uint32, htlc channeldb.HTLC,
    80  	resCfg ResolverConfig) *htlcTimeoutResolver {
    81  
    82  	h := &htlcTimeoutResolver{
    83  		contractResolverKit: *newContractResolverKit(resCfg),
    84  		htlcResolution:      res,
    85  		broadcastHeight:     broadcastHeight,
    86  		htlc:                htlc,
    87  	}
    88  
    89  	h.initReport()
    90  
    91  	return h
    92  }
    93  
    94  // ResolverKey returns an identifier which should be globally unique for this
    95  // particular resolver within the chain the original contract resides within.
    96  //
    97  // NOTE: Part of the ContractResolver interface.
    98  func (h *htlcTimeoutResolver) ResolverKey() []byte {
    99  	// The primary key for this resolver will be the outpoint of the HTLC
   100  	// on the commitment transaction itself. If this is our commitment,
   101  	// then the output can be found within the signed timeout tx,
   102  	// otherwise, it's just the ClaimOutpoint.
   103  	var op wire.OutPoint
   104  	if h.htlcResolution.SignedTimeoutTx != nil {
   105  		op = h.htlcResolution.SignedTimeoutTx.TxIn[0].PreviousOutPoint
   106  	} else {
   107  		op = h.htlcResolution.ClaimOutpoint
   108  	}
   109  
   110  	key := newResolverID(op)
   111  	return key[:]
   112  }
   113  
   114  const (
   115  	// expectedRemoteWitnessSuccessSize is the expected size of the witness
   116  	// on the remote commitment transaction for an outgoing HTLC that is
   117  	// swept on-chain by them with pre-image.
   118  	expectedRemoteWitnessSuccessSize = 4
   119  
   120  	// remotePreimageIndex index within the witness on the remote
   121  	// commitment transaction that will hold they pre-image if they go to
   122  	// sweep it on chain.
   123  	remotePreimageIndex = 2
   124  
   125  	// localPreimageIndex is the index within the witness on the local
   126  	// commitment transaction for an outgoing HTLC that will hold the
   127  	// pre-image if the remote party sweeps it.
   128  	localPreimageIndex = 1
   129  )
   130  
   131  // claimCleanUp is a helper method that's called once the HTLC output is spent
   132  // by the remote party. It'll extract the preimage, add it to the global cache,
   133  // and finally send the appropriate clean up message.
   134  func (h *htlcTimeoutResolver) claimCleanUp(
   135  	commitSpend *chainntnfs.SpendDetail) (ContractResolver, error) {
   136  
   137  	// Depending on if this is our commitment or not, then we'll be looking
   138  	// for a different witness pattern.
   139  	spenderIndex := commitSpend.SpenderInputIndex
   140  	spendingInput := commitSpend.SpendingTx.TxIn[spenderIndex]
   141  
   142  	log.Infof("%T(%v): extracting preimage! remote party spent "+
   143  		"HTLC with tx=%v", h, h.htlcResolution.ClaimOutpoint,
   144  		spew.Sdump(commitSpend.SpendingTx))
   145  
   146  	// Decode the sigScript of the spendingInput into a series of
   147  	// data pushes, so that we can extract the preimage.
   148  	//
   149  	// TODO(decred) verify whether we need to check the length of
   150  	// sigScriptPushes before trying to copy one of its elements. This
   151  	// depends on the particulars of how this call site is reached.
   152  	sigScriptPushes, err := input.SigScriptToWitnessStack(spendingInput.SignatureScript)
   153  	if err != nil {
   154  		return nil, err
   155  
   156  	}
   157  
   158  	// If this is the remote party's commitment, then we'll be looking for
   159  	// them to spend using the second-level success transaction.
   160  	var preimageBytes []byte
   161  	if h.htlcResolution.SignedTimeoutTx == nil {
   162  		// The witness stack when the remote party sweeps the output to
   163  		// them looks like:
   164  		//
   165  		//  * <sender sig> <recvr sig> <preimage> <witness script>
   166  		preimageBytes = sigScriptPushes[2]
   167  	} else {
   168  		// Otherwise, they'll be spending directly from our commitment
   169  		// output. In which case the witness stack looks like:
   170  		//
   171  		//  * <sig> <preimage> <witness script>
   172  		preimageBytes = sigScriptPushes[1]
   173  	}
   174  
   175  	preimage, err := lntypes.MakePreimage(preimageBytes)
   176  	if err != nil {
   177  		return nil, fmt.Errorf("unable to create pre-image from "+
   178  			"witness: %v", err)
   179  	}
   180  
   181  	log.Infof("%T(%v): extracting preimage=%v from on-chain "+
   182  		"spend!", h, h.htlcResolution.ClaimOutpoint, preimage)
   183  
   184  	// With the preimage obtained, we can now add it to the global cache.
   185  	if err := h.PreimageDB.AddPreimages(preimage); err != nil {
   186  		log.Errorf("%T(%v): unable to add witness to cache",
   187  			h, h.htlcResolution.ClaimOutpoint)
   188  	}
   189  
   190  	var pre [32]byte
   191  	copy(pre[:], preimage[:])
   192  
   193  	// Finally, we'll send the clean up message, mark ourselves as
   194  	// resolved, then exit.
   195  	if err := h.DeliverResolutionMsg(ResolutionMsg{
   196  		SourceChan: h.ShortChanID,
   197  		HtlcIndex:  h.htlc.HtlcIndex,
   198  		PreImage:   &pre,
   199  	}); err != nil {
   200  		return nil, err
   201  	}
   202  	h.resolved = true
   203  
   204  	// Checkpoint our resolver with a report which reflects the preimage
   205  	// claim by the remote party.
   206  	amt := dcrutil.Amount(h.htlcResolution.SweepSignDesc.Output.Value)
   207  	report := &channeldb.ResolverReport{
   208  		OutPoint:        h.htlcResolution.ClaimOutpoint,
   209  		Amount:          amt,
   210  		ResolverType:    channeldb.ResolverTypeOutgoingHtlc,
   211  		ResolverOutcome: channeldb.ResolverOutcomeClaimed,
   212  		SpendTxID:       commitSpend.SpenderTxHash,
   213  	}
   214  
   215  	return nil, h.Checkpoint(h, report)
   216  }
   217  
   218  // chainDetailsToWatch returns the output and script which we use to watch for
   219  // spends from the direct HTLC output on the commitment transaction.
   220  //
   221  // TODO(joostjager): output already set properly in
   222  // lnwallet.newOutgoingHtlcResolution? And script too?
   223  func (h *htlcTimeoutResolver) chainDetailsToWatch() (*wire.OutPoint, []byte, error) {
   224  	// If there's no timeout transaction, then the claim output is the
   225  	// output directly on the commitment transaction, so we'll just use
   226  	// that.
   227  	if h.htlcResolution.SignedTimeoutTx == nil {
   228  		outPointToWatch := h.htlcResolution.ClaimOutpoint
   229  		scriptToWatch := h.htlcResolution.SweepSignDesc.Output.PkScript
   230  
   231  		return &outPointToWatch, scriptToWatch, nil
   232  	}
   233  
   234  	// If this is the remote party's commitment, then we'll need to grab
   235  	// watch the output that our timeout transaction points to. We can
   236  	// directly grab the outpoint, then also extract the witness script
   237  	// (the last element of the witness stack) to re-construct the pkScript
   238  	// we need to watch.
   239  	outPointToWatch := h.htlcResolution.SignedTimeoutTx.TxIn[0].PreviousOutPoint
   240  	sigScript := h.htlcResolution.SignedTimeoutTx.TxIn[0].SignatureScript
   241  	sigScriptPushes, err := input.SigScriptToWitnessStack(sigScript)
   242  	if err != nil {
   243  		return nil, nil, err
   244  	}
   245  	scriptToWatch, err := input.ScriptHashPkScript(
   246  		sigScriptPushes[len(sigScriptPushes)-1],
   247  	)
   248  	if err != nil {
   249  		return nil, nil, err
   250  	}
   251  
   252  	return &outPointToWatch, scriptToWatch, nil
   253  }
   254  
   255  // isSuccessSpend returns true if the passed spend on the specified commitment
   256  // is a success spend that reveals the pre-image or not.
   257  func isSuccessSpend(spend *chainntnfs.SpendDetail, localCommit bool) bool {
   258  	// Based on the spending input index and transaction, obtain the
   259  	// witness that tells us what type of spend this is.
   260  	spenderIndex := spend.SpenderInputIndex
   261  	spendingInput := spend.SpendingTx.TxIn[spenderIndex]
   262  	spendingSigScript := spendingInput.SignatureScript
   263  	spendingWitness, err := input.SigScriptToWitnessStack(spendingSigScript)
   264  	if err != nil {
   265  		log.Errorf("Error decoding pushed data in sigScript: %v", err)
   266  		return false
   267  	}
   268  
   269  	// If this is the remote commitment then the only possible spends for
   270  	// outgoing HTLCs are:
   271  	//
   272  	//  RECVR: <sender sig> <recvr sig> <preimage> (2nd level success spend)
   273  	//  REVOK: <sig> <key>
   274  	//  SENDR: <sig> 0
   275  	//
   276  	// In this case, if 5 witness elements are present (factoring the
   277  	// witness script), and the 3rd element is the size of the pre-image,
   278  	// then this is a remote spend. If not, then we swept it ourselves, or
   279  	// revoked their output.
   280  	if !localCommit {
   281  		return len(spendingWitness) == expectedRemoteWitnessSuccessSize &&
   282  			len(spendingWitness[remotePreimageIndex]) == lntypes.HashSize
   283  	}
   284  
   285  	// Otherwise, for our commitment, the only possible spends for an
   286  	// outgoing HTLC are:
   287  	//
   288  	//  SENDR: <sendr sig>  <recvr sig> <0> (2nd level timeout)
   289  	//  RECVR: <recvr sig>  <preimage>
   290  	//  REVOK: <revoke sig> <revoke key>
   291  	//
   292  	// So the only success case has the pre-image as the 2nd (index 1)
   293  	// element in the witness.
   294  	return len(spendingWitness[localPreimageIndex]) == lntypes.HashSize
   295  }
   296  
   297  // Resolve kicks off full resolution of an outgoing HTLC output. If it's our
   298  // commitment, it isn't resolved until we see the second level HTLC txn
   299  // confirmed. If it's the remote party's commitment, we don't resolve until we
   300  // see a direct sweep via the timeout clause.
   301  //
   302  // NOTE: Part of the ContractResolver interface.
   303  func (h *htlcTimeoutResolver) Resolve() (ContractResolver, error) {
   304  	// If we're already resolved, then we can exit early.
   305  	if h.resolved {
   306  		return nil, nil
   307  	}
   308  
   309  	// Start by spending the HTLC output, either by broadcasting the
   310  	// second-level timeout transaction, or directly if this is the remote
   311  	// commitment.
   312  	commitSpend, err := h.spendHtlcOutput()
   313  	if err != nil {
   314  		return nil, err
   315  	}
   316  
   317  	// If the spend reveals the pre-image, then we'll enter the clean up
   318  	// workflow to pass the pre-image back to the incoming link, add it to
   319  	// the witness cache, and exit.
   320  	if isSuccessSpend(commitSpend, h.htlcResolution.SignedTimeoutTx != nil) {
   321  		log.Infof("%T(%v): HTLC has been swept with pre-image by "+
   322  			"remote party during timeout flow! Adding pre-image to "+
   323  			"witness cache", h.htlcResolution.ClaimOutpoint)
   324  
   325  		return h.claimCleanUp(commitSpend)
   326  	}
   327  
   328  	log.Infof("%T(%v): resolving htlc with incoming fail msg, fully "+
   329  		"confirmed", h, h.htlcResolution.ClaimOutpoint)
   330  
   331  	// At this point, the second-level transaction is sufficiently
   332  	// confirmed, or a transaction directly spending the output is.
   333  	// Therefore, we can now send back our clean up message, failing the
   334  	// HTLC on the incoming link.
   335  	failureMsg := &lnwire.FailPermanentChannelFailure{}
   336  	if err := h.DeliverResolutionMsg(ResolutionMsg{
   337  		SourceChan: h.ShortChanID,
   338  		HtlcIndex:  h.htlc.HtlcIndex,
   339  		Failure:    failureMsg,
   340  	}); err != nil {
   341  		return nil, err
   342  	}
   343  
   344  	// Depending on whether this was a local or remote commit, we must
   345  	// handle the spending transaction accordingly.
   346  	return h.handleCommitSpend(commitSpend)
   347  }
   348  
   349  // spendHtlcOutput handles the initial spend of an HTLC output via the timeout
   350  // clause. If this is our local commitment, the second-level timeout TX will be
   351  // used to spend the output into the next stage. If this is the remote
   352  // commitment, the output will be swept directly without the timeout
   353  // transaction.
   354  func (h *htlcTimeoutResolver) spendHtlcOutput() (*chainntnfs.SpendDetail, error) {
   355  	switch {
   356  
   357  	// If we have non-nil SignDetails, this means that have a 2nd level
   358  	// HTLC transaction that is signed using sighash SINGLE|ANYONECANPAY
   359  	// (the case for anchor type channels). In this case we can re-sign it
   360  	// and attach fees at will. We let the sweeper handle this job.
   361  	case h.htlcResolution.SignDetails != nil && !h.outputIncubating:
   362  		log.Infof("%T(%x): offering second-layer timeout tx to "+
   363  			"sweeper: %v", h, h.htlc.RHash[:],
   364  			spew.Sdump(h.htlcResolution.SignedTimeoutTx))
   365  
   366  		inp := input.MakeHtlcSecondLevelTimeoutAnchorInput(
   367  			h.htlcResolution.SignedTimeoutTx,
   368  			h.htlcResolution.SignDetails,
   369  			h.broadcastHeight,
   370  		)
   371  		_, err := h.Sweeper.SweepInput(
   372  			&inp,
   373  			sweep.Params{
   374  				Fee: sweep.FeePreference{
   375  					ConfTarget: secondLevelConfTarget,
   376  				},
   377  			},
   378  		)
   379  		if err != nil {
   380  			return nil, err
   381  		}
   382  
   383  	// If we have no SignDetails, and we haven't already sent the output to
   384  	// the utxo nursery, then we'll do so now.
   385  	case h.htlcResolution.SignDetails == nil && !h.outputIncubating:
   386  		log.Tracef("%T(%v): incubating htlc output", h,
   387  			h.htlcResolution.ClaimOutpoint)
   388  
   389  		err := h.IncubateOutputs(
   390  			h.ChanPoint, &h.htlcResolution, nil,
   391  			h.broadcastHeight,
   392  		)
   393  		if err != nil {
   394  			return nil, err
   395  		}
   396  
   397  		h.outputIncubating = true
   398  
   399  		if err := h.Checkpoint(h); err != nil {
   400  			log.Errorf("unable to Checkpoint: %v", err)
   401  			return nil, err
   402  		}
   403  	}
   404  
   405  	// Now that we've handed off the HTLC to the nursery or sweeper, we'll
   406  	// watch for a spend of the output, and make our next move off of that.
   407  	// Depending on if this is our commitment, or the remote party's
   408  	// commitment, we'll be watching a different outpoint and script.
   409  	outpointToWatch, scriptToWatch, err := h.chainDetailsToWatch()
   410  	if err != nil {
   411  		return nil, err
   412  	}
   413  
   414  	log.Infof("%T(%v): waiting for HTLC output %v to be spent"+
   415  		"fully confirmed", h, h.htlcResolution.ClaimOutpoint,
   416  		outpointToWatch)
   417  
   418  	// We'll block here until either we exit, or the HTLC output on the
   419  	// commitment transaction has been spent.
   420  	spend, err := waitForSpend(
   421  		outpointToWatch, scriptToWatch, h.broadcastHeight,
   422  		h.Notifier, h.quit,
   423  	)
   424  	if err != nil {
   425  		return nil, err
   426  	}
   427  
   428  	// If this was the second level transaction published by the sweeper,
   429  	// we can checkpoint the resolver now that it's confirmed.
   430  	if h.htlcResolution.SignDetails != nil && !h.outputIncubating {
   431  		h.outputIncubating = true
   432  		if err := h.Checkpoint(h); err != nil {
   433  			log.Errorf("unable to Checkpoint: %v", err)
   434  			return nil, err
   435  		}
   436  	}
   437  
   438  	return spend, err
   439  }
   440  
   441  // handleCommitSpend handles the spend of the HTLC output on the commitment
   442  // transaction. If this was our local commitment, the spend will be he
   443  // confirmed second-level timeout transaction, and we'll sweep that into our
   444  // wallet. If the was a remote commitment, the resolver will resolve
   445  // immetiately.
   446  func (h *htlcTimeoutResolver) handleCommitSpend(
   447  	commitSpend *chainntnfs.SpendDetail) (ContractResolver, error) {
   448  
   449  	var (
   450  		// claimOutpoint will be the outpoint of the second level
   451  		// transaction, or on the remote commitment directly. It will
   452  		// start out as set in the resolution, but we'll update it if
   453  		// the second-level goes through the sweeper and changes its
   454  		// txid.
   455  		claimOutpoint = h.htlcResolution.ClaimOutpoint
   456  
   457  		// spendTxID will be the ultimate spend of the claimOutpoint.
   458  		// We set it to the commit spend for now, as this is the
   459  		// ultimate spend in case this is a remote commitment. If we go
   460  		// through the second-level transaction, we'll update this
   461  		// accordingly.
   462  		spendTxID = commitSpend.SpenderTxHash
   463  
   464  		reports []*channeldb.ResolverReport
   465  	)
   466  
   467  	switch {
   468  
   469  	// If the sweeper is handling the second level transaction, wait for
   470  	// the CSV and possible CLTV lock to expire, before sweeping the output
   471  	// on the second-level.
   472  	case h.htlcResolution.SignDetails != nil:
   473  		waitHeight := uint32(commitSpend.SpendingHeight) +
   474  			h.htlcResolution.CsvDelay - 1
   475  		if h.hasCLTV() {
   476  			waitHeight = uint32(math.Max(
   477  				float64(waitHeight), float64(h.leaseExpiry),
   478  			))
   479  		}
   480  
   481  		h.reportLock.Lock()
   482  		h.currentReport.Stage = 2
   483  		h.currentReport.MaturityHeight = waitHeight
   484  		h.reportLock.Unlock()
   485  
   486  		if h.hasCLTV() {
   487  			log.Infof("%T(%x): waiting for CSV and CLTV lock to "+
   488  				"expire at height %v", h, h.htlc.RHash[:],
   489  				waitHeight)
   490  		} else {
   491  			log.Infof("%T(%x): waiting for CSV lock to expire at "+
   492  				"height %v", h, h.htlc.RHash[:], waitHeight)
   493  		}
   494  
   495  		err := waitForHeight(waitHeight, h.Notifier, h.quit)
   496  		if err != nil {
   497  			return nil, err
   498  		}
   499  
   500  		// We'll use this input index to determine the second-level
   501  		// output index on the transaction, as the signatures requires
   502  		// the indexes to be the same. We don't look for the
   503  		// second-level output script directly, as there might be more
   504  		// than one HTLC output to the same pkScript.
   505  		op := &wire.OutPoint{
   506  			Hash:  *commitSpend.SpenderTxHash,
   507  			Index: commitSpend.SpenderInputIndex,
   508  		}
   509  
   510  		// Let the sweeper sweep the second-level output now that the
   511  		// CSV/CLTV locks have expired.
   512  		var inp *input.BaseInput
   513  		if h.hasCLTV() {
   514  			log.Infof("%T(%x): CSV and CLTV locks expired, offering "+
   515  				"second-layer output to sweeper: %v", h,
   516  				h.htlc.RHash[:], op)
   517  			inp = input.NewCsvInputWithCltv(
   518  				op, input.LeaseHtlcOfferedTimeoutSecondLevel,
   519  				&h.htlcResolution.SweepSignDesc,
   520  				h.broadcastHeight, h.htlcResolution.CsvDelay,
   521  				h.leaseExpiry,
   522  			)
   523  		} else {
   524  			log.Infof("%T(%x): CSV lock expired, offering "+
   525  				"second-layer output to sweeper: %v", h,
   526  				h.htlc.RHash[:], op)
   527  			inp = input.NewCsvInput(
   528  				op, input.HtlcOfferedTimeoutSecondLevel,
   529  				&h.htlcResolution.SweepSignDesc,
   530  				h.broadcastHeight, h.htlcResolution.CsvDelay,
   531  			)
   532  		}
   533  		_, err = h.Sweeper.SweepInput(
   534  			inp,
   535  			sweep.Params{
   536  				Fee: sweep.FeePreference{
   537  					ConfTarget: sweepConfTarget,
   538  				},
   539  			},
   540  		)
   541  		if err != nil {
   542  			return nil, err
   543  		}
   544  
   545  		// Update the claim outpoint to point to the second-level
   546  		// transaction created by the sweeper.
   547  		claimOutpoint = *op
   548  		fallthrough
   549  
   550  	// Finally, if this was an output on our commitment transaction, we'll
   551  	// wait for the second-level HTLC output to be spent, and for that
   552  	// transaction itself to confirm.
   553  	case h.htlcResolution.SignedTimeoutTx != nil:
   554  		log.Infof("%T(%v): waiting for nursery/sweeper to spend CSV "+
   555  			"delayed output", h, claimOutpoint)
   556  		sweep, err := waitForSpend(
   557  			&claimOutpoint,
   558  			h.htlcResolution.SweepSignDesc.Output.PkScript,
   559  			h.broadcastHeight, h.Notifier, h.quit,
   560  		)
   561  		if err != nil {
   562  			return nil, err
   563  		}
   564  
   565  		// Update the spend txid to the hash of the sweep transaction.
   566  		spendTxID = sweep.SpenderTxHash
   567  
   568  		// Once our sweep of the timeout tx has confirmed, we add a
   569  		// resolution for our timeoutTx tx first stage transaction.
   570  		timeoutTx := commitSpend.SpendingTx
   571  		index := commitSpend.SpenderInputIndex
   572  		spendHash := commitSpend.SpenderTxHash
   573  
   574  		reports = append(reports, &channeldb.ResolverReport{
   575  			OutPoint:        timeoutTx.TxIn[index].PreviousOutPoint,
   576  			Amount:          h.htlc.Amt.ToAtoms(),
   577  			ResolverType:    channeldb.ResolverTypeOutgoingHtlc,
   578  			ResolverOutcome: channeldb.ResolverOutcomeFirstStage,
   579  			SpendTxID:       spendHash,
   580  		})
   581  	}
   582  
   583  	// With the clean up message sent, we'll now mark the contract
   584  	// resolved, update the recovered balance, record the timeout and the
   585  	// sweep txid on disk, and wait.
   586  	h.resolved = true
   587  	h.reportLock.Lock()
   588  	h.currentReport.RecoveredBalance = h.currentReport.LimboBalance
   589  	h.currentReport.LimboBalance = 0
   590  	h.reportLock.Unlock()
   591  
   592  	amt := dcrutil.Amount(h.htlcResolution.SweepSignDesc.Output.Value)
   593  	reports = append(reports, &channeldb.ResolverReport{
   594  		OutPoint:        claimOutpoint,
   595  		Amount:          amt,
   596  		ResolverType:    channeldb.ResolverTypeOutgoingHtlc,
   597  		ResolverOutcome: channeldb.ResolverOutcomeTimeout,
   598  		SpendTxID:       spendTxID,
   599  	})
   600  
   601  	return nil, h.Checkpoint(h, reports...)
   602  }
   603  
   604  // Stop signals the resolver to cancel any current resolution processes, and
   605  // suspend.
   606  //
   607  // NOTE: Part of the ContractResolver interface.
   608  func (h *htlcTimeoutResolver) Stop() {
   609  	close(h.quit)
   610  }
   611  
   612  // IsResolved returns true if the stored state in the resolve is fully
   613  // resolved. In this case the target output can be forgotten.
   614  //
   615  // NOTE: Part of the ContractResolver interface.
   616  func (h *htlcTimeoutResolver) IsResolved() bool {
   617  	return h.resolved
   618  }
   619  
   620  // report returns a report on the resolution state of the contract.
   621  func (h *htlcTimeoutResolver) report() *ContractReport {
   622  	// If the sign details are nil, the report will be created by handled
   623  	// by the nursery.
   624  	if h.htlcResolution.SignDetails == nil {
   625  		return nil
   626  	}
   627  
   628  	h.reportLock.Lock()
   629  	defer h.reportLock.Unlock()
   630  	copy := h.currentReport
   631  	return &copy
   632  }
   633  
   634  func (h *htlcTimeoutResolver) initReport() {
   635  	// We create the initial report. This will only be reported for
   636  	// resolvers not handled by the nursery.
   637  	finalAmt := h.htlc.Amt.ToAtoms()
   638  	if h.htlcResolution.SignedTimeoutTx != nil {
   639  		finalAmt = dcrutil.Amount(
   640  			h.htlcResolution.SignedTimeoutTx.TxOut[0].Value,
   641  		)
   642  	}
   643  
   644  	h.currentReport = ContractReport{
   645  		Outpoint:       h.htlcResolution.ClaimOutpoint,
   646  		Type:           ReportOutputOutgoingHtlc,
   647  		Amount:         finalAmt,
   648  		MaturityHeight: h.htlcResolution.Expiry,
   649  		LimboBalance:   finalAmt,
   650  		Stage:          1,
   651  	}
   652  }
   653  
   654  // Encode writes an encoded version of the ContractResolver into the passed
   655  // Writer.
   656  //
   657  // NOTE: Part of the ContractResolver interface.
   658  func (h *htlcTimeoutResolver) Encode(w io.Writer) error {
   659  	// First, we'll write out the relevant fields of the
   660  	// OutgoingHtlcResolution to the writer.
   661  	if err := encodeOutgoingResolution(w, &h.htlcResolution); err != nil {
   662  		return err
   663  	}
   664  
   665  	// With that portion written, we can now write out the fields specific
   666  	// to the resolver itself.
   667  	if err := binary.Write(w, endian, h.outputIncubating); err != nil {
   668  		return err
   669  	}
   670  	if err := binary.Write(w, endian, h.resolved); err != nil {
   671  		return err
   672  	}
   673  	if err := binary.Write(w, endian, h.broadcastHeight); err != nil {
   674  		return err
   675  	}
   676  
   677  	if err := binary.Write(w, endian, h.htlc.HtlcIndex); err != nil {
   678  		return err
   679  	}
   680  
   681  	// We encode the sign details last for backwards compatibility.
   682  	err := encodeSignDetails(w, h.htlcResolution.SignDetails)
   683  	if err != nil {
   684  		return err
   685  	}
   686  
   687  	return nil
   688  }
   689  
   690  // newTimeoutResolverFromReader attempts to decode an encoded ContractResolver
   691  // from the passed Reader instance, returning an active ContractResolver
   692  // instance.
   693  func newTimeoutResolverFromReader(r io.Reader, resCfg ResolverConfig) (
   694  	*htlcTimeoutResolver, error) {
   695  
   696  	h := &htlcTimeoutResolver{
   697  		contractResolverKit: *newContractResolverKit(resCfg),
   698  	}
   699  
   700  	// First, we'll read out all the mandatory fields of the
   701  	// OutgoingHtlcResolution that we store.
   702  	if err := decodeOutgoingResolution(r, &h.htlcResolution); err != nil {
   703  		return nil, err
   704  	}
   705  
   706  	// With those fields read, we can now read back the fields that are
   707  	// specific to the resolver itself.
   708  	if err := binary.Read(r, endian, &h.outputIncubating); err != nil {
   709  		return nil, err
   710  	}
   711  	if err := binary.Read(r, endian, &h.resolved); err != nil {
   712  		return nil, err
   713  	}
   714  	if err := binary.Read(r, endian, &h.broadcastHeight); err != nil {
   715  		return nil, err
   716  	}
   717  
   718  	if err := binary.Read(r, endian, &h.htlc.HtlcIndex); err != nil {
   719  		return nil, err
   720  	}
   721  
   722  	// Sign details is a new field that was added to the htlc resolution,
   723  	// so it is serialized last for backwards compatibility. We try to read
   724  	// it, but don't error out if there are not bytes left.
   725  	signDetails, err := decodeSignDetails(r)
   726  	if err == nil {
   727  		h.htlcResolution.SignDetails = signDetails
   728  	} else if err != io.EOF && err != io.ErrUnexpectedEOF {
   729  		return nil, err
   730  	}
   731  
   732  	h.initReport()
   733  
   734  	return h, nil
   735  }
   736  
   737  // Supplement adds additional information to the resolver that is required
   738  // before Resolve() is called.
   739  //
   740  // NOTE: Part of the htlcContractResolver interface.
   741  func (h *htlcTimeoutResolver) Supplement(htlc channeldb.HTLC) {
   742  	h.htlc = htlc
   743  }
   744  
   745  // SupplementState allows the user of a ContractResolver to supplement it with
   746  // state required for the proper resolution of a contract.
   747  //
   748  // NOTE: Part of the ContractResolver interface.
   749  func (h *htlcTimeoutResolver) SupplementState(state *channeldb.OpenChannel) {
   750  	if state.ChanType.HasLeaseExpiration() {
   751  		h.leaseExpiry = state.ThawHeight
   752  	}
   753  	h.channelInitiator = state.IsInitiator
   754  }
   755  
   756  // hasCLTV denotes whether the resolver must wait for an additional CLTV to
   757  // expire before resolving the contract.
   758  func (h *htlcTimeoutResolver) hasCLTV() bool {
   759  	return h.channelInitiator && h.leaseExpiry > 0
   760  }
   761  
   762  // HtlcPoint returns the htlc's outpoint on the commitment tx.
   763  //
   764  // NOTE: Part of the htlcContractResolver interface.
   765  func (h *htlcTimeoutResolver) HtlcPoint() wire.OutPoint {
   766  	return h.htlcResolution.HtlcPoint()
   767  }
   768  
   769  // A compile time assertion to ensure htlcTimeoutResolver meets the
   770  // ContractResolver interface.
   771  var _ htlcContractResolver = (*htlcTimeoutResolver)(nil)