funding+lnwallet: validate ChannelReserve is above DustLimit

This is necessary and is implied by BOLT#02. Both ChannelReserve
parameters should be above both DustLimit parameters. Otherwise,
it is possible for one side to have nothing at stake.
This commit is contained in:
eugene committed 2021-09-29 13:33:12 -04:00
1 parent fdcd726f9a
commit 950063840a
5 files changed
+81 -14

No files matched your search

+34 -2
View File
@@ -394,7 +394,7 @@ func (r *ChannelReservation) SetNumConfsRequired(numConfs uint16) {
// will also attempt to verify the constraints for sanity, returning an error
// if the parameters are seemed unsound.
func (r *ChannelReservation) CommitConstraints(c *channeldb.ChannelConstraints,
maxLocalCSVDelay uint16) error {
maxLocalCSVDelay uint16, responder bool) error {
r.Lock()
defer r.Unlock()
@@ -409,6 +409,13 @@ func (r *ChannelReservation) CommitConstraints(c *channeldb.ChannelConstraints,
return ErrChanReserveTooSmall(c.ChanReserve, c.DustLimit)
}
// Validate against the maximum-sized witness script dust limit, and
// also ensure that the DustLimit is not too large.
maxWitnessLimit := DustLimitForSize(input.UnknownWitnessSize)
if c.DustLimit < maxWitnessLimit || c.DustLimit > 3*maxWitnessLimit {
return ErrInvalidDustLimit(c.DustLimit)
}
// Fail if we consider the channel reserve to be too large. We
// currently fail if it is greater than 20% of the channel capacity.
maxChanReserve := r.partialState.Capacity / 5
@@ -449,7 +456,7 @@ func (r *ChannelReservation) CommitConstraints(c *channeldb.ChannelConstraints,
// Our dust limit should always be less than or equal to our proposed
// channel reserve.
if r.ourContribution.DustLimit > c.ChanReserve {
if responder && r.ourContribution.DustLimit > c.ChanReserve {
r.ourContribution.DustLimit = c.ChanReserve
}
@@ -462,6 +469,31 @@ func (r *ChannelReservation) CommitConstraints(c *channeldb.ChannelConstraints,
return nil
}
// validateReserveBounds checks that both ChannelReserve values are above both
// DustLimit values. This not only avoids stuck channels, but is also mandated
// by BOLT#02 even if it's not explicit. This returns true if the bounds are
// valid. This function should be called with the lock held.
func (r *ChannelReservation) validateReserveBounds() bool {
ourDustLimit := r.ourContribution.DustLimit
ourRequiredReserve := r.ourContribution.ChanReserve
theirDustLimit := r.theirContribution.DustLimit
theirRequiredReserve := r.theirContribution.ChanReserve
// We take the smaller of the two ChannelReserves and compare it
// against the larger of the two DustLimits.
minChanReserve := ourRequiredReserve
if minChanReserve > theirRequiredReserve {
minChanReserve = theirRequiredReserve
}
maxDustLimit := ourDustLimit
if maxDustLimit < theirDustLimit {
maxDustLimit = theirDustLimit
}
return minChanReserve >= maxDustLimit
}
// OurContribution returns the wallet's fully populated contribution to the
// pending payment channel. See 'ChannelContribution' for further details
// regarding the contents of a contribution.