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

     1  package contractcourt
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  
    10  	"github.com/decred/dcrd/dcrutil/v4"
    11  	"github.com/decred/dcrlnd/channeldb"
    12  	"github.com/decred/dcrlnd/htlcswitch/hop"
    13  	"github.com/decred/dcrlnd/input"
    14  	"github.com/decred/dcrlnd/invoices"
    15  	"github.com/decred/dcrlnd/lntypes"
    16  	"github.com/decred/dcrlnd/lnwallet"
    17  )
    18  
    19  // htlcIncomingContestResolver is a ContractResolver that's able to resolve an
    20  // incoming HTLC that is still contested. An HTLC is still contested, if at the
    21  // time of commitment broadcast, we don't know of the preimage for it yet, and
    22  // it hasn't expired. In this case, we can resolve the HTLC if we learn of the
    23  // preimage, otherwise the remote party will sweep it after it expires.
    24  //
    25  // TODO(roasbeef): just embed the other resolver?
    26  type htlcIncomingContestResolver struct {
    27  	// htlcExpiry is the absolute expiry of this incoming HTLC. We use this
    28  	// value to determine if we can exit early as if the HTLC times out,
    29  	// before we learn of the preimage then we can't claim it on chain
    30  	// successfully.
    31  	htlcExpiry uint32
    32  
    33  	// htlcSuccessResolver is the inner resolver that may be utilized if we
    34  	// learn of the preimage.
    35  	*htlcSuccessResolver
    36  }
    37  
    38  // newIncomingContestResolver instantiates a new incoming htlc contest resolver.
    39  func newIncomingContestResolver(
    40  	res lnwallet.IncomingHtlcResolution, broadcastHeight uint32,
    41  	htlc channeldb.HTLC, resCfg ResolverConfig) *htlcIncomingContestResolver {
    42  
    43  	success := newSuccessResolver(
    44  		res, broadcastHeight, htlc, resCfg,
    45  	)
    46  
    47  	return &htlcIncomingContestResolver{
    48  		htlcExpiry:          htlc.RefundTimeout,
    49  		htlcSuccessResolver: success,
    50  	}
    51  }
    52  
    53  // Resolve attempts to resolve this contract. As we don't yet know of the
    54  // preimage for the contract, we'll wait for one of two things to happen:
    55  //
    56  //  1. We learn of the preimage! In this case, we can sweep the HTLC incoming
    57  //     and ensure that if this was a multi-hop HTLC we are made whole. In this
    58  //     case, an additional ContractResolver will be returned to finish the
    59  //     job.
    60  //
    61  //  2. The HTLC expires. If this happens, then the contract is fully resolved
    62  //     as we have no remaining actions left at our disposal.
    63  //
    64  // NOTE: Part of the ContractResolver interface.
    65  func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) {
    66  	// If we're already full resolved, then we don't have anything further
    67  	// to do.
    68  	if h.resolved {
    69  		return nil, nil
    70  	}
    71  
    72  	// First try to parse the payload. If that fails, we can stop resolution
    73  	// now.
    74  	payload, err := h.decodePayload()
    75  	if err != nil {
    76  		log.Debugf("ChannelArbitrator(%v): cannot decode payload of "+
    77  			"htlc %v", h.ChanPoint, h.HtlcPoint())
    78  
    79  		// If we've locked in an htlc with an invalid payload on our
    80  		// commitment tx, we don't need to resolve it. The other party
    81  		// will time it out and get their funds back. This situation can
    82  		// present itself when we crash before processRemoteAdds in the
    83  		// link has ran.
    84  		h.resolved = true
    85  
    86  		// We write a report to disk that indicates we could not decode
    87  		// the htlc.
    88  		resReport := h.report().resolverReport(
    89  			nil, channeldb.ResolverTypeIncomingHtlc,
    90  			channeldb.ResolverOutcomeAbandoned,
    91  		)
    92  		return nil, h.PutResolverReport(nil, resReport)
    93  	}
    94  
    95  	// Register for block epochs. After registration, the current height
    96  	// will be sent on the channel immediately.
    97  	blockEpochs, err := h.Notifier.RegisterBlockEpochNtfn(nil)
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  	defer blockEpochs.Cancel()
   102  
   103  	var currentHeight int32
   104  	select {
   105  	case newBlock, ok := <-blockEpochs.Epochs:
   106  		if !ok {
   107  			return nil, errResolverShuttingDown
   108  		}
   109  		currentHeight = newBlock.Height
   110  	case <-h.quit:
   111  		return nil, errResolverShuttingDown
   112  	}
   113  
   114  	// We'll first check if this HTLC has been timed out, if so, we can
   115  	// return now and mark ourselves as resolved. If we're past the point of
   116  	// expiry of the HTLC, then at this point the sender can sweep it, so
   117  	// we'll end our lifetime. Here we deliberately forego the chance that
   118  	// the sender doesn't sweep and we already have or will learn the
   119  	// preimage. Otherwise the resolver could potentially stay active
   120  	// indefinitely and the channel will never close properly.
   121  	if uint32(currentHeight) >= h.htlcExpiry {
   122  		// TODO(roasbeef): should also somehow check if outgoing is
   123  		// resolved or not
   124  		//  * may need to hook into the circuit map
   125  		//  * can't timeout before the outgoing has been
   126  
   127  		log.Infof("%T(%v): HTLC has timed out (expiry=%v, height=%v), "+
   128  			"abandoning", h, h.htlcResolution.ClaimOutpoint,
   129  			h.htlcExpiry, currentHeight)
   130  		h.resolved = true
   131  
   132  		// Finally, get our report and checkpoint our resolver with a
   133  		// timeout outcome report.
   134  		report := h.report().resolverReport(
   135  			nil, channeldb.ResolverTypeIncomingHtlc,
   136  			channeldb.ResolverOutcomeTimeout,
   137  		)
   138  		return nil, h.Checkpoint(h, report)
   139  	}
   140  
   141  	// applyPreimage is a helper function that will populate our internal
   142  	// resolver with the preimage we learn of. This should be called once
   143  	// the preimage is revealed so the inner resolver can properly complete
   144  	// its duties. The error return value indicates whether the preimage
   145  	// was properly applied.
   146  	applyPreimage := func(preimage lntypes.Preimage) error {
   147  		// Sanity check to see if this preimage matches our htlc. At
   148  		// this point it should never happen that it does not match.
   149  		if !preimage.Matches(h.htlc.RHash) {
   150  			return errors.New("preimage does not match hash")
   151  		}
   152  
   153  		// Update htlcResolution with the matching preimage.
   154  		h.htlcResolution.Preimage = preimage
   155  
   156  		log.Infof("%T(%v): extracted preimage=%v from beacon!", h,
   157  			h.htlcResolution.ClaimOutpoint, preimage)
   158  
   159  		// If this is our commitment transaction, then we'll need to
   160  		// populate the witness for the second-level HTLC transaction.
   161  		if h.htlcResolution.SignedSuccessTx != nil {
   162  			// Within the witness for the success transaction, the
   163  			// preimage is the 4th element as it looks like:
   164  			//
   165  			//  * <sender sig> <recvr sig> <preimage> <witness script>
   166  			//
   167  			// We'll populate it within the witness, as since this
   168  			// was a "contest" resolver, we didn't yet know of the
   169  			// preimage.
   170  			newSigScript, err := input.ReplaceReceiverHtlcSpendRedeemPreimage(
   171  				h.htlcResolution.SignedSuccessTx.TxIn[0].SignatureScript, preimage[:],
   172  			)
   173  			if err != nil {
   174  				return fmt.Errorf("error replacing preimage in txin: %v", err)
   175  			} else {
   176  				h.htlcResolution.SignedSuccessTx.TxIn[0].SignatureScript = newSigScript
   177  			}
   178  		}
   179  
   180  		return nil
   181  	}
   182  
   183  	// Define a closure to process htlc resolutions either directly or
   184  	// triggered by future notifications.
   185  	processHtlcResolution := func(e invoices.HtlcResolution) (
   186  		ContractResolver, error) {
   187  
   188  		// Take action based on the type of resolution we have
   189  		// received.
   190  		switch resolution := e.(type) {
   191  
   192  		// If the htlc resolution was a settle, apply the
   193  		// preimage and return a success resolver.
   194  		case *invoices.HtlcSettleResolution:
   195  			err := applyPreimage(resolution.Preimage)
   196  			if err != nil {
   197  				return nil, err
   198  			}
   199  
   200  			return h.htlcSuccessResolver, nil
   201  
   202  		// If the htlc was failed, mark the htlc as
   203  		// resolved.
   204  		case *invoices.HtlcFailResolution:
   205  			log.Infof("%T(%v): Exit hop HTLC canceled "+
   206  				"(expiry=%v, height=%v), abandoning", h,
   207  				h.htlcResolution.ClaimOutpoint,
   208  				h.htlcExpiry, currentHeight)
   209  
   210  			h.resolved = true
   211  
   212  			// Checkpoint our resolver with an abandoned outcome
   213  			// because we take no further action on this htlc.
   214  			report := h.report().resolverReport(
   215  				nil, channeldb.ResolverTypeIncomingHtlc,
   216  				channeldb.ResolverOutcomeAbandoned,
   217  			)
   218  			return nil, h.Checkpoint(h, report)
   219  
   220  		// Error if the resolution type is unknown, we are only
   221  		// expecting settles and fails.
   222  		default:
   223  			return nil, fmt.Errorf("unknown resolution"+
   224  				" type: %v", e)
   225  		}
   226  	}
   227  
   228  	var (
   229  		hodlChan       chan interface{}
   230  		witnessUpdates <-chan lntypes.Preimage
   231  	)
   232  	if payload.FwdInfo.NextHop == hop.Exit {
   233  		// Create a buffered hodl chan to prevent deadlock.
   234  		hodlChan = make(chan interface{}, 1)
   235  
   236  		// Notify registry that we are potentially resolving as an exit
   237  		// hop on-chain. If this HTLC indeed pays to an existing
   238  		// invoice, the invoice registry will tell us what to do with
   239  		// the HTLC. This is identical to HTLC resolution in the link.
   240  		circuitKey := channeldb.CircuitKey{
   241  			ChanID: h.ShortChanID,
   242  			HtlcID: h.htlc.HtlcIndex,
   243  		}
   244  
   245  		resolution, err := h.Registry.NotifyExitHopHtlc(
   246  			h.htlc.RHash, h.htlc.Amt, h.htlcExpiry, currentHeight,
   247  			circuitKey, hodlChan, payload,
   248  		)
   249  		if err != nil {
   250  			return nil, err
   251  		}
   252  
   253  		defer h.Registry.HodlUnsubscribeAll(hodlChan)
   254  
   255  		// Take action based on the resolution we received. If the htlc
   256  		// was settled, or a htlc for a known invoice failed we can
   257  		// resolve it directly. If the resolution is nil, the htlc was
   258  		// neither accepted nor failed, so we cannot take action yet.
   259  		switch res := resolution.(type) {
   260  		case *invoices.HtlcFailResolution:
   261  			// In the case where the htlc failed, but the invoice
   262  			// was known to the registry, we can directly resolve
   263  			// the htlc.
   264  			if res.Outcome != invoices.ResultInvoiceNotFound {
   265  				return processHtlcResolution(resolution)
   266  			}
   267  
   268  		// If we settled the htlc, we can resolve it.
   269  		case *invoices.HtlcSettleResolution:
   270  			return processHtlcResolution(resolution)
   271  
   272  		// If the resolution is nil, the htlc was neither settled nor
   273  		// failed so we cannot take action at present.
   274  		case nil:
   275  
   276  		default:
   277  			return nil, fmt.Errorf("unknown htlc resolution type: %T",
   278  				resolution)
   279  		}
   280  	} else {
   281  		// If the HTLC hasn't expired yet, then we may still be able to
   282  		// claim it if we learn of the pre-image, so we'll subscribe to
   283  		// the preimage database to see if it turns up, or the HTLC
   284  		// times out.
   285  		//
   286  		// NOTE: This is done BEFORE opportunistically querying the db,
   287  		// to ensure the preimage can't be delivered between querying
   288  		// and registering for the preimage subscription.
   289  		preimageSubscription := h.PreimageDB.SubscribeUpdates()
   290  		defer preimageSubscription.CancelSubscription()
   291  
   292  		// With the epochs and preimage subscriptions initialized, we'll
   293  		// query to see if we already know the preimage.
   294  		preimage, ok := h.PreimageDB.LookupPreimage(h.htlc.RHash)
   295  		if ok {
   296  			// If we do, then this means we can claim the HTLC!
   297  			// However, we don't know how to ourselves, so we'll
   298  			// return our inner resolver which has the knowledge to
   299  			// do so.
   300  			if err := applyPreimage(preimage); err != nil {
   301  				return nil, err
   302  			}
   303  
   304  			return h.htlcSuccessResolver, nil
   305  		}
   306  
   307  		witnessUpdates = preimageSubscription.WitnessUpdates
   308  	}
   309  
   310  	for {
   311  		select {
   312  		case preimage := <-witnessUpdates:
   313  			// We received a new preimage, but we need to ignore
   314  			// all except the preimage we are waiting for.
   315  			if !preimage.Matches(h.htlc.RHash) {
   316  				continue
   317  			}
   318  
   319  			if err := applyPreimage(preimage); err != nil {
   320  				return nil, err
   321  			}
   322  
   323  			// We've learned of the preimage and this information
   324  			// has been added to our inner resolver. We return it so
   325  			// it can continue contract resolution.
   326  			return h.htlcSuccessResolver, nil
   327  
   328  		case hodlItem := <-hodlChan:
   329  			htlcResolution := hodlItem.(invoices.HtlcResolution)
   330  			return processHtlcResolution(htlcResolution)
   331  
   332  		case newBlock, ok := <-blockEpochs.Epochs:
   333  			if !ok {
   334  				return nil, errResolverShuttingDown
   335  			}
   336  
   337  			// If this new height expires the HTLC, then this means
   338  			// we never found out the preimage, so we can mark
   339  			// resolved and exit.
   340  			newHeight := uint32(newBlock.Height)
   341  			if newHeight >= h.htlcExpiry {
   342  				log.Infof("%T(%v): HTLC has timed out "+
   343  					"(expiry=%v, height=%v), abandoning", h,
   344  					h.htlcResolution.ClaimOutpoint,
   345  					h.htlcExpiry, currentHeight)
   346  				h.resolved = true
   347  
   348  				report := h.report().resolverReport(
   349  					nil,
   350  					channeldb.ResolverTypeIncomingHtlc,
   351  					channeldb.ResolverOutcomeTimeout,
   352  				)
   353  				return nil, h.Checkpoint(h, report)
   354  			}
   355  
   356  		case <-h.quit:
   357  			return nil, errResolverShuttingDown
   358  		}
   359  	}
   360  }
   361  
   362  // report returns a report on the resolution state of the contract.
   363  func (h *htlcIncomingContestResolver) report() *ContractReport {
   364  	// No locking needed as these values are read-only.
   365  
   366  	finalAmt := h.htlc.Amt.ToAtoms()
   367  	if h.htlcResolution.SignedSuccessTx != nil {
   368  		finalAmt = dcrutil.Amount(
   369  			h.htlcResolution.SignedSuccessTx.TxOut[0].Value,
   370  		)
   371  	}
   372  
   373  	return &ContractReport{
   374  		Outpoint:       h.htlcResolution.ClaimOutpoint,
   375  		Type:           ReportOutputIncomingHtlc,
   376  		Amount:         finalAmt,
   377  		MaturityHeight: h.htlcExpiry,
   378  		LimboBalance:   finalAmt,
   379  		Stage:          1,
   380  	}
   381  }
   382  
   383  // Stop signals the resolver to cancel any current resolution processes, and
   384  // suspend.
   385  //
   386  // NOTE: Part of the ContractResolver interface.
   387  func (h *htlcIncomingContestResolver) Stop() {
   388  	close(h.quit)
   389  }
   390  
   391  // IsResolved returns true if the stored state in the resolve is fully
   392  // resolved. In this case the target output can be forgotten.
   393  //
   394  // NOTE: Part of the ContractResolver interface.
   395  func (h *htlcIncomingContestResolver) IsResolved() bool {
   396  	return h.resolved
   397  }
   398  
   399  // Encode writes an encoded version of the ContractResolver into the passed
   400  // Writer.
   401  //
   402  // NOTE: Part of the ContractResolver interface.
   403  func (h *htlcIncomingContestResolver) Encode(w io.Writer) error {
   404  	// We'll first write out the one field unique to this resolver.
   405  	if err := binary.Write(w, endian, h.htlcExpiry); err != nil {
   406  		return err
   407  	}
   408  
   409  	// Then we'll write out our internal resolver.
   410  	return h.htlcSuccessResolver.Encode(w)
   411  }
   412  
   413  // newIncomingContestResolverFromReader attempts to decode an encoded ContractResolver
   414  // from the passed Reader instance, returning an active ContractResolver
   415  // instance.
   416  func newIncomingContestResolverFromReader(r io.Reader, resCfg ResolverConfig) (
   417  	*htlcIncomingContestResolver, error) {
   418  
   419  	h := &htlcIncomingContestResolver{}
   420  
   421  	// We'll first read the one field unique to this resolver.
   422  	if err := binary.Read(r, endian, &h.htlcExpiry); err != nil {
   423  		return nil, err
   424  	}
   425  
   426  	// Then we'll decode our internal resolver.
   427  	successResolver, err := newSuccessResolverFromReader(r, resCfg)
   428  	if err != nil {
   429  		return nil, err
   430  	}
   431  	h.htlcSuccessResolver = successResolver
   432  
   433  	return h, nil
   434  }
   435  
   436  // Supplement adds additional information to the resolver that is required
   437  // before Resolve() is called.
   438  //
   439  // NOTE: Part of the htlcContractResolver interface.
   440  func (h *htlcIncomingContestResolver) Supplement(htlc channeldb.HTLC) {
   441  	h.htlc = htlc
   442  }
   443  
   444  // SupplementState allows the user of a ContractResolver to supplement it with
   445  // state required for the proper resolution of a contract.
   446  //
   447  // NOTE: Part of the ContractResolver interface.
   448  func (h *htlcIncomingContestResolver) SupplementState(_ *channeldb.OpenChannel) {
   449  }
   450  
   451  // decodePayload (re)decodes the hop payload of a received htlc.
   452  func (h *htlcIncomingContestResolver) decodePayload() (*hop.Payload, error) {
   453  
   454  	onionReader := bytes.NewReader(h.htlc.OnionBlob)
   455  	iterator, err := h.OnionProcessor.ReconstructHopIterator(
   456  		onionReader, h.htlc.RHash[:],
   457  	)
   458  	if err != nil {
   459  		return nil, err
   460  	}
   461  
   462  	return iterator.HopPayload()
   463  }
   464  
   465  // A compile time assertion to ensure htlcIncomingContestResolver meets the
   466  // ContractResolver interface.
   467  var _ htlcContractResolver = (*htlcIncomingContestResolver)(nil)