github.com/decred/dcrlnd@v0.7.6/chanacceptor/merge.go (about)

     1  package chanacceptor
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  
     7  	"github.com/decred/dcrd/dcrutil/v4"
     8  	"github.com/decred/dcrlnd/lnwire"
     9  )
    10  
    11  const (
    12  	// We use field names in our errors for more readable errors. Create
    13  	// consts for them here so that we can exactly match in our unit tests.
    14  	fieldCSV             = "csv delay"
    15  	fieldHtlcLimit       = "htlc limit"
    16  	fieldMinDep          = "min depth"
    17  	fieldReserve         = "reserve"
    18  	fieldMinIn           = "min htlc in"
    19  	fieldInFlightTotal   = "in flight total"
    20  	fieldUpfrontShutdown = "upfront shutdown"
    21  )
    22  
    23  // fieldMismatchError returns a merge error for a named field when we get two
    24  // channel acceptor responses which have different values set.
    25  func fieldMismatchError(name string, current, new interface{}) error {
    26  	return fmt.Errorf("multiple values set for: %v, %v and %v",
    27  		name, current, new)
    28  }
    29  
    30  // mergeInt64 merges two int64 values, failing if they have different non-zero
    31  // values.
    32  func mergeInt64(name string, current, new int64) (int64, error) {
    33  	switch {
    34  	case current == 0:
    35  		return new, nil
    36  
    37  	case new == 0:
    38  		return current, nil
    39  
    40  	case current != new:
    41  		return 0, fieldMismatchError(name, current, new)
    42  
    43  	default:
    44  		return new, nil
    45  	}
    46  }
    47  
    48  // mergeMilliatoms merges two msat values, failing if they have different
    49  // non-zero values.
    50  func mergeMilliatoms(name string, current,
    51  	new lnwire.MilliAtom) (lnwire.MilliAtom, error) {
    52  
    53  	switch {
    54  	case current == 0:
    55  		return new, nil
    56  
    57  	case new == 0:
    58  		return current, nil
    59  
    60  	case current != new:
    61  		return 0, fieldMismatchError(name, current, new)
    62  
    63  	default:
    64  		return new, nil
    65  	}
    66  }
    67  
    68  // mergeDeliveryAddress merges two delivery address values, failing if they have
    69  // different non-zero values.
    70  func mergeDeliveryAddress(name string, current,
    71  	new lnwire.DeliveryAddress) (lnwire.DeliveryAddress, error) {
    72  
    73  	switch {
    74  	case current == nil:
    75  		return new, nil
    76  
    77  	case new == nil:
    78  		return current, nil
    79  
    80  	case !bytes.Equal(current, new):
    81  		return nil, fieldMismatchError(name, current, new)
    82  
    83  	default:
    84  		return new, nil
    85  	}
    86  }
    87  
    88  // mergeResponse takes two channel accept responses, and attempts to merge their
    89  // fields, failing if any fields conflict (are non-zero and not equal). It
    90  // returns a new response that has all the merged fields in it.
    91  func mergeResponse(current, new ChannelAcceptResponse) (ChannelAcceptResponse,
    92  	error) {
    93  
    94  	csv, err := mergeInt64(
    95  		fieldCSV, int64(current.CSVDelay), int64(new.CSVDelay),
    96  	)
    97  	if err != nil {
    98  		return current, err
    99  	}
   100  	current.CSVDelay = uint16(csv)
   101  
   102  	htlcLimit, err := mergeInt64(
   103  		fieldHtlcLimit, int64(current.HtlcLimit),
   104  		int64(new.HtlcLimit),
   105  	)
   106  	if err != nil {
   107  		return current, err
   108  	}
   109  	current.HtlcLimit = uint16(htlcLimit)
   110  
   111  	minDepth, err := mergeInt64(
   112  		fieldMinDep, int64(current.MinAcceptDepth),
   113  		int64(new.MinAcceptDepth),
   114  	)
   115  	if err != nil {
   116  		return current, err
   117  	}
   118  	current.MinAcceptDepth = uint16(minDepth)
   119  
   120  	reserve, err := mergeInt64(
   121  		fieldReserve, int64(current.Reserve), int64(new.Reserve),
   122  	)
   123  	if err != nil {
   124  		return current, err
   125  	}
   126  	current.Reserve = dcrutil.Amount(reserve)
   127  
   128  	current.MinHtlcIn, err = mergeMilliatoms(
   129  		fieldMinIn, current.MinHtlcIn, new.MinHtlcIn,
   130  	)
   131  	if err != nil {
   132  		return current, err
   133  	}
   134  
   135  	current.InFlightTotal, err = mergeMilliatoms(
   136  		fieldInFlightTotal, current.InFlightTotal,
   137  		new.InFlightTotal,
   138  	)
   139  	if err != nil {
   140  		return current, err
   141  	}
   142  
   143  	current.UpfrontShutdown, err = mergeDeliveryAddress(
   144  		fieldUpfrontShutdown, current.UpfrontShutdown,
   145  		new.UpfrontShutdown,
   146  	)
   147  	if err != nil {
   148  		return current, err
   149  	}
   150  
   151  	return current, nil
   152  }