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

     1  package contractcourt
     2  
     3  import (
     4  	"encoding/binary"
     5  	"io"
     6  
     7  	"github.com/decred/dcrlnd/channeldb"
     8  )
     9  
    10  // breachResolver is a resolver that will handle breached closes. In the
    11  // future, this will likely take over the duties the current breacharbiter has.
    12  type breachResolver struct {
    13  	// resolved reflects if the contract has been fully resolved or not.
    14  	resolved bool
    15  
    16  	// subscribed denotes whether or not the breach resolver has subscribed
    17  	// to the breacharbiter for breach resolution.
    18  	subscribed bool
    19  
    20  	// replyChan is closed when the breach arbiter has completed serving
    21  	// justice.
    22  	replyChan chan struct{}
    23  
    24  	contractResolverKit
    25  }
    26  
    27  // newBreachResolver instantiates a new breach resolver.
    28  func newBreachResolver(resCfg ResolverConfig) *breachResolver {
    29  	r := &breachResolver{
    30  		contractResolverKit: *newContractResolverKit(resCfg),
    31  		replyChan:           make(chan struct{}),
    32  	}
    33  
    34  	r.initLogger(r)
    35  
    36  	return r
    37  }
    38  
    39  // ResolverKey returns the unique identifier for this resolver.
    40  func (b *breachResolver) ResolverKey() []byte {
    41  	key := newResolverID(b.ChanPoint)
    42  	return key[:]
    43  }
    44  
    45  // Resolve queries the breacharbiter to see if the justice transaction has been
    46  // broadcast.
    47  func (b *breachResolver) Resolve() (ContractResolver, error) {
    48  	if !b.subscribed {
    49  		complete, err := b.SubscribeBreachComplete(
    50  			&b.ChanPoint, b.replyChan,
    51  		)
    52  		if err != nil {
    53  			return nil, err
    54  		}
    55  
    56  		// If the breach resolution process is already complete, then
    57  		// we can cleanup and checkpoint the resolved state.
    58  		if complete {
    59  			b.resolved = true
    60  			return nil, b.Checkpoint(b)
    61  		}
    62  
    63  		// Prevent duplicate subscriptions.
    64  		b.subscribed = true
    65  	}
    66  
    67  	select {
    68  	case <-b.replyChan:
    69  		// The replyChan has been closed, signalling that the breach
    70  		// has been fully resolved. Checkpoint the resolved state and
    71  		// exit.
    72  		b.resolved = true
    73  		return nil, b.Checkpoint(b)
    74  	case <-b.quit:
    75  	}
    76  
    77  	return nil, errResolverShuttingDown
    78  }
    79  
    80  // Stop signals the breachResolver to stop.
    81  func (b *breachResolver) Stop() {
    82  	close(b.quit)
    83  }
    84  
    85  // IsResolved returns true if the breachResolver is fully resolved and cleanup
    86  // can occur.
    87  func (b *breachResolver) IsResolved() bool {
    88  	return b.resolved
    89  }
    90  
    91  // SupplementState adds additional state to the breachResolver.
    92  func (b *breachResolver) SupplementState(_ *channeldb.OpenChannel) {
    93  }
    94  
    95  // Encode encodes the breachResolver to the passed writer.
    96  func (b *breachResolver) Encode(w io.Writer) error {
    97  	return binary.Write(w, endian, b.resolved)
    98  }
    99  
   100  // newBreachResolverFromReader attempts to decode an encoded breachResolver
   101  // from the passed Reader instance, returning an active breachResolver.
   102  func newBreachResolverFromReader(r io.Reader, resCfg ResolverConfig) (
   103  	*breachResolver, error) {
   104  
   105  	b := &breachResolver{
   106  		contractResolverKit: *newContractResolverKit(resCfg),
   107  		replyChan:           make(chan struct{}),
   108  	}
   109  
   110  	if err := binary.Read(r, endian, &b.resolved); err != nil {
   111  		return nil, err
   112  	}
   113  
   114  	b.initLogger(b)
   115  
   116  	return b, nil
   117  }
   118  
   119  // A compile time assertion to ensure breachResolver meets the ContractResolver
   120  // interface.
   121  var _ ContractResolver = (*breachResolver)(nil)