153 lines
3.5 KiB
Go
153 lines
3.5 KiB
Go
|
package chanacceptor
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"fmt"
|
||
|
|
||
|
"github.com/btcsuite/btcutil"
|
||
|
"github.com/lightningnetwork/lnd/lnwire"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
// We use field names in our errors for more readable errors. Create
|
||
|
// consts for them here so that we can exactly match in our unit tests.
|
||
|
fieldCSV = "csv delay"
|
||
|
fieldHtlcLimit = "htlc limit"
|
||
|
fieldMinDep = "min depth"
|
||
|
fieldReserve = "reserve"
|
||
|
fieldMinIn = "min htlc in"
|
||
|
fieldInFlightTotal = "in flight total"
|
||
|
fieldUpfrontShutdown = "upfront shutdown"
|
||
|
)
|
||
|
|
||
|
// fieldMismatchError returns a merge error for a named field when we get two
|
||
|
// channel acceptor responses which have different values set.
|
||
|
func fieldMismatchError(name string, current, new interface{}) error {
|
||
|
return fmt.Errorf("multiple values set for: %v, %v and %v",
|
||
|
name, current, new)
|
||
|
}
|
||
|
|
||
|
// mergeInt64 merges two int64 values, failing if they have different non-zero
|
||
|
// values.
|
||
|
func mergeInt64(name string, current, new int64) (int64, error) {
|
||
|
switch {
|
||
|
case current == 0:
|
||
|
return new, nil
|
||
|
|
||
|
case new == 0:
|
||
|
return current, nil
|
||
|
|
||
|
case current != new:
|
||
|
return 0, fieldMismatchError(name, current, new)
|
||
|
|
||
|
default:
|
||
|
return new, nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// mergeMillisatoshi merges two msat values, failing if they have different
|
||
|
// non-zero values.
|
||
|
func mergeMillisatoshi(name string, current,
|
||
|
new lnwire.MilliSatoshi) (lnwire.MilliSatoshi, error) {
|
||
|
|
||
|
switch {
|
||
|
case current == 0:
|
||
|
return new, nil
|
||
|
|
||
|
case new == 0:
|
||
|
return current, nil
|
||
|
|
||
|
case current != new:
|
||
|
return 0, fieldMismatchError(name, current, new)
|
||
|
|
||
|
default:
|
||
|
return new, nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// mergeDeliveryAddress merges two delivery address values, failing if they have
|
||
|
// different non-zero values.
|
||
|
func mergeDeliveryAddress(name string, current,
|
||
|
new lnwire.DeliveryAddress) (lnwire.DeliveryAddress, error) {
|
||
|
|
||
|
switch {
|
||
|
case current == nil:
|
||
|
return new, nil
|
||
|
|
||
|
case new == nil:
|
||
|
return current, nil
|
||
|
|
||
|
case !bytes.Equal(current, new):
|
||
|
return nil, fieldMismatchError(name, current, new)
|
||
|
|
||
|
default:
|
||
|
return new, nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// mergeResponse takes two channel accept responses, and attempts to merge their
|
||
|
// fields, failing if any fields conflict (are non-zero and not equal). It
|
||
|
// returns a new response that has all the merged fields in it.
|
||
|
func mergeResponse(current, new ChannelAcceptResponse) (ChannelAcceptResponse,
|
||
|
error) {
|
||
|
|
||
|
csv, err := mergeInt64(
|
||
|
fieldCSV, int64(current.CSVDelay), int64(new.CSVDelay),
|
||
|
)
|
||
|
if err != nil {
|
||
|
return current, err
|
||
|
}
|
||
|
current.CSVDelay = uint16(csv)
|
||
|
|
||
|
htlcLimit, err := mergeInt64(
|
||
|
fieldHtlcLimit, int64(current.HtlcLimit),
|
||
|
int64(new.HtlcLimit),
|
||
|
)
|
||
|
if err != nil {
|
||
|
return current, err
|
||
|
}
|
||
|
current.HtlcLimit = uint16(htlcLimit)
|
||
|
|
||
|
minDepth, err := mergeInt64(
|
||
|
fieldMinDep, int64(current.MinAcceptDepth),
|
||
|
int64(new.MinAcceptDepth),
|
||
|
)
|
||
|
if err != nil {
|
||
|
return current, err
|
||
|
}
|
||
|
current.MinAcceptDepth = uint16(minDepth)
|
||
|
|
||
|
reserve, err := mergeInt64(
|
||
|
fieldReserve, int64(current.Reserve), int64(new.Reserve),
|
||
|
)
|
||
|
if err != nil {
|
||
|
return current, err
|
||
|
}
|
||
|
current.Reserve = btcutil.Amount(reserve)
|
||
|
|
||
|
current.MinHtlcIn, err = mergeMillisatoshi(
|
||
|
fieldMinIn, current.MinHtlcIn, new.MinHtlcIn,
|
||
|
)
|
||
|
if err != nil {
|
||
|
return current, err
|
||
|
}
|
||
|
|
||
|
current.InFlightTotal, err = mergeMillisatoshi(
|
||
|
fieldInFlightTotal, current.InFlightTotal,
|
||
|
new.InFlightTotal,
|
||
|
)
|
||
|
if err != nil {
|
||
|
return current, err
|
||
|
}
|
||
|
|
||
|
current.UpfrontShutdown, err = mergeDeliveryAddress(
|
||
|
fieldUpfrontShutdown, current.UpfrontShutdown,
|
||
|
new.UpfrontShutdown,
|
||
|
)
|
||
|
if err != nil {
|
||
|
return current, err
|
||
|
}
|
||
|
|
||
|
return current, nil
|
||
|
}
|