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  }