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 )