diff --git a/itest/lnd_amp_test.go b/itest/lnd_amp_test.go index a76aedd99..e3b1898da 100644 --- a/itest/lnd_amp_test.go +++ b/itest/lnd_amp_test.go @@ -60,12 +60,12 @@ func testSendPaymentAMPInvoiceCase(ht *lntest.HarnessTest, // \__ Dave ____/ // mppReq := &mppOpenChannelRequest{ - amtAliceCarol: 235000, - amtAliceDave: 135000, - amtCarolBob: 135000, - amtCarolEve: 135000, - amtDaveBob: 135000, - amtEveBob: 135000, + amtAliceCarol: 285000, + amtAliceDave: 155000, + amtCarolBob: 200000, + amtCarolEve: 155000, + amtDaveBob: 155000, + amtEveBob: 155000, } mts.openChannels(mppReq) chanPointAliceDave := mts.channelPoints[1] @@ -368,12 +368,12 @@ func testSendPaymentAMP(ht *lntest.HarnessTest) { // \__ Dave ____/ // mppReq := &mppOpenChannelRequest{ - amtAliceCarol: 235000, - amtAliceDave: 135000, - amtCarolBob: 135000, - amtCarolEve: 135000, - amtDaveBob: 135000, - amtEveBob: 135000, + amtAliceCarol: 285000, + amtAliceDave: 155000, + amtCarolBob: 200000, + amtCarolEve: 155000, + amtDaveBob: 155000, + amtEveBob: 155000, } mts.openChannels(mppReq) chanPointAliceDave := mts.channelPoints[1] diff --git a/itest/lnd_multi-hop-error-propagation_test.go b/itest/lnd_multi-hop-error-propagation_test.go index 3941accb0..6bd3c1568 100644 --- a/itest/lnd_multi-hop-error-propagation_test.go +++ b/itest/lnd_multi-hop-error-propagation_test.go @@ -1,8 +1,6 @@ package itest import ( - "math" - "github.com/lightningnetwork/lnd/funding" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc" @@ -240,55 +238,42 @@ func testHtlcErrorPropagation(ht *lntest.HarnessTest) { // // To do so, we'll push most of the funds in the channel over to // Alice's side, leaving on 10k satoshis of available balance for bob. - // There's a max payment amount, so we'll have to do this - // incrementally. chanReserve := int64(chanAmt / 100) - amtToSend := int64(chanAmt) - chanReserve - 20000 - amtSent := int64(0) - for amtSent != amtToSend { - // We'll send in chunks of the max payment amount. If we're - // about to send too much, then we'll only send the amount - // remaining. - toSend := int64(math.MaxUint32) - if toSend+amtSent > amtToSend { - toSend = amtToSend - amtSent - } + feeBuffer := lntest.CalcStaticFeeBuffer(cType, 0) + amtToSend := int64(chanAmt) - chanReserve - int64(feeBuffer) - 10000 - invoiceReq = &lnrpc.Invoice{ - Value: toSend, - } - carolInvoice2 := carol.RPC.AddInvoice(invoiceReq) - - req := &routerrpc.SendPaymentRequest{ - PaymentRequest: carolInvoice2.PaymentRequest, - TimeoutSeconds: 60, - FeeLimitMsat: noFeeLimitMsat, - MaxParts: 1, - } - ht.SendPaymentAndAssertStatus(bob, req, lnrpc.Payment_SUCCEEDED) - - // For each send bob makes, we need to check that bob has a - // forward and settle event for his send, and carol has a - // settle event and a final htlc event for her receive. - ht.AssertHtlcEventTypes( - bobEvents, routerrpc.HtlcEvent_SEND, - lntest.HtlcEventForward, - ) - ht.AssertHtlcEventTypes( - bobEvents, routerrpc.HtlcEvent_SEND, - lntest.HtlcEventSettle, - ) - ht.AssertHtlcEventTypes( - carolEvents, routerrpc.HtlcEvent_RECEIVE, - lntest.HtlcEventSettle, - ) - ht.AssertHtlcEventTypes( - carolEvents, routerrpc.HtlcEvent_UNKNOWN, - lntest.HtlcEventFinal, - ) - - amtSent += toSend + invoiceReq = &lnrpc.Invoice{ + Value: amtToSend, } + carolInvoice2 := carol.RPC.AddInvoice(invoiceReq) + + req := &routerrpc.SendPaymentRequest{ + PaymentRequest: carolInvoice2.PaymentRequest, + TimeoutSeconds: 60, + FeeLimitMsat: noFeeLimitMsat, + MaxParts: 1, + } + ht.SendPaymentAndAssertStatus(bob, req, lnrpc.Payment_SUCCEEDED) + + // We need to check that bob has a forward and settle event for his + // send, and carol has a settle event and a final htlc event for her + // receive. + ht.AssertHtlcEventTypes( + bobEvents, routerrpc.HtlcEvent_SEND, + lntest.HtlcEventForward, + ) + ht.AssertHtlcEventTypes( + bobEvents, routerrpc.HtlcEvent_SEND, + lntest.HtlcEventSettle, + ) + ht.AssertHtlcEventTypes( + carolEvents, routerrpc.HtlcEvent_RECEIVE, + lntest.HtlcEventSettle, + ) + ht.AssertHtlcEventTypes( + carolEvents, routerrpc.HtlcEvent_UNKNOWN, + lntest.HtlcEventFinal, + ) // At this point, Alice has 50mil satoshis on her side of the channel, // but Bob only has 10k available on his side of the channel. So a @@ -347,7 +332,7 @@ func testHtlcErrorPropagation(ht *lntest.HarnessTest) { // Reset mission control to forget the temporary channel failure above. alice.RPC.ResetMissionControl() - req := &routerrpc.SendPaymentRequest{ + req = &routerrpc.SendPaymentRequest{ PaymentRequest: carolInvoice.PaymentRequest, TimeoutSeconds: 60, FeeLimitMsat: noFeeLimitMsat, diff --git a/itest/lnd_send_multi_path_payment_test.go b/itest/lnd_send_multi_path_payment_test.go index 143cf496d..10ad3f4a2 100644 --- a/itest/lnd_send_multi_path_payment_test.go +++ b/itest/lnd_send_multi_path_payment_test.go @@ -28,12 +28,12 @@ func testSendMultiPathPayment(ht *lntest.HarnessTest) { // \__ Dave ____/ // req := &mppOpenChannelRequest{ - amtAliceCarol: 235000, - amtAliceDave: 135000, - amtCarolBob: 135000, - amtCarolEve: 135000, - amtDaveBob: 135000, - amtEveBob: 135000, + amtAliceCarol: 285000, + amtAliceDave: 155000, + amtCarolBob: 200000, + amtCarolEve: 155000, + amtDaveBob: 155000, + amtEveBob: 155000, } mts.openChannels(req) chanPointAliceDave := mts.channelPoints[1] diff --git a/lntest/utils.go b/lntest/utils.go index 5ac6c355e..660c42ef9 100644 --- a/lntest/utils.go +++ b/lntest/utils.go @@ -226,3 +226,49 @@ func CalculateMaxHtlc(chanCap btcutil.Amount) uint64 { return uint64(max) } + +// CalcStaticFeeBuffer calculates appropriate fee buffer which must be taken +// into account when sending htlcs. +func CalcStaticFeeBuffer(c lnrpc.CommitmentType, numHTLCs int) btcutil.Amount { + //nolint:lll + const ( + htlcWeight = input.HTLCWeight + defaultSatPerVByte = lnwallet.DefaultAnchorsCommitMaxFeeRateSatPerVByte + scale = 1000 + ) + + var ( + commitWeight = input.CommitWeight + feePerKw = chainfee.SatPerKWeight(DefaultFeeRateSatPerKw) + ) + + switch { + // The taproot commitment type has the extra anchor outputs, but also a + // smaller witness field (will just be a normal key spend), so we need + // to account for that here as well. + case CommitTypeHasTaproot(c): + feePerKw = chainfee.SatPerKVByte( + defaultSatPerVByte * scale, + ).FeePerKWeight() + + commitWeight = input.TaprootCommitWeight + + // The anchor commitment type is slightly heavier, and we must also add + // the value of the two anchors to the resulting fee the initiator + // pays. In addition the fee rate is capped at 10 sat/vbyte for anchor + // channels. + case CommitTypeHasAnchors(c): + feePerKw = chainfee.SatPerKVByte( + defaultSatPerVByte * scale, + ).FeePerKWeight() + commitWeight = input.AnchorCommitWeight + } + + // Account for the HTLC which will be required when sending an htlc. + numHTLCs++ + feeBuffer := lnwallet.CalcFeeBuffer( + feePerKw, int64(commitWeight+numHTLCs*htlcWeight), + ) + + return feeBuffer.ToSatoshis() +}