Add notifications for local initiated sends settles and forwarding
failures. As with link failures, local send settles and forwarding
failures are reported directly to the router so must have their own
notification handling.
Notify link failures for our own payments. Separate handling code is
required for local payment link failures because we do not pass these
failures back through the switch (like we do for link failures for
forwards), but rather send them straight back to the router. Our own
sends have the payment ID saved in the incoming htlc ID of the packet's
incoming circuit. This change replaces that value with for the sake
of consistent notifying of sends and receives from our node.
This commit sets more fields on the htlcPacket created to fail adding
a htlc packet to the switch for notification purposes. This new data is
copied by value from the original packet. The packet is then failed
back to the peer that forwarded us the packet, which is handled by
handledownstream packet. The values added to the packet are not used
in the handling of a failed packet.
In this commit, a htlcNotifier interface is added to allow for easy
unit testing. Instances of the HtlcNotifier are added to the server,
switch and link.
This commit enables the user to specify he is not interested in
automatically close channels with pending payments that their
corresponding htlcs have timed-out.
By requiring a configurable grace period uptime of our node
before closing such channels, we give a chance to the other node to
properly cancel the htlc and avoid unnecessary on-chain transaction.
In mobile it is very important for the user experience as otherwise
channels will be force closed more frequently.
This commit adds a linkError field to track the value of failures
which occur at our node. This field is set when local payments or
multi hop htlcs fail in the switch or on our outgoing link. This
addition is required for the addition of a htlc notifier which will
notify these failures in handleDownstreamPacket.
The passing of link error to failAddPacket removes the need for an
additional error field, because the link error's failure detail will
contain any additional metadata. In the places where the failure detail
does not cover all the metadata that was previously supplied by addr
err, the error is logged before calling failAddPacket so that this
change does not reduce the amount of information we log.
Add a FailureDetail interface which allows us have different kinds of
failures for link errors. This interface will be used to cover failures
that occur when on invoice payment, because the errors have already
been enumerated in the invoices package.
Rename FailureDetail in a separate commit so that a FailureDetail
interface can be introduced in the following commit.
OutgoingFailureOnionDecode is renamed to OutgoingFailureDecodeError
to specifically indicate that we could not decode the wire
failure that our payment experienced.
Add a CheckCircularForward function which detects packets which are
forwards over the same incoming and outgoing link, and errors if the
node is configured to disallow forwards of this nature. This check is
added to increase the cost of a liquidity lockup attack, because it
increases the length of the route required to lock up an individual
node's bandwidth. Since nodes are currently limited to 20 hops,
increasing the length of the route needed to lock up capital increases
the number of malicious payments an attacker will have to route, which
increases the capital requirement of the attack overall.
Update the ChannelLink interface to specifically
return the LinkError struct. This error implements
the ClearTextError interface, so will be picked
up as a routing realted error by the router.
With LinkErrors implemented, the switch now
returns a LinkError for all failures on our
incoming/outgoing link and ForwardingError when
the failure occurs down the line.
Add a constructor for the creation of forwarding errors.
A special constructor is added for the case where we have
an unknown wire failure, and must set a nil failure message.
This commit is adapted from @Bluetegu's original
pull request #1462.
This commit reads an optional address to pay funds out to
from a user iniitiated close channel address. If the channel
already has a shutdown script set, the request will fail if
an address is provided. Otherwise, the cooperative close will
pay out to the address provided.
In this commit, we create a new chainfee package, that houses all fee
related functionality used within the codebase. The creation of this new
package furthers our long-term goal of extracting functionality from the
bloated `lnwallet` package into new distinct packages. Additionally,
this new packages resolves a class of import cycle that could arise if a
new package that was imported by something in `lnwallet` wanted to use
the existing fee related functions in the prior `lnwallet` package.
In the scenario where the requested channel does not have enough balance
and another channel towards the same node generates a different failure,
we erroneously returned UnknownNextPeer instead of the expected
TemporaryChannelFailure.
This commit rewrites the non-strict forwarding logic in the switch to
return the proper failure message. Part of this is moving the link
balance check inside the link.
The policy update logic that resided part in the gossiper and
part in the rpc server is extracted into its own object.
This prepares for additional validation logic to be added for policy
updates that would otherwise make the gossiper heavier.
It is also a small first step towards separation of our own channel data
from the rest of the graph.
Since we will now wait to deliver the event after channel reestablish,
notifying when the link is added to the switch will no longer be
sufficient. Later, we will add receiving reestablish as an additional
requirement for EligibleToForward returning true.
The inactive ntfn is also moved, to ensure that we don't fire inactive
notifications if no corresponding active notification was sent.
In this commit, we fix a bug where if a user updates a forwarding policy to be
zero, the update will be applied to the policy correctly on-disk, but not
in-memory.
We solve this issue by having the gossiper return the list of on-disk updated
policies and passing these policies to the switch, so the switch can assume
that zero-valued fields are intentional and not just uninitialized.
htlcs
config: Adding RejectHTLC field in config struct
This commit adds a RejectHTLC field in the config struct in config.go.
This allows the user to run lnd as a node that does not accept onward
HTLCs.
htlcswitch/switch: Adding a field RejectHTLC to the switch config
This commit adds a field RejectHTLC to the switch config. When the
switch receives an HTLC it will check this flag and if the HTLC is not
from the source hop, the HTLC will be rejected.
htlcswitch/switch: adding check for RejectHTLC flag and incomingChanID
This commit adds a check when receiving UpdateAddHTLC. The check looks
for the RejectHTLC flag set and whether the HTLC is from the sourceHop
(the local switch). If the HTLC is not from the sourceHop, then we
reject the HTLC and return a FailChannelDisabled error.
server: adding RejectHTLC field to initialization of switch
lnd_test: adding test for RejectHTLC
This commit adds a test which tests that a node with the --rejecthtlc
flag will reject any onward HTLCs but still can receive direct HTLCs and
can send HTLCs.
This commit makes the outgoing link pipeline the settle to the
switch as soon as it receives it. Previously, it would wait for a
revocation before sending it, which caused increased latency on
payments as well as possibly never settling on the incoming link.
A duplicate settle is still sent to the switch, but it is handled
gracefully. A new AckEventTicker was added to the switch which
acknowledges any pending settle / fail entries in an outgoing
link's fwd pkgs in batch. This was needed in order to reduce the
number of db txn's which would have been incurred by acking whenever
we receive a duplicate settle without batching.
Methods on failure message types used to be defined on value receivers.
This allowed assignment of a failure message to ForwardingError both as
a value and as a pointer. This is error-prone, especially when using a
type switch.
In this commit the failure message methods are changed so that they
target pointer receivers.
Two instances where a value was assigned instead of a reference are
fixed.
In this commit we move handing the deobfuscator from the router to the
switch from when the payment is initiated, to when the result is
queried.
We do this because only the router can recreate the deobfuscator after a
restart, and we are preparing for being able to handle results across
restarts.
Since the deobfuscator cannot be nil anymore, we can also get rid of
that special case.
This lets us distinguish an critical error from a actual payment result
(success or failure). This is important since we know that we can only
attempt another payment when a final result from the previous payment
attempt is received.
With the following commits, it'll become important to not resuse
paymentIDs, since there is no way to tell whether the HTLC in question
has already been forwarded and settled/failed.
We clarify this in the SendHTLC comments, and alter the tests to not
attempt to resend an HTLC with a duplicate payment ID.
This commit moves the responsibility of generating a unique payment ID
from the switch to the router. This will make it easier for the router
to keep track of which HTLCs were successfully forwarded onto the
network, as it can query the switch for existing HTLCs as long as the
paymentIDs are kept.
The router is expected to maintain a map from paymentHash->paymentID,
such that they can be replayed on restart. This also lets the router
check the status of a sent payment after a restart, by querying the
switch for the paymentID in question.
In this commit, we now properly convert multi-hop malformed HTLC
failures. Before this commit, we wouldn't properly add a layer of
encryption to these errors meaning that the destination would fail to
decrypt the error as it was actually plaintext.
To remedy this, we'll now check if we need to convert an error, and if
so we'll encrypt it as if it we were the source of the error (the true
source is our direct channel peer).
In this commit, we fix a bug that caused us to be unable to properly
handle malformed HTLC failures from our direct link. Before this commit,
we would attempt to decrypt it and fail since it wasn't well formed. In
this commit, if its an error for a local payment, and it needed to be
converted, then we'll decode it w/o decrypting since it's already
plaintext.
This commit modifies the behavior of the
HasActiveLink method within the switch to
only return true if the link is in the
link index and is eligible to forward
HTLCs.
The prior version returns true whenever
the link is found in the link index,
which may return true for pending
channels that are not actually active.
This commit adds conversion between the lnwire.UpdateFee message and the
new FeeUpdate PaymentDescriptor. We re-purpose the existing Amount field
in the PaymentDescriptor stuct to hold the feerate.
This commit moves the logic handling responses to
locally-initiated payments to be asynchronous. The
reordering of operations into handleLocalDispatch
brings a serious performance burden to the switch's
main event loop. However, the at-most once semantics
of circuit map and idempotency of cleanup methods
allows concurrent operations to run in parallel.
Prior to this commit, the async_payments_benchmark
would timeout due to the forcibly serial nature of
the prior design. With this change, there is no
perceptible difference in the benchmark OMM, even
though we've added two extra db calls.
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.
In this commit, we thread through a link's quit channel into
routeAsync, the primary helper method allowing links to send
htlcPackets through the switch. This is intended to remove
deadlocks from happening, where the link is synchronously
blocking on forwarding packets to the switch, but also
needs to shutdown.
In this commit, we modify the removeLink method to be more asynchronous.
Before this commit, we would attempt to block until the peer exits.
However, it may be the case that at times time, then target link is
attempting to forward a batch of packets to the switch (forwardBatch).
Atm, this method doesn't pass in an external context/quit, so we can't
cancel this message/request. As a result, we'll now ensure that
`removeLink` doesn't block, so we can resume the switch's main loop as
soon as possible.
In this commit, we move the block height dependency from the links in
the switch to the switch itself. This is possible due to a recent change
on the links no longer depending on the block height to update their
commitment fees.
We'll now only have the switch be alerted of new blocks coming in and
links will retrieve the height from it atomically.
In this commit, we fix a bug in the way we handle removing items from
the interfaceIndex. Before this commit, we would delete all items items
with the target public key that of the peer that owns the link being
removed. However, this is incorrect as the peer may have other links
sill active.
In this commit, we fix this by first only deleting the link from the
peer's index, and then checking to see if the index is empty after this
deletion. Only if so do we delete the index for the peer all together.
In this commit, we modify the interfaceIndex to no longer key the second
level of the index by the ChannelLink. Instead, we'll use the chan ID as
it's a stable identifier, unlike a reference to an interface.
In this commit, we fix an existing source of a panic, that could at
times lead to a deadlock. If the circuit returned from closeCircuit
didn't have an outgoing key (as it was an incomplete forward), then we
would attempt to de-ref a nil pointer. This would trigger a panic, and
the runtime would start to unwind the stack, and execute each defer in
line. A deadlock can arise here, as in the defer at the root goroutine,
we need to grab the fwdingEventMtx. However, we already have it at the
panic site.
We fix this issue by ensuring we only attempt to add the event if it's a
_settle_ and also actually has an outgoing circuit (which it should
already, just a defensive check).
In this commit, we ensure that any time we send a TempChannelFailure
that's destined for a multi-hop source sender, then we'll always package
the latest channel update along with it.
In this commit, we update the testUpdateChannelPolicy to exercise the
recent set of changes within the switch. If one applies this test to a
fresh branch (without those new changes) it should fail. This is due to
the fact that before, Bob would attempt to apply the constraints of the
incoming link (which we updated) instead of the outgoing link. With the
recent set of changes, the test now properly passes.
In this commit, we simplify the switch's code a bit. Rather than having
a set of channels we use to mutate or query for the set of current
links, we'll instead now just use a mutex to guard a set of link
indexes. This serves to simplify the ode, and also make it such that we
don't need to block forwarding in order to add/remove a link.
In this commit, we fix a very old, lingering bug within the link. When
accepting an HTLC we are meant to validate the fee against the
constraints of the *outgoing* link. This is due to the fact that we're
offering a payment transit service on our outgoing link. Before this
commit, we would use the policies of the *incoming* link. This would at
times lead to odd routing errors as we would go to route, get an error
update and then route again, repeating the process.
With this commit, we'll properly use the incoming link for timelock
related constraints, and the outgoing link for fee related constraints.
We do this by introducing a new HtlcSatisfiesPolicy method in the link.
This method should return a non-nil error if the link can carry the HTLC
as it satisfies its current forwarding policy. We'll use this method now
at *forwarding* time to ensure that we only forward to links that
actually accept the policy. This fixes a number of bugs that existed
before that could result in a link accepting an HTLC that actually
violated its policy. In the case that the policy is violated for *all*
links, we take care to return the error returned by the *target* link so
the caller can update their sending accordingly.
In this commit, we also remove the prior linkControl channel in the
channelLink. Instead, of sending a message to update the internal link
policy, we'll use a mutex in place. This simplifies the code, and also
adds some necessary refactoring in anticipation of the next follow up
commit.