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