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

     1  package contractcourt
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  
     9  	"github.com/decred/dcrd/wire"
    10  	"github.com/decred/dcrlnd/build"
    11  	"github.com/decred/dcrlnd/channeldb"
    12  	"github.com/decred/slog"
    13  )
    14  
    15  var (
    16  	endian = binary.BigEndian
    17  )
    18  
    19  const (
    20  	// sweepConfTarget is the default number of blocks that we'll use as a
    21  	// confirmation target when sweeping.
    22  	sweepConfTarget = 6
    23  
    24  	// secondLevelConfTarget is the confirmation target we'll use when
    25  	// adding fees to our second-level HTLC transactions.
    26  	secondLevelConfTarget = 6
    27  )
    28  
    29  // ContractResolver is an interface which packages a state machine which is
    30  // able to carry out the necessary steps required to fully resolve a Decred
    31  // contract on-chain. Resolvers are fully encodable to ensure callers are able
    32  // to persist them properly. A resolver may produce another resolver in the
    33  // case that claiming an HTLC is a multi-stage process. In this case, we may
    34  // partially resolve the contract, then persist, and set up for an additional
    35  // resolution.
    36  type ContractResolver interface {
    37  	// ResolverKey returns an identifier which should be globally unique
    38  	// for this particular resolver within the chain the original contract
    39  	// resides within.
    40  	ResolverKey() []byte
    41  
    42  	// Resolve instructs the contract resolver to resolve the output
    43  	// on-chain. Once the output has been *fully* resolved, the function
    44  	// should return immediately with a nil ContractResolver value for the
    45  	// first return value.  In the case that the contract requires further
    46  	// resolution, then another resolve is returned.
    47  	//
    48  	// NOTE: This function MUST be run as a goroutine.
    49  	Resolve() (ContractResolver, error)
    50  
    51  	// SupplementState allows the user of a ContractResolver to supplement
    52  	// it with state required for the proper resolution of a contract.
    53  	SupplementState(*channeldb.OpenChannel)
    54  
    55  	// IsResolved returns true if the stored state in the resolve is fully
    56  	// resolved. In this case the target output can be forgotten.
    57  	IsResolved() bool
    58  
    59  	// Encode writes an encoded version of the ContractResolver into the
    60  	// passed Writer.
    61  	Encode(w io.Writer) error
    62  
    63  	// Stop signals the resolver to cancel any current resolution
    64  	// processes, and suspend.
    65  	Stop()
    66  }
    67  
    68  // htlcContractResolver is the required interface for htlc resolvers.
    69  type htlcContractResolver interface {
    70  	ContractResolver
    71  
    72  	// HtlcPoint returns the htlc's outpoint on the commitment tx.
    73  	HtlcPoint() wire.OutPoint
    74  
    75  	// Supplement adds additional information to the resolver that is
    76  	// required before Resolve() is called.
    77  	Supplement(htlc channeldb.HTLC)
    78  }
    79  
    80  // reportingContractResolver is a ContractResolver that also exposes a report on
    81  // the resolution state of the contract.
    82  type reportingContractResolver interface {
    83  	ContractResolver
    84  
    85  	report() *ContractReport
    86  }
    87  
    88  // ResolverConfig contains the externally supplied configuration items that are
    89  // required by a ContractResolver implementation.
    90  type ResolverConfig struct {
    91  	// ChannelArbitratorConfig contains all the interfaces and closures
    92  	// required for the resolver to interact with outside sub-systems.
    93  	ChannelArbitratorConfig
    94  
    95  	// Checkpoint allows a resolver to check point its state. This function
    96  	// should write the state of the resolver to persistent storage, and
    97  	// return a non-nil error upon success. It takes a resolver report,
    98  	// which contains information about the outcome and should be written
    99  	// to disk if non-nil.
   100  	Checkpoint func(ContractResolver, ...*channeldb.ResolverReport) error
   101  }
   102  
   103  // contractResolverKit is meant to be used as a mix-in struct to be embedded within a
   104  // given ContractResolver implementation. It contains all the common items that
   105  // a resolver requires to carry out its duties.
   106  type contractResolverKit struct {
   107  	ResolverConfig
   108  
   109  	log slog.Logger
   110  
   111  	quit chan struct{}
   112  }
   113  
   114  // newContractResolverKit instantiates the mix-in struct.
   115  func newContractResolverKit(cfg ResolverConfig) *contractResolverKit {
   116  	return &contractResolverKit{
   117  		ResolverConfig: cfg,
   118  		quit:           make(chan struct{}),
   119  	}
   120  }
   121  
   122  // initLogger initializes the resolver-specific logger.
   123  func (r *contractResolverKit) initLogger(resolver ContractResolver) {
   124  	logPrefix := fmt.Sprintf("%T(%v):", resolver, r.ChanPoint)
   125  	r.log = build.NewPrefixLog(logPrefix, log)
   126  }
   127  
   128  var (
   129  	// errResolverShuttingDown is returned when the resolver stops
   130  	// progressing because it received the quit signal.
   131  	errResolverShuttingDown = errors.New("resolver shutting down")
   132  )