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 }