htlcswitch: allow overpaying for incoming payments

In this commit, we relax the constraints on accepting an exit hop
payment a bit. We'll now accept any incoming payment that _at least_
pays the invoice amount. This puts us further inline with the
specification, which recommends that nodes accept overpayment by a
certain margin.

Fixes #1002.
This commit is contained in:
Olaoluwa Osuntokun 2018-04-02 15:58:47 -07:00
parent d82f67cc1d
commit 5984cbd4ff
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21
2 changed files with 85 additions and 2 deletions

@ -1962,7 +1962,7 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
// they wish to send. So since we expect the htlc to
// have a different amount, we should not fail.
if !l.cfg.DebugHTLC && invoice.Terms.Value > 0 &&
fwdInfo.AmountToForward != invoice.Terms.Value {
fwdInfo.AmountToForward < invoice.Terms.Value {
log.Errorf("Onion payload of incoming htlc(%x) "+
"has incorrect value: expected %v, "+

@ -3026,4 +3026,87 @@ func TestChannelLinkAcceptDuplicatePayment(t *testing.T) {
}
}
// TODO(roasbeef): add test for re-sending after hodl mode, to settle any lingering
// TestChannelLinkAcceptOverpay tests that if we create an invoice for sender,
// and the sender sends *more* than specified in the invoice, then we'll still
// accept it and settle as normal.
func TestChannelLinkAcceptOverpay(t *testing.T) {
t.Parallel()
// First, we'll create our traditional three hop network. We'll only be
// interacting with and asserting the state of two of the end points
// for this test.
channels, cleanUp, _, err := createClusterChannels(
btcutil.SatoshiPerBitcoin*3,
btcutil.SatoshiPerBitcoin*5)
if err != nil {
t.Fatalf("unable to create channel: %v", err)
}
defer cleanUp()
n := newThreeHopNetwork(t, channels.aliceToBob, channels.bobToAlice,
channels.bobToCarol, channels.carolToBob, testStartingHeight)
if err := n.start(); err != nil {
t.Fatalf("unable to start three hop network: %v", err)
}
defer n.stop()
carolBandwidthBefore := n.carolChannelLink.Bandwidth()
firstBobBandwidthBefore := n.firstBobChannelLink.Bandwidth()
secondBobBandwidthBefore := n.secondBobChannelLink.Bandwidth()
aliceBandwidthBefore := n.aliceChannelLink.Bandwidth()
// We'll request a route to send 10k satoshis via Alice -> Bob ->
// Carol.
amount := lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin)
htlcAmt, totalTimelock, hops := generateHops(
amount, testStartingHeight,
n.firstBobChannelLink, n.carolChannelLink,
)
// When we actually go to send the payment, we'll actually create an
// invoice at Carol for only half of this amount.
receiver := n.carolServer
rhash, err := n.makePayment(
n.aliceServer, n.carolServer, n.bobServer.PubKey(),
hops, amount/2, htlcAmt, totalTimelock,
).Wait(30 * time.Second)
if err != nil {
t.Fatalf("unable to send payment: %v", err)
}
time.Sleep(100 * time.Millisecond)
// Even though we sent 2x what was asked for, Carol should still have
// accepted the payment and marked it as settled.
invoice, err := receiver.registry.LookupInvoice(rhash)
if err != nil {
t.Fatalf("unable to get invoice: %v", err)
}
if !invoice.Terms.Settled {
t.Fatal("carol invoice haven't been settled")
}
expectedAliceBandwidth := aliceBandwidthBefore - htlcAmt
if expectedAliceBandwidth != n.aliceChannelLink.Bandwidth() {
t.Fatalf("channel bandwidth incorrect: expected %v, got %v",
expectedAliceBandwidth, n.aliceChannelLink.Bandwidth())
}
expectedBobBandwidth1 := firstBobBandwidthBefore + htlcAmt
if expectedBobBandwidth1 != n.firstBobChannelLink.Bandwidth() {
t.Fatalf("channel bandwidth incorrect: expected %v, got %v",
expectedBobBandwidth1, n.firstBobChannelLink.Bandwidth())
}
expectedBobBandwidth2 := secondBobBandwidthBefore - amount
if expectedBobBandwidth2 != n.secondBobChannelLink.Bandwidth() {
t.Fatalf("channel bandwidth incorrect: expected %v, got %v",
expectedBobBandwidth2, n.secondBobChannelLink.Bandwidth())
}
expectedCarolBandwidth := carolBandwidthBefore + amount
if expectedCarolBandwidth != n.carolChannelLink.Bandwidth() {
t.Fatalf("channel bandwidth incorrect: expected %v, got %v",
expectedCarolBandwidth, n.carolChannelLink.Bandwidth())
}
}