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)