htlcswitch: implement strict forwarding for locally dispatched payments
In this commit, we address an issue that could arise when using the SendToRoute RPC. In this RPC, we specify the exact hops that a payment should take. However, within the switch, we would set a constraint for the first hop to be any hop as long as the first peer was at the end of it. This would cause discrepancies when attempting to use the RPC as the payment would actually go through another hop with the same peer. We fix this by explicitly specifying the channel ID of the first hop. Fixes #1500. Fixes #1515.
This commit is contained in:
parent
8baf172614
commit
7535371238
@ -215,9 +215,11 @@ func TestChannelLinkSingleHopPayment(t *testing.T) {
|
|||||||
// * alice<->bob commitment state to be updated.
|
// * alice<->bob commitment state to be updated.
|
||||||
// * user notification to be sent.
|
// * user notification to be sent.
|
||||||
receiver := n.bobServer
|
receiver := n.bobServer
|
||||||
rhash, err := n.makePayment(n.aliceServer, receiver,
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
n.bobServer.PubKey(), hops, amount, htlcAmt,
|
rhash, err := n.makePayment(
|
||||||
totalTimelock).Wait(30 * time.Second)
|
n.aliceServer, receiver, firstHop, hops, amount, htlcAmt,
|
||||||
|
totalTimelock,
|
||||||
|
).Wait(30 * time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to make the payment: %v", err)
|
t.Fatalf("unable to make the payment: %v", err)
|
||||||
}
|
}
|
||||||
@ -309,9 +311,11 @@ func TestChannelLinkBidirectionalOneHopPayments(t *testing.T) {
|
|||||||
sender: "alice",
|
sender: "alice",
|
||||||
}
|
}
|
||||||
|
|
||||||
_, r.err = n.makePayment(n.aliceServer, n.bobServer,
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
n.bobServer.PubKey(), hopsForwards, amt, htlcAmt,
|
_, r.err = n.makePayment(
|
||||||
totalTimelock).Wait(5 * time.Minute)
|
n.aliceServer, n.bobServer, firstHop,
|
||||||
|
hopsForwards, amt, htlcAmt, totalTimelock,
|
||||||
|
).Wait(5 * time.Minute)
|
||||||
resultChan <- r
|
resultChan <- r
|
||||||
}(i)
|
}(i)
|
||||||
}
|
}
|
||||||
@ -324,9 +328,11 @@ func TestChannelLinkBidirectionalOneHopPayments(t *testing.T) {
|
|||||||
sender: "bob",
|
sender: "bob",
|
||||||
}
|
}
|
||||||
|
|
||||||
_, r.err = n.makePayment(n.bobServer, n.aliceServer,
|
firstHop := n.aliceChannelLink.ShortChanID()
|
||||||
n.aliceServer.PubKey(), hopsBackwards, amt, htlcAmt,
|
_, r.err = n.makePayment(
|
||||||
totalTimelock).Wait(5 * time.Minute)
|
n.bobServer, n.aliceServer, firstHop,
|
||||||
|
hopsBackwards, amt, htlcAmt, totalTimelock,
|
||||||
|
).Wait(5 * time.Minute)
|
||||||
resultChan <- r
|
resultChan <- r
|
||||||
}(i)
|
}(i)
|
||||||
}
|
}
|
||||||
@ -442,9 +448,11 @@ func TestChannelLinkMultiHopPayment(t *testing.T) {
|
|||||||
// * Alice<->Bob commitment states to be updated.
|
// * Alice<->Bob commitment states to be updated.
|
||||||
// * user notification to be sent.
|
// * user notification to be sent.
|
||||||
receiver := n.carolServer
|
receiver := n.carolServer
|
||||||
rhash, err := n.makePayment(n.aliceServer, n.carolServer,
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
n.bobServer.PubKey(), hops, amount, htlcAmt,
|
rhash, err := n.makePayment(
|
||||||
totalTimelock).Wait(30 * time.Second)
|
n.aliceServer, n.carolServer, firstHop, hops, amount, htlcAmt,
|
||||||
|
totalTimelock,
|
||||||
|
).Wait(30 * time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to send payment: %v", err)
|
t.Fatalf("unable to send payment: %v", err)
|
||||||
}
|
}
|
||||||
@ -518,10 +526,11 @@ func TestExitNodeTimelockPayloadMismatch(t *testing.T) {
|
|||||||
// The proper value of the outgoing CLTV should be the policy set by
|
// The proper value of the outgoing CLTV should be the policy set by
|
||||||
// the receiving node, instead we set it to be a random value.
|
// the receiving node, instead we set it to be a random value.
|
||||||
hops[0].OutgoingCTLV = 500
|
hops[0].OutgoingCTLV = 500
|
||||||
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
_, err = n.makePayment(n.aliceServer, n.bobServer,
|
_, err = n.makePayment(
|
||||||
n.bobServer.PubKey(), hops, amount, htlcAmt,
|
n.aliceServer, n.bobServer, firstHop, hops, amount, htlcAmt,
|
||||||
htlcExpiry).Wait(30 * time.Second)
|
htlcExpiry,
|
||||||
|
).Wait(30 * time.Second)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("payment should have failed but didn't")
|
t.Fatalf("payment should have failed but didn't")
|
||||||
}
|
}
|
||||||
@ -570,10 +579,11 @@ func TestExitNodeAmountPayloadMismatch(t *testing.T) {
|
|||||||
// value of the amount to forward should be the amount that the
|
// value of the amount to forward should be the amount that the
|
||||||
// receiving node expects to receive.
|
// receiving node expects to receive.
|
||||||
hops[0].AmountToForward = 1
|
hops[0].AmountToForward = 1
|
||||||
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
_, err = n.makePayment(n.aliceServer, n.bobServer,
|
_, err = n.makePayment(
|
||||||
n.bobServer.PubKey(), hops, amount, htlcAmt,
|
n.aliceServer, n.bobServer, firstHop, hops, amount, htlcAmt,
|
||||||
htlcExpiry).Wait(30 * time.Second)
|
htlcExpiry,
|
||||||
|
).Wait(30 * time.Second)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("payment should have failed but didn't")
|
t.Fatalf("payment should have failed but didn't")
|
||||||
} else if err.Error() != lnwire.CodeIncorrectPaymentAmount.String() {
|
} else if err.Error() != lnwire.CodeIncorrectPaymentAmount.String() {
|
||||||
@ -617,9 +627,11 @@ func TestLinkForwardTimelockPolicyMismatch(t *testing.T) {
|
|||||||
|
|
||||||
// Next, we'll make the payment which'll send an HTLC with our
|
// Next, we'll make the payment which'll send an HTLC with our
|
||||||
// specified parameters to the first hop in the route.
|
// specified parameters to the first hop in the route.
|
||||||
_, err = n.makePayment(n.aliceServer, n.carolServer,
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
n.bobServer.PubKey(), hops, amount, htlcAmt,
|
_, err = n.makePayment(
|
||||||
htlcExpiry).Wait(30 * time.Second)
|
n.aliceServer, n.carolServer, firstHop, hops, amount, htlcAmt,
|
||||||
|
htlcExpiry,
|
||||||
|
).Wait(30 * time.Second)
|
||||||
|
|
||||||
// We should get an error, and that error should indicate that the HTLC
|
// We should get an error, and that error should indicate that the HTLC
|
||||||
// should be rejected due to a policy violation.
|
// should be rejected due to a policy violation.
|
||||||
@ -673,9 +685,11 @@ func TestLinkForwardFeePolicyMismatch(t *testing.T) {
|
|||||||
|
|
||||||
// Next, we'll make the payment which'll send an HTLC with our
|
// Next, we'll make the payment which'll send an HTLC with our
|
||||||
// specified parameters to the first hop in the route.
|
// specified parameters to the first hop in the route.
|
||||||
_, err = n.makePayment(n.aliceServer, n.bobServer,
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
n.bobServer.PubKey(), hops, amountNoFee, amountNoFee,
|
_, err = n.makePayment(
|
||||||
htlcExpiry).Wait(30 * time.Second)
|
n.aliceServer, n.bobServer, firstHop, hops, amountNoFee,
|
||||||
|
amountNoFee, htlcExpiry,
|
||||||
|
).Wait(30 * time.Second)
|
||||||
|
|
||||||
// We should get an error, and that error should indicate that the HTLC
|
// We should get an error, and that error should indicate that the HTLC
|
||||||
// should be rejected due to a policy violation.
|
// should be rejected due to a policy violation.
|
||||||
@ -729,9 +743,11 @@ func TestLinkForwardMinHTLCPolicyMismatch(t *testing.T) {
|
|||||||
|
|
||||||
// Next, we'll make the payment which'll send an HTLC with our
|
// Next, we'll make the payment which'll send an HTLC with our
|
||||||
// specified parameters to the first hop in the route.
|
// specified parameters to the first hop in the route.
|
||||||
_, err = n.makePayment(n.aliceServer, n.bobServer,
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
n.bobServer.PubKey(), hops, amountNoFee, htlcAmt,
|
_, err = n.makePayment(
|
||||||
htlcExpiry).Wait(30 * time.Second)
|
n.aliceServer, n.bobServer, firstHop, hops, amountNoFee,
|
||||||
|
htlcAmt, htlcExpiry,
|
||||||
|
).Wait(30 * time.Second)
|
||||||
|
|
||||||
// We should get an error, and that error should indicate that the HTLC
|
// We should get an error, and that error should indicate that the HTLC
|
||||||
// should be rejected due to a policy violation (below min HTLC).
|
// should be rejected due to a policy violation (below min HTLC).
|
||||||
@ -786,9 +802,11 @@ func TestUpdateForwardingPolicy(t *testing.T) {
|
|||||||
|
|
||||||
// First, send this 10 mSAT payment over the three hops, the payment
|
// First, send this 10 mSAT payment over the three hops, the payment
|
||||||
// should succeed, and all balances should be updated accordingly.
|
// should succeed, and all balances should be updated accordingly.
|
||||||
payResp, err := n.makePayment(n.aliceServer, n.carolServer,
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
n.bobServer.PubKey(), hops, amountNoFee, htlcAmt,
|
payResp, err := n.makePayment(
|
||||||
htlcExpiry).Wait(30 * time.Second)
|
n.aliceServer, n.carolServer, firstHop, hops, amountNoFee,
|
||||||
|
htlcAmt, htlcExpiry,
|
||||||
|
).Wait(30 * time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to send payment: %v", err)
|
t.Fatalf("unable to send payment: %v", err)
|
||||||
}
|
}
|
||||||
@ -836,9 +854,10 @@ func TestUpdateForwardingPolicy(t *testing.T) {
|
|||||||
// Next, we'll send the payment again, using the exact same per-hop
|
// Next, we'll send the payment again, using the exact same per-hop
|
||||||
// payload for each node. This payment should fail as it won't factor
|
// payload for each node. This payment should fail as it won't factor
|
||||||
// in Bob's new fee policy.
|
// in Bob's new fee policy.
|
||||||
_, err = n.makePayment(n.aliceServer, n.carolServer,
|
_, err = n.makePayment(
|
||||||
n.bobServer.PubKey(), hops, amountNoFee, htlcAmt,
|
n.aliceServer, n.carolServer, firstHop, hops, amountNoFee,
|
||||||
htlcExpiry).Wait(30 * time.Second)
|
htlcAmt, htlcExpiry,
|
||||||
|
).Wait(30 * time.Second)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("payment should've been rejected")
|
t.Fatalf("payment should've been rejected")
|
||||||
}
|
}
|
||||||
@ -895,9 +914,11 @@ func TestChannelLinkMultiHopInsufficientPayment(t *testing.T) {
|
|||||||
// * user notification to be sent.
|
// * user notification to be sent.
|
||||||
|
|
||||||
receiver := n.carolServer
|
receiver := n.carolServer
|
||||||
rhash, err := n.makePayment(n.aliceServer, n.carolServer,
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
n.bobServer.PubKey(), hops, amount, htlcAmt,
|
rhash, err := n.makePayment(
|
||||||
totalTimelock).Wait(30 * time.Second)
|
n.aliceServer, n.carolServer, firstHop, hops, amount, htlcAmt,
|
||||||
|
totalTimelock,
|
||||||
|
).Wait(30 * time.Second)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("error haven't been received")
|
t.Fatal("error haven't been received")
|
||||||
} else if !strings.Contains(err.Error(), "insufficient capacity") {
|
} else if !strings.Contains(err.Error(), "insufficient capacity") {
|
||||||
@ -991,8 +1012,10 @@ func TestChannelLinkMultiHopUnknownPaymentHash(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send payment and expose err channel.
|
// Send payment and expose err channel.
|
||||||
_, err = n.aliceServer.htlcSwitch.SendHTLC(n.bobServer.PubKey(), htlc,
|
_, err = n.aliceServer.htlcSwitch.SendHTLC(
|
||||||
newMockDeobfuscator())
|
n.firstBobChannelLink.ShortChanID(), htlc,
|
||||||
|
newMockDeobfuscator(),
|
||||||
|
)
|
||||||
if err.Error() != lnwire.CodeUnknownPaymentHash.String() {
|
if err.Error() != lnwire.CodeUnknownPaymentHash.String() {
|
||||||
t.Fatal("error haven't been received")
|
t.Fatal("error haven't been received")
|
||||||
}
|
}
|
||||||
@ -1066,10 +1089,11 @@ func TestChannelLinkMultiHopUnknownNextHop(t *testing.T) {
|
|||||||
)
|
)
|
||||||
n.bobServer.htlcSwitch.RemoveLink(bobChanID)
|
n.bobServer.htlcSwitch.RemoveLink(bobChanID)
|
||||||
|
|
||||||
bobPub := n.bobServer.PubKey()
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
receiver := n.carolServer
|
receiver := n.carolServer
|
||||||
rhash, err := n.makePayment(n.aliceServer, receiver, bobPub, hops,
|
rhash, err := n.makePayment(
|
||||||
amount, htlcAmt, totalTimelock).Wait(30 * time.Second)
|
n.aliceServer, receiver, firstHop, hops, amount, htlcAmt,
|
||||||
|
totalTimelock).Wait(30 * time.Second)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("error haven't been received")
|
t.Fatal("error haven't been received")
|
||||||
} else if err.Error() != lnwire.CodeUnknownNextPeer.String() {
|
} else if err.Error() != lnwire.CodeUnknownNextPeer.String() {
|
||||||
@ -1173,9 +1197,11 @@ func TestChannelLinkMultiHopDecodeError(t *testing.T) {
|
|||||||
n.firstBobChannelLink, n.carolChannelLink)
|
n.firstBobChannelLink, n.carolChannelLink)
|
||||||
|
|
||||||
receiver := n.carolServer
|
receiver := n.carolServer
|
||||||
rhash, err := n.makePayment(n.aliceServer, n.carolServer,
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
n.bobServer.PubKey(), hops, amount, htlcAmt,
|
rhash, err := n.makePayment(
|
||||||
totalTimelock).Wait(30 * time.Second)
|
n.aliceServer, n.carolServer, firstHop, hops, amount, htlcAmt,
|
||||||
|
totalTimelock,
|
||||||
|
).Wait(30 * time.Second)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("error haven't been received")
|
t.Fatal("error haven't been received")
|
||||||
}
|
}
|
||||||
@ -1257,9 +1283,11 @@ func TestChannelLinkExpiryTooSoonExitNode(t *testing.T) {
|
|||||||
startingHeight-10, n.firstBobChannelLink)
|
startingHeight-10, n.firstBobChannelLink)
|
||||||
|
|
||||||
// Now we'll send out the payment from Alice to Bob.
|
// Now we'll send out the payment from Alice to Bob.
|
||||||
_, err = n.makePayment(n.aliceServer, n.bobServer,
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
n.bobServer.PubKey(), hops, amount, htlcAmt,
|
_, err = n.makePayment(
|
||||||
totalTimelock).Wait(30 * time.Second)
|
n.aliceServer, n.bobServer, firstHop, hops, amount, htlcAmt,
|
||||||
|
totalTimelock,
|
||||||
|
).Wait(30 * time.Second)
|
||||||
|
|
||||||
// The payment should've failed as the time lock value was in the
|
// The payment should've failed as the time lock value was in the
|
||||||
// _past_.
|
// _past_.
|
||||||
@ -1315,9 +1343,11 @@ func TestChannelLinkExpiryTooSoonMidNode(t *testing.T) {
|
|||||||
startingHeight-10, n.firstBobChannelLink, n.carolChannelLink)
|
startingHeight-10, n.firstBobChannelLink, n.carolChannelLink)
|
||||||
|
|
||||||
// Now we'll send out the payment from Alice to Bob.
|
// Now we'll send out the payment from Alice to Bob.
|
||||||
_, err = n.makePayment(n.aliceServer, n.bobServer,
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
n.bobServer.PubKey(), hops, amount, htlcAmt,
|
_, err = n.makePayment(
|
||||||
totalTimelock).Wait(30 * time.Second)
|
n.aliceServer, n.bobServer, firstHop, hops, amount, htlcAmt,
|
||||||
|
totalTimelock,
|
||||||
|
).Wait(30 * time.Second)
|
||||||
|
|
||||||
// The payment should've failed as the time lock value was in the
|
// The payment should've failed as the time lock value was in the
|
||||||
// _past_.
|
// _past_.
|
||||||
@ -1412,9 +1442,11 @@ func TestChannelLinkSingleHopMessageOrdering(t *testing.T) {
|
|||||||
// * settle request to be sent back from bob to alice.
|
// * settle request to be sent back from bob to alice.
|
||||||
// * alice<->bob commitment state to be updated.
|
// * alice<->bob commitment state to be updated.
|
||||||
// * user notification to be sent.
|
// * user notification to be sent.
|
||||||
_, err = n.makePayment(n.aliceServer, n.bobServer,
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
n.bobServer.PubKey(), hops, amount, htlcAmt,
|
_, err = n.makePayment(
|
||||||
totalTimelock).Wait(30 * time.Second)
|
n.aliceServer, n.bobServer, firstHop, hops, amount, htlcAmt,
|
||||||
|
totalTimelock,
|
||||||
|
).Wait(30 * time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to make the payment: %v", err)
|
t.Fatalf("unable to make the payment: %v", err)
|
||||||
}
|
}
|
||||||
@ -3236,9 +3268,11 @@ func TestChannelRetransmission(t *testing.T) {
|
|||||||
//
|
//
|
||||||
// TODO(roasbeef); increase timeout?
|
// TODO(roasbeef); increase timeout?
|
||||||
receiver := n.bobServer
|
receiver := n.bobServer
|
||||||
rhash, err := n.makePayment(n.aliceServer, receiver,
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
n.bobServer.PubKey(), hops, amount, htlcAmt,
|
rhash, err := n.makePayment(
|
||||||
totalTimelock).Wait(time.Second * 5)
|
n.aliceServer, receiver, firstHop, hops, amount,
|
||||||
|
htlcAmt, totalTimelock,
|
||||||
|
).Wait(time.Second * 5)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ct.Fatalf("payment shouldn't haven been finished")
|
ct.Fatalf("payment shouldn't haven been finished")
|
||||||
}
|
}
|
||||||
@ -3529,9 +3563,10 @@ func TestChannelLinkShutdownDuringForward(t *testing.T) {
|
|||||||
n.firstBobChannelLink, n.carolChannelLink,
|
n.firstBobChannelLink, n.carolChannelLink,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
n.makePayment(
|
n.makePayment(
|
||||||
n.aliceServer, n.carolServer, n.bobServer.PubKey(),
|
n.aliceServer, n.carolServer, firstHop, hops, amount, htlcAmt,
|
||||||
hops, amount, htlcAmt, totalTimelock,
|
totalTimelock,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Strobe the batch ticker of Bob's incoming link, waiting for it to
|
// Strobe the batch ticker of Bob's incoming link, waiting for it to
|
||||||
@ -3705,16 +3740,20 @@ func TestChannelLinkAcceptDuplicatePayment(t *testing.T) {
|
|||||||
// With the invoice now added to Carol's registry, we'll send the
|
// With the invoice now added to Carol's registry, we'll send the
|
||||||
// payment. It should succeed w/o any issues as it has been crafted
|
// payment. It should succeed w/o any issues as it has been crafted
|
||||||
// properly.
|
// properly.
|
||||||
_, err = n.aliceServer.htlcSwitch.SendHTLC(n.bobServer.PubKey(), htlc,
|
_, err = n.aliceServer.htlcSwitch.SendHTLC(
|
||||||
newMockDeobfuscator())
|
n.firstBobChannelLink.ShortChanID(), htlc,
|
||||||
|
newMockDeobfuscator(),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to send payment to carol: %v", err)
|
t.Fatalf("unable to send payment to carol: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, if we attempt to send the payment *again* it should be rejected
|
// Now, if we attempt to send the payment *again* it should be rejected
|
||||||
// as it's a duplicate request.
|
// as it's a duplicate request.
|
||||||
_, err = n.aliceServer.htlcSwitch.SendHTLC(n.bobServer.PubKey(), htlc,
|
_, err = n.aliceServer.htlcSwitch.SendHTLC(
|
||||||
newMockDeobfuscator())
|
n.firstBobChannelLink.ShortChanID(), htlc,
|
||||||
|
newMockDeobfuscator(),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error shouldn't have been received got: %v", err)
|
t.Fatalf("error shouldn't have been received got: %v", err)
|
||||||
}
|
}
|
||||||
@ -3760,9 +3799,10 @@ func TestChannelLinkAcceptOverpay(t *testing.T) {
|
|||||||
// When we actually go to send the payment, we'll actually create an
|
// When we actually go to send the payment, we'll actually create an
|
||||||
// invoice at Carol for only half of this amount.
|
// invoice at Carol for only half of this amount.
|
||||||
receiver := n.carolServer
|
receiver := n.carolServer
|
||||||
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
rhash, err := n.makePayment(
|
rhash, err := n.makePayment(
|
||||||
n.aliceServer, n.carolServer, n.bobServer.PubKey(),
|
n.aliceServer, n.carolServer, firstHop, hops, amount/2, htlcAmt,
|
||||||
hops, amount/2, htlcAmt, totalTimelock,
|
totalTimelock,
|
||||||
).Wait(30 * time.Second)
|
).Wait(30 * time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to send payment: %v", err)
|
t.Fatalf("unable to send payment: %v", err)
|
||||||
@ -4732,9 +4772,10 @@ func TestForwardingAsymmetricTimeLockPolicies(t *testing.T) {
|
|||||||
n.carolChannelLink,
|
n.carolChannelLink,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
_, err = n.makePayment(
|
_, err = n.makePayment(
|
||||||
n.aliceServer, n.carolServer, n.bobServer.PubKey(), hops,
|
n.aliceServer, n.carolServer, firstHop, hops, amount, htlcAmt,
|
||||||
amount, htlcAmt, totalTimelock,
|
totalTimelock,
|
||||||
).Wait(30 * time.Second)
|
).Wait(30 * time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to send payment: %v", err)
|
t.Fatalf("unable to send payment: %v", err)
|
||||||
|
@ -340,7 +340,8 @@ func (s *Switch) ProcessContractResolution(msg contractcourt.ResolutionMsg) erro
|
|||||||
|
|
||||||
// SendHTLC is used by other subsystems which aren't belong to htlc switch
|
// SendHTLC is used by other subsystems which aren't belong to htlc switch
|
||||||
// package in order to send the htlc update.
|
// package in order to send the htlc update.
|
||||||
func (s *Switch) SendHTLC(nextNode [33]byte, htlc *lnwire.UpdateAddHTLC,
|
func (s *Switch) SendHTLC(firstHop lnwire.ShortChannelID,
|
||||||
|
htlc *lnwire.UpdateAddHTLC,
|
||||||
deobfuscator ErrorDecrypter) ([sha256.Size]byte, error) {
|
deobfuscator ErrorDecrypter) ([sha256.Size]byte, error) {
|
||||||
|
|
||||||
// Create payment and add to the map of payment in order later to be
|
// Create payment and add to the map of payment in order later to be
|
||||||
@ -369,6 +370,7 @@ func (s *Switch) SendHTLC(nextNode [33]byte, htlc *lnwire.UpdateAddHTLC,
|
|||||||
packet := &htlcPacket{
|
packet := &htlcPacket{
|
||||||
incomingChanID: sourceHop,
|
incomingChanID: sourceHop,
|
||||||
incomingHTLCID: paymentID,
|
incomingHTLCID: paymentID,
|
||||||
|
outgoingChanID: firstHop,
|
||||||
destNode: nextNode,
|
destNode: nextNode,
|
||||||
htlc: htlc,
|
htlc: htlc,
|
||||||
}
|
}
|
||||||
@ -783,56 +785,24 @@ func (s *Switch) handleLocalDispatch(pkt *htlcPacket) error {
|
|||||||
// User have created the htlc update therefore we should find the
|
// User have created the htlc update therefore we should find the
|
||||||
// appropriate channel link and send the payment over this link.
|
// appropriate channel link and send the payment over this link.
|
||||||
case *lnwire.UpdateAddHTLC:
|
case *lnwire.UpdateAddHTLC:
|
||||||
// Try to find links by node destination.
|
|
||||||
s.indexMtx.RLock()
|
s.indexMtx.RLock()
|
||||||
links, err := s.getLinks(pkt.destNode)
|
link, err := s.getLinkByShortID(pkt.outgoingChanID)
|
||||||
|
s.indexMtx.RUnlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.indexMtx.RUnlock()
|
log.Errorf("Link %v not found", pkt.outgoingChanID)
|
||||||
|
|
||||||
log.Errorf("unable to find links by destination %v", err)
|
|
||||||
return &ForwardingError{
|
return &ForwardingError{
|
||||||
ErrorSource: s.cfg.SelfKey,
|
ErrorSource: s.cfg.SelfKey,
|
||||||
FailureMessage: &lnwire.FailUnknownNextPeer{},
|
FailureMessage: &lnwire.FailUnknownNextPeer{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.indexMtx.RUnlock()
|
|
||||||
|
|
||||||
// Try to find destination channel link with appropriate
|
if !link.EligibleToForward() {
|
||||||
// bandwidth.
|
err := fmt.Errorf("Link %v is not available to forward",
|
||||||
var (
|
pkt.outgoingChanID)
|
||||||
destination ChannelLink
|
|
||||||
largestBandwidth lnwire.MilliSatoshi
|
|
||||||
)
|
|
||||||
for _, link := range links {
|
|
||||||
// We'll skip any links that aren't yet eligible for
|
|
||||||
// forwarding.
|
|
||||||
if !link.EligibleToForward() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
bandwidth := link.Bandwidth()
|
|
||||||
if bandwidth > largestBandwidth {
|
|
||||||
|
|
||||||
largestBandwidth = bandwidth
|
|
||||||
}
|
|
||||||
|
|
||||||
if bandwidth >= htlc.Amount {
|
|
||||||
destination = link
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the channel link we're attempting to forward the update
|
|
||||||
// over has insufficient capacity, then we'll cancel the HTLC
|
|
||||||
// as the payment cannot succeed.
|
|
||||||
if destination == nil {
|
|
||||||
err := fmt.Errorf("insufficient capacity in available "+
|
|
||||||
"outgoing links: need %v, max available is %v",
|
|
||||||
htlc.Amount, largestBandwidth)
|
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
|
||||||
// Note that we don't need to populate an update here,
|
// The update does not need to be populated as the error
|
||||||
// as this will go directly back to the router.
|
// will be returned back to the router.
|
||||||
htlcErr := lnwire.NewTemporaryChannelFailure(nil)
|
htlcErr := lnwire.NewTemporaryChannelFailure(nil)
|
||||||
return &ForwardingError{
|
return &ForwardingError{
|
||||||
ErrorSource: s.cfg.SelfKey,
|
ErrorSource: s.cfg.SelfKey,
|
||||||
@ -841,12 +811,23 @@ func (s *Switch) handleLocalDispatch(pkt *htlcPacket) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the packet to the destination channel link which
|
if link.Bandwidth() < htlc.Amount {
|
||||||
// manages then channel.
|
err := fmt.Errorf("Link %v has insufficient capacity: "+
|
||||||
//
|
"need %v, has %v", pkt.outgoingChanID,
|
||||||
// TODO(roasbeef): should return with an error
|
htlc.Amount, link.Bandwidth())
|
||||||
pkt.outgoingChanID = destination.ShortChanID()
|
log.Error(err)
|
||||||
return destination.HandleSwitchPacket(pkt)
|
|
||||||
|
// The update does not need to be populated as the error
|
||||||
|
// will be returned back to the router.
|
||||||
|
htlcErr := lnwire.NewTemporaryChannelFailure(nil)
|
||||||
|
return &ForwardingError{
|
||||||
|
ErrorSource: s.cfg.SelfKey,
|
||||||
|
ExtraMsg: err.Error(),
|
||||||
|
FailureMessage: htlcErr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return link.HandleSwitchPacket(pkt)
|
||||||
|
|
||||||
// We've just received a settle update which means we can finalize the
|
// We've just received a settle update which means we can finalize the
|
||||||
// user payment and return successful response.
|
// user payment and return successful response.
|
||||||
|
@ -1330,8 +1330,7 @@ func TestSkipIneligibleLinksLocalForward(t *testing.T) {
|
|||||||
// We'll attempt to send out a new HTLC that has Alice as the first
|
// We'll attempt to send out a new HTLC that has Alice as the first
|
||||||
// outgoing link. This should fail as Alice isn't yet able to forward
|
// outgoing link. This should fail as Alice isn't yet able to forward
|
||||||
// any active HTLC's.
|
// any active HTLC's.
|
||||||
alicePub := aliceChannelLink.Peer().PubKey()
|
_, err = s.SendHTLC(aliceChannelLink.ShortChanID(), addMsg, nil)
|
||||||
_, err = s.SendHTLC(alicePub, addMsg, nil)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("local forward should fail due to inactive link")
|
t.Fatalf("local forward should fail due to inactive link")
|
||||||
}
|
}
|
||||||
@ -1656,7 +1655,8 @@ func TestSwitchSendPayment(t *testing.T) {
|
|||||||
// Handle the request and checks that bob channel link received it.
|
// Handle the request and checks that bob channel link received it.
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
_, err := s.SendHTLC(aliceChannelLink.Peer().PubKey(), update,
|
_, err := s.SendHTLC(
|
||||||
|
aliceChannelLink.ShortChanID(), update,
|
||||||
newMockDeobfuscator())
|
newMockDeobfuscator())
|
||||||
errChan <- err
|
errChan <- err
|
||||||
}()
|
}()
|
||||||
@ -1664,8 +1664,10 @@ func TestSwitchSendPayment(t *testing.T) {
|
|||||||
go func() {
|
go func() {
|
||||||
// Send the payment with the same payment hash and same
|
// Send the payment with the same payment hash and same
|
||||||
// amount and check that it will be propagated successfully
|
// amount and check that it will be propagated successfully
|
||||||
_, err := s.SendHTLC(aliceChannelLink.Peer().PubKey(), update,
|
_, err := s.SendHTLC(
|
||||||
newMockDeobfuscator())
|
aliceChannelLink.ShortChanID(), update,
|
||||||
|
newMockDeobfuscator(),
|
||||||
|
)
|
||||||
errChan <- err
|
errChan <- err
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -1793,9 +1795,10 @@ func TestLocalPaymentNoForwardingEvents(t *testing.T) {
|
|||||||
// wait for Alice to receive the preimage for the payment before
|
// wait for Alice to receive the preimage for the payment before
|
||||||
// proceeding.
|
// proceeding.
|
||||||
receiver := n.bobServer
|
receiver := n.bobServer
|
||||||
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
_, err = n.makePayment(
|
_, err = n.makePayment(
|
||||||
n.aliceServer, receiver, n.bobServer.PubKey(), hops, amount,
|
n.aliceServer, receiver, firstHop, hops, amount, htlcAmt,
|
||||||
htlcAmt, totalTimelock,
|
totalTimelock,
|
||||||
).Wait(30 * time.Second)
|
).Wait(30 * time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to make the payment: %v", err)
|
t.Fatalf("unable to make the payment: %v", err)
|
||||||
@ -1852,10 +1855,11 @@ func TestMultiHopPaymentForwardingEvents(t *testing.T) {
|
|||||||
finalAmt, testStartingHeight, n.firstBobChannelLink,
|
finalAmt, testStartingHeight, n.firstBobChannelLink,
|
||||||
n.carolChannelLink,
|
n.carolChannelLink,
|
||||||
)
|
)
|
||||||
|
firstHop := n.firstBobChannelLink.ShortChanID()
|
||||||
for i := 0; i < numPayments; i++ {
|
for i := 0; i < numPayments; i++ {
|
||||||
_, err := n.makePayment(
|
_, err := n.makePayment(
|
||||||
n.aliceServer, n.carolServer, n.bobServer.PubKey(),
|
n.aliceServer, n.carolServer, firstHop, hops, finalAmt,
|
||||||
hops, finalAmt, htlcAmt, totalTimelock,
|
htlcAmt, totalTimelock,
|
||||||
).Wait(30 * time.Second)
|
).Wait(30 * time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to send payment: %v", err)
|
t.Fatalf("unable to send payment: %v", err)
|
||||||
|
@ -664,7 +664,7 @@ func (r *paymentResponse) Wait(d time.Duration) (chainhash.Hash, error) {
|
|||||||
// * from Alice to Carol through the Bob
|
// * from Alice to Carol through the Bob
|
||||||
// * from Alice to some another peer through the Bob
|
// * from Alice to some another peer through the Bob
|
||||||
func (n *threeHopNetwork) makePayment(sendingPeer, receivingPeer lnpeer.Peer,
|
func (n *threeHopNetwork) makePayment(sendingPeer, receivingPeer lnpeer.Peer,
|
||||||
firstHopPub [33]byte, hops []ForwardingInfo,
|
firstHop lnwire.ShortChannelID, hops []ForwardingInfo,
|
||||||
invoiceAmt, htlcAmt lnwire.MilliSatoshi,
|
invoiceAmt, htlcAmt lnwire.MilliSatoshi,
|
||||||
timelock uint32) *paymentResponse {
|
timelock uint32) *paymentResponse {
|
||||||
|
|
||||||
@ -708,8 +708,9 @@ func (n *threeHopNetwork) makePayment(sendingPeer, receivingPeer lnpeer.Peer,
|
|||||||
|
|
||||||
// Send payment and expose err channel.
|
// Send payment and expose err channel.
|
||||||
go func() {
|
go func() {
|
||||||
_, err := sender.htlcSwitch.SendHTLC(firstHopPub, htlc,
|
_, err := sender.htlcSwitch.SendHTLC(
|
||||||
newMockDeobfuscator())
|
firstHop, htlc, newMockDeobfuscator(),
|
||||||
|
)
|
||||||
paymentErr <- err
|
paymentErr <- err
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user