Commit Graph

191 Commits

Author SHA1 Message Date
Christian Decker
e76bf541ad paymod: Fix the routehints being lost when retrying
We were removing the current hint from the list and not inheriting the current
routehint, so we'd be forgetting a hint at each retry. Now we keep the array
unchanged in the root, and simply skip the ones that are not usable given the
current information we have about the channels (in the form of channel_hints).

Fixes #3861
2020-07-23 10:14:21 +09:30
Christian Decker
d289ee64a1 paymod: Add the courtesy +1 to the CLTVs to allow for a new block
This may be related to the issue #3862, however the water was muddied by it
being the wrong error to return, and the node should not expect this courtesy
feature to be present at all...
2020-07-23 10:14:21 +09:30
Christian Decker
e92787a0e2 paymod: Teach the adaptive splitter to respect the HTLC limit
There is little point in trying to split if the resulting HTLCs exceed the
maximum number of HTLCs we can add to our channels. So abort if a split would
result in more HTLCs than our channels can support.
2020-07-23 10:14:21 +09:30
Christian Decker
acdd9b8762 paymod: Teach the presplit modifier to respect the chan HTLC limit
The presplit modifier could end up exceeding the maximum number of HTLCs we
can add to a channel right out the gate, so we switch to a dynamic presplit if
that is the case. The presplit will now at most use 1/3rd of the available
HTLCs on the channels if the normal split would exceed the number of availabe
HTLCs. And we also abort early if we don't have a sufficient HTLCs available.
2020-07-23 10:14:21 +09:30
Christian Decker
a1dc9cbd97 paymod: Track how many HTLCs each channel can still add
It turns out that by aggressively splitting payments we may end up exhausting
the number of HTLCs we can add to a channel quickly. By tracking the number of
HTLCs we can still add, and excluding the channels to which we cannot add any
more we increase the route diversity, and avoid quickly exhausting the HTLC
budget.

In the next commit we'll also implement an early abort if we've exhausted all
channels, so we don't end up splitting indefinitely and we can also optimize
the initial split to not run afoul of that limit.
2020-07-23 10:14:21 +09:30
Vincent
54888d454b Fixed assertion in pay plugin
This PR includes the fix discussed on PR #3855. This fix was tested with the use case described inside the issue and worked.

Fixes: #3855

Changelog-None
2020-07-23 10:14:21 +09:30
Rusty Russell
178415aca7 pay: handle returned errors more gracefully.
The code had incorrect assertions, partially because it didn't clearly
distinguish errors from the final node (which, barring blockheight issues,
mean a complete failre) and intermediate nodes.

In particular, we can't trust the *values*, so we need to distinguish
these by the *sender*.

If a route is of length 2 (A, B):
- erring_index == 0 means us complaining about channel A.
- erring_index == 1 means A.node complaining about channel B.
- erring_index == 2 means the final destination node B.node.

This is particularly of note because Travis does NOT run test_pay_routeboost!

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2020-07-23 10:14:21 +09:30
Rusty Russell
a849e5f4bd pay: fix problematic sharing of shadow route data.
Because listchannels responses are async, with mpp we can end up
fighting over use of the parent's data giving results from incorrect
final CLTVs to assertion failures like below:

```
pay: plugins/libplugin-pay.c:1964: shadow_route_listchannels: Assertion `amount_msat_greater_eq(p->constraints.fee_budget, d->constraints.fee_budget)' failed.
pay: FATAL SIGNAL 6 (version v0.9.0rc2-11-g29d32e0-modded)
0x563129eb6a15 send_backtrace
	common/daemon.c:38
0x563129eb6abf crashdump
	common/daemon.c:51
0x7fe37c8b920f ???
	???:0
0x7fe37c8b918b ???
	???:0
0x7fe37c898858 ???
	???:0
0x7fe37c898728 ???
	???:0
0x7fe37c8a9f35 ???
	???:0
0x563129ea5c63 shadow_route_listchannels
	plugins/libplugin-pay.c:1964
0x563129e9c56a handle_rpc_reply
	plugins/libplugin.c:547
0x563129e9cbfa rpc_read_response_one
	plugins/libplugin.c:662
