github.com/decred/dcrlnd@v0.7.6/autopilot/agent_constraints.go (about) 1 package autopilot 2 3 import ( 4 "github.com/decred/dcrd/dcrutil/v4" 5 ) 6 7 // AgentConstraints is an interface the agent will query to determine what 8 // limits it will need to stay inside when opening channels. 9 type AgentConstraints interface { 10 // ChannelBudget should, given the passed parameters, return whether 11 // more channels can be opened while still staying within the set 12 // constraints. If the constraints allow us to open more channels, then 13 // the first return value will represent the amount of additional funds 14 // available towards creating channels. The second return value is the 15 // exact *number* of additional channels available. 16 ChannelBudget(chans []LocalChannel, balance dcrutil.Amount) ( 17 dcrutil.Amount, uint32) 18 19 // MaxPendingOpens returns the maximum number of pending channel 20 // establishment goroutines that can be lingering. We cap this value in 21 // order to control the level of parallelism caused by the autopilot 22 // agent. 23 MaxPendingOpens() uint16 24 25 // MinChanSize returns the smallest channel that the autopilot agent 26 // should create. 27 MinChanSize() dcrutil.Amount 28 29 // MaxChanSize returns largest channel that the autopilot agent should 30 // create. 31 MaxChanSize() dcrutil.Amount 32 } 33 34 // agenConstraints is an implementation of the AgentConstraints interface that 35 // indicate the constraints the autopilot agent must adhere to when opening 36 // channels. 37 type agentConstraints struct { 38 // minChanSize is the smallest channel that the autopilot agent should 39 // create. 40 minChanSize dcrutil.Amount 41 42 // maxChanSize is the largest channel that the autopilot agent should 43 // create. 44 maxChanSize dcrutil.Amount 45 46 // chanLimit is the maximum number of channels that should be created. 47 chanLimit uint16 48 49 // allocation is the percentage of total funds that should be committed 50 // to automatic channel establishment. 51 allocation float64 52 53 // maxPendingOpens is the maximum number of pending channel 54 // establishment goroutines that can be lingering. We cap this value in 55 // order to control the level of parallelism caused by the autopilot 56 // agent. 57 maxPendingOpens uint16 58 } 59 60 // A compile time assertion to ensure agentConstraints satisfies the 61 // AgentConstraints interface. 62 var _ AgentConstraints = (*agentConstraints)(nil) 63 64 // NewConstraints returns a new AgentConstraints with the given limits. 65 func NewConstraints(minChanSize, maxChanSize dcrutil.Amount, chanLimit, 66 maxPendingOpens uint16, allocation float64) AgentConstraints { 67 68 return &agentConstraints{ 69 minChanSize: minChanSize, 70 maxChanSize: maxChanSize, 71 chanLimit: chanLimit, 72 allocation: allocation, 73 maxPendingOpens: maxPendingOpens, 74 } 75 } 76 77 // ChannelBudget should, given the passed parameters, return whether more 78 // channels can be be opened while still staying within the set constraints. 79 // If the constraints allow us to open more channels, then the first return 80 // value will represent the amount of additional funds available towards 81 // creating channels. The second return value is the exact *number* of 82 // additional channels available. 83 // 84 // Note: part of the AgentConstraints interface. 85 func (h *agentConstraints) ChannelBudget(channels []LocalChannel, 86 funds dcrutil.Amount) (dcrutil.Amount, uint32) { 87 88 // If we're already over our maximum allowed number of channels, then 89 // we'll instruct the controller not to create any more channels. 90 if len(channels) >= int(h.chanLimit) { 91 return 0, 0 92 } 93 94 // The number of additional channels that should be opened is the 95 // difference between the channel limit, and the number of channels we 96 // already have open. 97 numAdditionalChans := uint32(h.chanLimit) - uint32(len(channels)) 98 99 // First, we'll tally up the total amount of funds that are currently 100 // present within the set of active channels. 101 var totalChanAllocation dcrutil.Amount 102 for _, channel := range channels { 103 totalChanAllocation += channel.Balance 104 } 105 106 // With this value known, we'll now compute the total amount of fund 107 // allocated across regular utxo's and channel utxo's. 108 totalFunds := funds + totalChanAllocation 109 110 // Once the total amount has been computed, we then calculate the 111 // fraction of funds currently allocated to channels. 112 fundsFraction := float64(totalChanAllocation) / float64(totalFunds) 113 114 // If this fraction is below our threshold, then we'll return true, to 115 // indicate the controller should call Select to obtain a candidate set 116 // of channels to attempt to open. 117 needMore := fundsFraction < h.allocation 118 if !needMore { 119 return 0, 0 120 } 121 122 // Now that we know we need more funds, we'll compute the amount of 123 // additional funds we should allocate towards channels. 124 targetAllocation := dcrutil.Amount(float64(totalFunds) * h.allocation) 125 fundsAvailable := targetAllocation - totalChanAllocation 126 return fundsAvailable, numAdditionalChans 127 } 128 129 // MaxPendingOpens returns the maximum number of pending channel establishment 130 // goroutines that can be lingering. We cap this value in order to control the 131 // level of parallelism caused by the autopilot agent. 132 // 133 // Note: part of the AgentConstraints interface. 134 func (h *agentConstraints) MaxPendingOpens() uint16 { 135 return h.maxPendingOpens 136 } 137 138 // MinChanSize returns the smallest channel that the autopilot agent should 139 // create. 140 // 141 // Note: part of the AgentConstraints interface. 142 func (h *agentConstraints) MinChanSize() dcrutil.Amount { 143 return h.minChanSize 144 } 145 146 // MaxChanSize returns largest channel that the autopilot agent should create. 147 // 148 // Note: part of the AgentConstraints interface. 149 func (h *agentConstraints) MaxChanSize() dcrutil.Amount { 150 return h.maxChanSize 151 }