funding: properly verify and apply channel constraints during funding flow

This commit implements some missing functionality as we’ll now properly
validate and generate the various channel flow control constraints
during initial channel funding.

With this commit, we take an additional step towards full spec
compliance as we’ll now properly send over the required channel
reservation, max HTLC’s, and other parameters during the funding flow.

When processing the desired parameters by the remote party, if we think
they’re unreasonable, then we’ll send an Error message and end the
funding flow.
This commit is contained in:
Olaoluwa Osuntokun 2017-09-12 18:07:43 +02:00
parent 6e6b5ac9af
commit 769abb87ea
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21

@ -693,8 +693,6 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
return
}
// TODO(roasbeef): validate sanity of all params sent
// TODO(roasbeef): error if funding flow already ongoing
fndgLog.Infof("Recv'd fundingRequest(amt=%v, push=%v, delay=%v, "+
"pendingId=%x) from peer(%x)", amt, msg.PushAmount,
@ -731,7 +729,18 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
// We'll also validate and apply all the constraints the initiating
// party is attempting to dictate for our commitment transaction.
reservation.RequireLocalDelay(msg.CsvDelay)
err = reservation.CommitConstraints(
uint16(msg.CsvDelay), msg.MaxAcceptedHTLCs,
msg.MaxValueInFlight, msg.ChannelReserve,
)
if err != nil {
f.failFundingFlow(
fmsg.peerAddress.IdentityKey, fmsg.msg.PendingChannelID,
[]byte(fmt.Sprintf("Unacceptable channel "+
"constraints: %v", err)),
)
return
}
fndgLog.Infof("Requiring %v confirmations for pendingChan(%x): "+
"amt=%v, push_amt=%v", numConfsReq, fmsg.msg.PendingChannelID,
@ -756,6 +765,9 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
// delay we require given the total amount of funds within the channel.
remoteCsvDelay := f.cfg.RequiredRemoteDelay(amt)
// We'll also generate our required constraints for the remote party,
chanReserve, maxValue, maxHtlcs := reservation.RemoteChanConstraints()
// With our parameters set, we'll now process their contribution so we
// can move the funding workflow ahead.
remoteContribution := &lnwallet.ChannelContribution{
@ -764,10 +776,10 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
ChannelConfig: &channeldb.ChannelConfig{
ChannelConstraints: channeldb.ChannelConstraints{
DustLimit: msg.DustLimit,
MaxPendingAmount: msg.MaxValueInFlight,
ChanReserve: msg.ChannelReserve,
MaxPendingAmount: maxValue,
ChanReserve: chanReserve,
MinHTLC: msg.HtlcMinimum,
MaxAcceptedHtlcs: msg.MaxAcceptedHTLCs,
MaxAcceptedHtlcs: maxHtlcs,
},
CsvDelay: remoteCsvDelay,
MultiSigKey: copyPubKey(msg.FundingKey),
@ -787,6 +799,8 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
fndgLog.Infof("Sending fundingResp for pendingID(%x)",
msg.PendingChannelID)
fndgLog.Debugf("Remote party accepted commitment constraints: %v",
spew.Sdump(remoteContribution.ChannelConfig.ChannelConstraints))
// With the initiator's contribution recorded, respond with our
// contribution in the next message of the workflow.
@ -794,11 +808,12 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
fundingAccept := lnwire.AcceptChannel{
PendingChannelID: msg.PendingChannelID,
DustLimit: ourContribution.DustLimit,
MaxValueInFlight: ourContribution.MaxPendingAmount,
ChannelReserve: ourContribution.ChanReserve,
MaxValueInFlight: maxValue,
ChannelReserve: chanReserve,
MinAcceptDepth: uint32(numConfsReq),
HtlcMinimum: ourContribution.MinHTLC,
CsvDelay: uint16(remoteCsvDelay),
MaxAcceptedHTLCs: maxHtlcs,
FundingKey: ourContribution.MultiSigKey,
RevocationPoint: ourContribution.RevocationBasePoint,
PaymentPoint: ourContribution.PaymentBasePoint,
@ -840,10 +855,26 @@ func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
fndgLog.Infof("Recv'd fundingResponse for pendingID(%x)", pendingChanID)
// We'll also specify the responder's preference for the number of
// required confirmations, and also the CSV delay that they specify for
// us within the reservation itself.
// required confirmations, and also the set of channel constraints
// they've specified for commitment states we can create.
resCtx.reservation.SetNumConfsRequired(uint16(msg.MinAcceptDepth))
resCtx.reservation.RequireLocalDelay(uint16(msg.CsvDelay))
err = resCtx.reservation.CommitConstraints(
uint16(msg.CsvDelay), msg.MaxAcceptedHTLCs,
msg.MaxValueInFlight, msg.ChannelReserve,
)
if err != nil {
f.failFundingFlow(
fmsg.peerAddress.IdentityKey, fmsg.msg.PendingChannelID,
[]byte(fmt.Sprintf("Unacceptable channel "+
"constraints: %v", err)),
)
return
}
// As they've accepted our channel constraints, we'll regenerate them
// here so we can properly commit their accepted constraints to the
// reservation.
chanReserve, maxValue, maxHtlcs := resCtx.reservation.RemoteChanConstraints()
// The remote node has responded with their portion of the channel
// contribution. At this point, we can process their contribution which
@ -854,10 +885,10 @@ func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
ChannelConfig: &channeldb.ChannelConfig{
ChannelConstraints: channeldb.ChannelConstraints{
DustLimit: msg.DustLimit,
MaxPendingAmount: msg.MaxValueInFlight,
ChanReserve: msg.ChannelReserve,
MaxPendingAmount: maxValue,
ChanReserve: chanReserve,
MinHTLC: msg.HtlcMinimum,
MaxAcceptedHtlcs: msg.MaxAcceptedHTLCs,
MaxAcceptedHtlcs: maxHtlcs,
},
MultiSigKey: copyPubKey(msg.FundingKey),
RevocationBasePoint: copyPubKey(msg.RevocationPoint),
@ -878,6 +909,8 @@ func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
fndgLog.Infof("pendingChan(%x): remote party proposes num_confs=%v, "+
"csv_delay=%v", pendingChanID, msg.MinAcceptDepth, msg.CsvDelay)
fndgLog.Debugf("Remote party accepted commitment constraints: %v",
spew.Sdump(remoteContribution.ChannelConfig.ChannelConstraints))
// Now that we have their contribution, we can extract, then send over
// both the funding out point and our signature for their version of
@ -1828,12 +1861,15 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
// delay we require given the total amount of funds within the channel.
remoteCsvDelay := f.cfg.RequiredRemoteDelay(capacity)
// TODO(roasbeef): require remote delay?
// Once the reservation has been created, and indexed, queue a funding
// request to the remote peer, kicking off the funding workflow.
ourContribution := reservation.OurContribution()
// Finally, we'll use the current value of the channels and our default
// policy to determine of required commitment constraints for the
// remote party.
chanReserve, maxValue, maxHtlcs := reservation.RemoteChanConstraints()
fndgLog.Infof("Starting funding workflow with %v for pendingID(%x)",
msg.peerAddress.Address, chanID)
@ -1843,12 +1879,12 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
FundingAmount: capacity,
PushAmount: msg.pushAmt,
DustLimit: ourContribution.DustLimit,
MaxValueInFlight: ourContribution.MaxPendingAmount,
ChannelReserve: ourContribution.ChanReserve,
MaxValueInFlight: maxValue,
ChannelReserve: chanReserve,
HtlcMinimum: ourContribution.MinHTLC,
FeePerKiloWeight: uint32(feePerKw),
CsvDelay: uint16(remoteCsvDelay),
MaxAcceptedHTLCs: ourContribution.MaxAcceptedHtlcs,
MaxAcceptedHTLCs: maxHtlcs,
FundingKey: ourContribution.MultiSigKey,
RevocationPoint: ourContribution.RevocationBasePoint,
PaymentPoint: ourContribution.PaymentBasePoint,