github.com/decred/dcrlnd@v0.7.6/chanacceptor/chainedacceptor.go (about) 1 package chanacceptor 2 3 import ( 4 "sync" 5 "sync/atomic" 6 ) 7 8 // ChainedAcceptor represents a conjunction of ChannelAcceptor results. 9 type ChainedAcceptor struct { 10 acceptorID uint64 // To be used atomically. 11 12 // acceptors is a map of ChannelAcceptors that will be evaluated when 13 // the ChainedAcceptor's Accept method is called. 14 acceptors map[uint64]ChannelAcceptor 15 acceptorsMtx sync.RWMutex 16 } 17 18 // NewChainedAcceptor initializes a ChainedAcceptor. 19 func NewChainedAcceptor() *ChainedAcceptor { 20 return &ChainedAcceptor{ 21 acceptors: make(map[uint64]ChannelAcceptor), 22 } 23 } 24 25 // AddAcceptor adds a ChannelAcceptor to this ChainedAcceptor. 26 func (c *ChainedAcceptor) AddAcceptor(acceptor ChannelAcceptor) uint64 { 27 id := atomic.AddUint64(&c.acceptorID, 1) 28 29 c.acceptorsMtx.Lock() 30 c.acceptors[id] = acceptor 31 c.acceptorsMtx.Unlock() 32 33 // Return the id so that a caller can call RemoveAcceptor. 34 return id 35 } 36 37 // RemoveAcceptor removes a ChannelAcceptor from this ChainedAcceptor given 38 // an ID. 39 func (c *ChainedAcceptor) RemoveAcceptor(id uint64) { 40 c.acceptorsMtx.Lock() 41 delete(c.acceptors, id) 42 c.acceptorsMtx.Unlock() 43 } 44 45 // Accept evaluates the results of all ChannelAcceptors in the acceptors map 46 // and returns the conjunction of all these predicates. 47 // 48 // NOTE: Part of the ChannelAcceptor interface. 49 func (c *ChainedAcceptor) Accept(req *ChannelAcceptRequest) *ChannelAcceptResponse { 50 c.acceptorsMtx.RLock() 51 defer c.acceptorsMtx.RUnlock() 52 53 var finalResp ChannelAcceptResponse 54 55 for _, acceptor := range c.acceptors { 56 // Call our acceptor to determine whether we want to accept this 57 // channel. 58 acceptorResponse := acceptor.Accept(req) 59 60 // If we should reject the channel, we can just exit early. This 61 // has the effect of returning the error belonging to our first 62 // failed acceptor. 63 if acceptorResponse.RejectChannel() { 64 return acceptorResponse 65 } 66 67 // If we have accepted the channel, we need to set the other 68 // fields that were set in the response. However, since we are 69 // dealing with multiple responses, we need to make sure that we 70 // have not received inconsistent values (eg a csv delay of 1 71 // from one acceptor, and a delay of 120 from another). We 72 // set each value on our final response if it has not been set 73 // yet, and allow duplicate sets if the value is the same. If 74 // we cannot set a field, we return an error response. 75 var err error 76 finalResp, err = mergeResponse(finalResp, *acceptorResponse) 77 if err != nil { 78 log.Errorf("response for: %x has inconsistent values: %v", 79 req.OpenChanMsg.PendingChannelID, err) 80 81 return NewChannelAcceptResponse( 82 false, errChannelRejected, nil, 0, 0, 83 0, 0, 0, 0, 84 ) 85 } 86 } 87 88 // If we have gone through all of our acceptors with no objections, we 89 // can return an acceptor with a nil error. 90 return &finalResp 91 } 92 93 // A compile-time constraint to ensure ChainedAcceptor implements the 94 // ChannelAcceptor interface. 95 var _ ChannelAcceptor = (*ChainedAcceptor)(nil)