0x563129e9ccf0 rpc_conn_read_response
	plugins/libplugin.c:681
0x563129ece660 next_plan
	ccan/ccan/io/io.c:59
0x563129ecf245 do_plan
	ccan/ccan/io/io.c:407
0x563129ecf287 io_ready
	ccan/ccan/io/io.c:417
0x563129ed151f io_loop
	ccan/ccan/io/poll.c:445
0x563129e9ef03 plugin_main
	plugins/libplugin.c:1284
0x563129e9b099 main
	plugins/pay.c:2010
0x7fe37c89a0b2 ???
	???:0
0x563129e9452d ???
	???:0
0xffffffffffffffff ???
	???:0
```
2020-07-23 10:14:21 +09:30
Christian Decker
f950153f98 paymod: Fix the adaptive splitter partitioning
We were using the current constraints, including any shadow route and other
modifications, when computing the remainder that the second child should
use. Instead we should use the `start_constraints` on the parent payment,
which is a copy of `constraints` created in `payment_start` exactly for this
purpose.

Also added an assert for the invariant on the multiplier.
2020-07-23 10:14:21 +09:30
Christian Decker
cb20dfc59e paymod: Do not duplicate partids
When using mpp we need to always have partids>0, since we bumped the partid
for the root, but not the next_id we'd end up with partid=1 being
duplicated. Not a big problem since we never ended up sending the root to
lightningd, instead skipping it, but it was confusing me while trying to trace
sub-payment's ancestry.
2020-07-23 10:14:21 +09:30
Christian Decker
7b4e70effa paymod: Consolidate step selection and changes in presplit modifier
We skip most payment steps and all sub-payments, so consolidate the skip
conditions in one if-statement. We also not use `payment_set_step` to skip any
modifiers after us after the step change.
2020-07-23 10:14:21 +09:30
Christian Decker
e1c6b977b4 paymod: Add a log entry whenever we add a channel hint
Mainly used for testing so we make sure we exclude or constrain the correct
channels. Test to follow.
2020-07-23 10:14:21 +09:30
Christian Decker
0ca2c6b9f3 paymod: Rewrite the shadow-route constraint enforcement
We now check against both constraints on the modifier and the payment before
applying either. This "fixes" the assert that was causing the crash in #3851,
but we are still looking for the source of the inconsistency where the
modifier constraints, initialized to 1/4th of the payment, suddenly get more
permissive than the payment itself.
2020-07-23 10:14:21 +09:30
Christian Decker
c0d70cdfc7 paymod: Add invariant verification for constraints on shadowroute
This was highlighted in #3851, so I added an assertion. After the rewrite in
the next commit we would simply skip if any of the constraints were not
maintained, but this serves as the canary in the coalmine, so we don't paper over.
2020-07-23 10:14:21 +09:30
Christian Decker
157e70ffe8 paymod: Add a comment about how we derive errors from erring_index
Mainly to help my future self remember
2020-07-23 10:14:21 +09:30
Christian Decker
b2463b12c0 paymod: Count all attempts, not just the ones with a result
With the presplitter in particular we would have n attempts but the array
contains n+1 entries, which is kinda weird.
2020-07-23 10:14:21 +09:30
Christian Decker
c984376a15 plugin: Always set an end_time for payments in a final state
Reported-by: @thestick613
Fixes #3848
2020-07-18 17:21:11 +02:00
Christian Decker
2146a548bd plugin: Do not return multiple times from pay
While we were unsetting the `payment->cmd` in case of a success to signal that
we should not return to the JSON-RPC command twice, we were not doing that in
the case of failures. This was causing multiple responses to a single incoming
command, and `lightningd` was correctly killing the plugin. This issue was
introduced through early returns (anything setting `payment->abort=true`) and
was caused in Rusty's case through an MPP timeout.

Fixes #3847
Reported-by: Rusty Russell <@rustyrussell>
Signed-off-by: Christian Decker <@cdecker>
2020-07-18 11:40:02 +02:00
Christian Decker
958244367c plugin: Do not get upset if it can't parse waitsendpay result
We were rather pedanticly failing the plugin if we were unable to parse the
`waitsendpay` result, but had coded all the modifiers in such a way that they
can handle a `NULL` result (verified in the code and manually by randomly
failing the parsing). So we now just log the result we failed to parse and
merrily go our way.

Worst case is that we end up retrying the same route multiple times, since we
can't blacklist any nodes / channels without understanding the error, but that
is still in the scope of what we must handle anyway.
2020-07-18 11:40:02 +02:00
Christian Decker
3b54847ae4 paymod: Do not assume that parsing the waitsendpay result succeeds
Suggested-by: ZmnSCPxj
Signed-off-by: Christian Decker
Reference: #3846
2020-07-18 11:40:02 +02:00
Christian Decker
a3610d66ac retrymod: Make retry modifier slightly more verbose
I found it rather useful to trace how a payment is getting retried in the logs.
2020-07-15 11:32:58 +02:00
Christian Decker
041ee930a4 mpp: Consider an abort as the payment being finished
If one part sets the root to be aborted, there is little point in continuing
to wait for the remainder, return to the caller immediately.
2020-07-15 11:32:58 +02:00
Christian Decker
718b6e3398 mpp: Detect if destination supports MPP from invoice and abort early
We abort on the root since that is the coordination point for all parts of the payment.
2020-07-15 11:32:58 +02:00
Christian Decker
de75d3ac0c mpp: Add CLI option to opt-out of multi-part payments
Several tests are not well-suited for mpp, so I added a CLI option to opt-out
of the MPP support at startup time.
2020-07-15 11:32:58 +02:00
Christian Decker
535aaca109 paymod: Implement adaptive splitter
This modifier splits a payment that has been attempted a number of times (by a
modifier earlier in the mod chain) and has failed consistently. It splits the
amount roughly in half, with a but if random fuzz, and then starts a new round
of attempts for the two smaller amounts.
2020-07-15 11:32:58 +02:00
Christian Decker
443643e0b0 retrymod: Reset retry counter if parent is a split
If the parent is a split we have new payment parameters, and want to perform a
number of attempts with those.
2020-07-15 11:32:58 +02:00
Christian Decker
d0eb3a79eb paymod: Not having a result doesn't mean we failed at getroute
Specifically if we split, there is no result, but we shouldn't add a failure
message.
2020-07-15 11:32:58 +02:00
Christian Decker
3f399d15cb paymod: Don't assume that the first payment was executed at all
With the `presplit`-modifier we actually skip execution of the root altogether
which results in the root not having a result at all. Instead we should use
the result returned by `payment_collect_result`.
2020-07-15 11:32:58 +02:00
Christian Decker
c97ff05ffb mpp: Add the presplit-modifier that splits a root payment first 2020-07-15 11:32:58 +02:00
Christian Decker
7f53ade64b paymod: Allow callers to opt out of shadow routing amount fuzzing
With MPP we require that the sum of parts is equal to the `total_msat` amount
declared in the onion. Since that can't be changed once the first part arrives
we need a way to disable amount fuzzing for MPP.
2020-07-15 11:32:58 +02:00
Rusty Russell
899ec2b3d4 JSON API: fix up two existing warnings to be conformant.
Technically an API break, but nobody relies on these I hope!

Note that the feerates warning was buried inside the style object:
it should be top-level.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2020-07-14 21:28:26 +02:00
Christian Decker
65963bc003 exemptfee: Only apply to the root payment and fix logs
We were applying the fee exemption to all payments individually, which is ok
until we switch to MPP, where amounts change. Also the log entry was referring
to the total amount, and not the fee of the payment.
2020-07-14 06:25:29 +09:30
Christian Decker
9be4d552fa paymod: Add a bit more information to the pay response
Amount, parent_part_id  and own partid can be helpful when debugging.
2020-07-14 06:25:29 +09:30
Christian Decker
6f40cb0202 paymod: Inherit exemptfee modifier data on retry 2020-07-14 06:25:29 +09:30
Christian Decker
b88a55b2a4 paymod: Only wait on blockheight if we need to
We were wrongfully identifying all payment failures as blockheight mismatches.
2020-07-14 06:25:29 +09:30
Christian Decker
f20091fc72 pay: Do not duplicate "message" field in response to pay 2020-07-14 06:25:29 +09:30
Christian Decker
411b760985 paymod: Reset the step if we're waiting for a block
This was causing the state flapping test to fail, since we were yielding
control of the io_loop, waiting for the blockheight to be reached, and not
setting the status beforehand. An interim `paystatus` call would then find a
failed leaf and deduce the entire payment failed. Setting it back to the
previous state keeps the overall payment pending while we wait.
2020-07-14 06:25:29 +09:30
Christian Decker
02e44e9903 paymod: Set the STOPPED_RETRYING status code if we stopped retrying 2020-07-14 06:25:29 +09:30
Christian Decker
5776a33116 paymod: Activate paymod and move legacy pay to legacypay command
As suggested during the paymod-03 review it is better to activate the new code
right away, and give users an escape hatch to use the legacy code instead. The
way I implemented it allows using either `legacypay` or `pay` and then set
`legacy` to switch to the other implementation.

Changelog-Added: JSON-RPC: The `pay` command now uses the new payment flow, the new `legacypay` command can be used to issue payment with the legacy code if required.

Suggested-by: Rusty Russell <@rustyrussell>
Suggested-by: ZmnSCPxj <@zmnscpxj>
2020-07-14 06:25:29 +09:30
Christian Decker
514c4044c8 tlv: Allow passing a raw pointer and a length to tlvstream_set_raw
Allows us to do fewer allocations, since the argument doesn't have to be tal
allocated itself.

Suggested-by: Rusty Russell <@rustyrussell>
2020-07-13 14:19:16 +02:00
Christian Decker
af4955c28e paymod: Fix waitsendpay error parsing for unknown failure codes
It turns out that the `failcodename` doesn't get populated if the `failcode`
isn't a known error from the enum (duh...) so don't fail parsing if it's
missing.
2020-07-07 23:25:45 +02:00
Christian Decker
5daa5bd61e paymod: Fix the onion payload construction
I wrongly used a pointer to the array that'd move on append, so an extra
dereference was required here.
2020-07-07 23:25:45 +02:00
Christian Decker
da8eb6fb4c paymod: Expose riskfactor and wire through to getroute 2020-07-07 23:25:45 +02:00
Christian Decker
d8b8a0b31e paymod: Add label to sendonion calls
These get reflected in the `listsendpays` command, and are quite useful.
2020-07-07 23:25:45 +02:00
Christian Decker
2649de54f2 paymod: Do not wait for a blockheight if we're already there
We want to differentiate a wrong block-height from other failure reasons, such
as an unknown `payment_hash`, so we skip the `waitblockheight` if we're
already at the correct height.
2020-07-07 23:25:45 +02:00
Christian Decker
5601a1ab21 paymod: Add a deadline to the pay command and retry modifier 2020-07-07 23:25:45 +02:00
Christian Decker
f557955515 paymod: Consolidate parsing RPC results in libplugin
We handle these in a number of different ways, and regularly get the parsing
and logic for optional fields wrong, so let's consolidate them here.
2020-07-07 23:25:45 +02:00
Christian Decker
4b3e849ce9 paymod: Add function to set the current step
This is necessary otherwise we would not be calling modifiers for the newly
set state which can lead to unexpected results.
2020-07-07 23:25:45 +02:00
Christian Decker
4aed45e98d paymod: Add attempts array to pay return value 2020-07-07 23:25:45 +02:00
Christian Decker
030633bb28 paymod: Add a human readable failreason to payments
This makes it easier to stash a human readable failure message in an attempt.
2020-07-07 23:25:45 +02:00
Christian Decker
2ef130e427 paymod: Apply and unapply routes to the channel hints
Add/remove the HTLC amount from the channel hints so concurrent getroute calls
have the correct exclusions. This can sometimes underflow, if we're unlucky
and call getroute too closely, but that's not a big issue, it can only result
in a failed MPP attempt too many, nothing fatal, and it'll get corrected based
on the result returned by the failing node.
2020-07-07 23:25:45 +02:00
Christian Decker
2331cd62e1 paymod: Add user-provided label back into the paystatus result 2020-07-07 23:25:45 +02:00
Christian Decker
215a0ada8b paymod: Update the route constraints as we apply routes and mods
These are primarily the fee and cltv constraints that we need to keep up to
date in order to give modifiers a correct view of what is and what isn't
allowed.
2020-07-07 23:25:45 +02:00
Christian Decker
935578e567 paymod: Exclude most expensive/slowest chan if limits are exceeded 2020-07-07 23:25:45 +02:00
Christian Decker
4648d2867f paymod: Compute fee and CLTV delta limits for a payment
So far we got away with not caring about these but since we're implementing
modifiers that impact these limits, we better keep track of them.
2020-07-07 23:25:45 +02:00
Christian Decker
e71bdf9ed8 paymod: Wrap the getroute request in a struct
Keeping the arguments in their non-serialized form allows us to amend them as
we apply modifiers and learn new information.
2020-07-07 23:25:45 +02:00
Christian Decker
097cb8d3a0 paymod: Exclude nodes that we found to be faulty 2020-07-07 23:25:45 +02:00
Christian Decker
2f0e535b81 paymod: Add reason why a payment was attempted
This is a slight change in interface in that the string no longer spells out
that a specific node was excluded.
2020-07-07 23:25:45 +02:00
Christian Decker
3a35dd34ac paymod: Add the contents of paystatus
This proved to be rather difficult given the tight coupling of the old structs
and the output of the command.
2020-07-07 23:25:45 +02:00
Christian Decker
2e88249a7b paymod: Make the transition to FAILED a function call
We need to set some variables as well, and the transition to FAILED is a bit
special in that quite some modifiers will skip into FAILED.
2020-07-07 23:25:45 +02:00
ZmnSCPxj jxPCSnmZ
4a89819cdd plugins/Makefile: Change plugins build procedure.
Changelog-None
2020-07-07 21:32:31 +02:00
Christian Decker
7981f4c4d9 paymod: Extract the channel hints update into its own function
We could end up with multiple channel hints, which is a bit wasteful. We now
look for existing ones before adding a new one, and if one exists we use the
more restrictive parameters.

Suggested-by: Lisa Neigut <@niftynei>
2020-07-02 11:54:12 +02:00
Christian Decker
ddb0424a4d paymod: Remove the dummy payment modifier
It was there only for demonstration purposes, and is no longer useful.
2020-07-02 11:54:12 +02:00
Christian Decker
fc714bf2df paymod: Fill in the pay return value 2020-07-02 11:54:12 +02:00
Christian Decker
9aff885828 paymod Collect the final failure when aggregating the tree results
We're lucky that we can distinguish the severity of the failure based on the
failcode, so we bubble up the one with the maximum failcode, and let callers
inspect details if they need more information.
2020-07-02 11:54:12 +02:00
Christian Decker
7a266b8239 paymod: Make payment_tree_result public to users can query state 2020-07-02 11:54:12 +02:00
Christian Decker
895542c6f1 paymod: Simplify retry mod logic and add abort logic 2020-07-02 11:54:12 +02:00
Christian Decker
73fc10e25f paymod: Parse error from waitsendpay and exclude failed chans 2020-07-02 11:54:12 +02:00
Christian Decker
0b85b983ac paymod: Teach the retry_mod not to insist when it's futile
An important life lesson: if there is no path to happiness, then trying harder
will still not get you there.
2020-07-02 11:54:12 +02:00
Christian Decker
10f231bcb5 paymod: Include excludes resulting from channel_hints for getrotue 2020-07-02 11:54:12 +02:00
Christian Decker
5e3134083e paymod: Add a local_channel_hints modifier to collect local channels
We can have quite detailed information about our local channels, so call
`listpeers` before the `getroute` call on the root payment, to seed that
information in the channel_hints.
2020-07-02 11:54:12 +02:00
Christian Decker
b1e9f4923b paymod: Add the final cltv delta to the getroute call 2020-07-02 11:54:12 +02:00
Christian Decker
6af5ab9504 paymod: Move onion payload construction into its own function
Suggested-by: Rusty Russell <@rustyrussell>
2020-07-01 12:19:02 +02:00
Christian Decker
b15876c112 paymod: Implement TLV onion payload generation 2020-07-01 12:19:02 +02:00
Christian Decker
958eb41cbb paymod: Do not pass cmd to sub-payments, plugin suffices
We were passing the `cmd` instance around where `plugin` suffices (used to
start RPC calls and logs).
2020-07-01 12:19:02 +02:00
Christian Decker
df94ec35ba paymod: Do not reply to the same JSON-RPC command multiple times 2020-07-01 12:19:02 +02:00
Christian Decker
8207b4eac8 paymod: Use reasonable partids
We were just handwaving the partid generation, which broke some tests that
expected the first payment attempt to always have partid=0, so here we just
track the partids assigned in the payment tree, starting at 0.
2020-07-01 12:19:02 +02:00
Christian Decker
04c9c5e0d1 paymod: Collect and return results of a tree of partial payments
The status of what started as a simple JSON-RPC call is now spread across an
entire tree of partial payments and payment attempts. So we collect the status
in a single struct in order to report back success of failure.
2020-07-01 12:19:02 +02:00
Christian Decker
4fec969062 paymod: Parse and store the waitsendpay result
This is necessary so we can later aggregate across an entire tree of attempts
and report success or failure to the RPC caller.
2020-07-01 12:19:02 +02:00
Christian Decker
6fb81bf203 paymod: Call waitsendpay on the sendonion we just queued 2020-07-01 12:19:02 +02:00
Christian Decker
d8ebe6fbcd paymod: Parse createonion result and call sendonion 2020-07-01 12:19:02 +02:00
Christian Decker
d37b8548fb paymod: Call createonion to generate the onion and associated data
After we gave each modifier a chance to have its say, we can now proceed to
generate the onion that's going to be sent in the next step.
2020-07-01 12:19:02 +02:00
Christian Decker
5f32cfe9cd paymod: Implement legacy onion payload computation
This is just for testing for now, TLV payload computation will come next. We
stage all the payloads in deserialized form so modifiers can modify them more
easily and serialize them only before actually calling `createonion`.
2020-07-01 12:19:02 +02:00
Christian Decker
5ef7297e51 paymod: Add a getinfo call on payment_start to get the blockheight
This is necessary so we can build the absolute locktimes in the next step. For
now just fetch the blockheight on each (sub-)payment, later we can reuse the
root blockheight if it ends up using too much traffic.
2020-07-01 12:19:02 +02:00
Christian Decker
3c3e2c9c8f paymod: Implement getroute call 2020-07-01 12:19:02 +02:00
Christian Decker
ce0025c95c paymod: Implement bubbling results up the hierarchy of payments
A payment is considered finished if it is in a final state (success or
failure) or all its sub-payments are finished. If that's the case we notify
`payment_finished` and bubble up through `payment_child_finished`, eventually
bubbling up to the root, which can then report success of failure back to the
RPC command that initiated the whole process.
2020-07-01 12:19:02 +02:00
Christian Decker
5c32e33aab paymod: Add a retry modifier that retries payments on failure
This is likely a bit of overkill for this type of functionality, but it is a
nice first use-case of how functionality can be compartmentalized into
modifiers. If makes swapping retry mechanisms in and out really simple.
2020-07-01 12:19:02 +02:00
Christian Decker
aeb5cc0b7c paymod: Generate type-safe accessor functions for modifier data
This should make it easy for JSON-RPC functions and modifiers to get the
associated data for a given modifier name. Useful if a modifier needs to
access its parent's modifier data, or in other functions that need to access
modifier data, e.g., when passing destination pointers into the `param()`
call.
2020-07-01 12:19:02 +02:00
Christian Decker
23b4dca3c7 paymod: Add a simple test-command to test the paymod state-machine
This commit can be reverted/skipped once we have implemented all the logic and
have feature parity with the normal `pay`. It's main purpose is to expose the
unfinished functionality to test it, without completely breaking the existing
`pay` command.
2020-07-01 12:19:02 +02:00
Christian Decker
5d1725209d paymod: Implement base state-machine transitions
The actual steps are mocked out, but we can already run through the various
phases of a payment, and the modifiers should be called for each state.
2020-07-01 12:19:02 +02:00
Christian Decker
8138ef136f plugin: Add a data backend for the new payment state-machine 2020-07-01 12:19:02 +02:00