2023-07-31 11:21:22 +09:30
|
|
|
#include "config.h"
|
|
|
|
#include <ccan/array_size/array_size.h>
|
|
|
|
#include <ccan/cast/cast.h>
|
|
|
|
#include <ccan/htable/htable_type.h>
|
|
|
|
#include <ccan/tal/str/str.h>
|
|
|
|
#include <common/bolt11.h>
|
|
|
|
#include <common/bolt12_merkle.h>
|
|
|
|
#include <common/gossmap.h>
|
2023-12-13 16:05:43 +10:30
|
|
|
#include <common/gossmods_listpeerchannels.h>
|
2023-07-31 11:21:22 +09:30
|
|
|
#include <common/json_param.h>
|
|
|
|
#include <common/json_stream.h>
|
|
|
|
#include <common/memleak.h>
|
|
|
|
#include <common/pseudorand.h>
|
|
|
|
#include <common/type_to_string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <plugins/renepay/pay.h>
|
|
|
|
#include <plugins/renepay/pay_flow.h>
|
|
|
|
#include <plugins/renepay/uncertainty_network.h>
|
|
|
|
|
|
|
|
// TODO(eduardo): maybe there are too many debug_err and plugin_err and
|
|
|
|
// plugin_log(...,LOG_BROKEN,...) that could be resolved with a command_fail
|
|
|
|
|
2023-07-31 11:21:25 +09:30
|
|
|
// TODO(eduardo): notice that pending attempts performed with another
|
|
|
|
// pay plugin are not considered by the uncertainty network in renepay,
|
|
|
|
// it would be nice if listsendpay would give us the route of pending
|
|
|
|
// sendpays.
|
|
|
|
|
2023-07-31 11:21:22 +09:30
|
|
|
#define INVALID_ID UINT64_MAX
|
|
|
|
#define MAX(a,b) ((a)>(b)? (a) : (b))
|
2023-07-31 11:21:25 +09:30
|
|
|
#define MIN(a,b) ((a)<(b)? (a) : (b))
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-10 11:29:42 +09:30
|
|
|
struct pay_plugin *pay_plugin;
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
static void memleak_mark(struct plugin *p, struct htable *memtable)
|
|
|
|
{
|
2023-08-10 11:29:42 +09:30
|
|
|
memleak_scan_obj(memtable, pay_plugin);
|
2023-07-31 11:21:25 +09:30
|
|
|
memleak_scan_htable(memtable, &pay_plugin->chan_extra_map->raw);
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
static const char *init(struct plugin *p,
|
|
|
|
const char *buf UNUSED, const jsmntok_t *config UNUSED)
|
|
|
|
{
|
|
|
|
size_t num_channel_updates_rejected;
|
|
|
|
|
2023-08-10 11:29:42 +09:30
|
|
|
tal_steal(p, pay_plugin);
|
2023-07-31 11:21:22 +09:30
|
|
|
pay_plugin->plugin = p;
|
2023-07-31 11:21:25 +09:30
|
|
|
pay_plugin->last_time = 0;
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
rpc_scan(p, "getinfo", take(json_out_obj(NULL, NULL, NULL)),
|
|
|
|
"{id:%}", JSON_SCAN(json_to_node_id, &pay_plugin->my_id));
|
|
|
|
|
|
|
|
rpc_scan(p, "listconfigs",
|
|
|
|
take(json_out_obj(NULL, NULL, NULL)),
|
|
|
|
"{configs:"
|
|
|
|
"{max-locktime-blocks:{value_int:%},"
|
|
|
|
"experimental-offers:{set:%}}}",
|
|
|
|
JSON_SCAN(json_to_number, &pay_plugin->maxdelay_default),
|
|
|
|
JSON_SCAN(json_to_bool, &pay_plugin->exp_offers)
|
|
|
|
);
|
|
|
|
|
|
|
|
list_head_init(&pay_plugin->payments);
|
|
|
|
|
2023-08-10 11:29:42 +09:30
|
|
|
pay_plugin->chan_extra_map = tal(pay_plugin,struct chan_extra_map);
|
2023-07-31 11:21:22 +09:30
|
|
|
chan_extra_map_init(pay_plugin->chan_extra_map);
|
|
|
|
|
2023-08-10 11:29:42 +09:30
|
|
|
pay_plugin->payflow_map = tal(pay_plugin,struct payflow_map);
|
2023-07-31 11:21:22 +09:30
|
|
|
payflow_map_init(pay_plugin->payflow_map);
|
|
|
|
|
2023-08-10 11:29:42 +09:30
|
|
|
pay_plugin->gossmap = gossmap_load(pay_plugin,
|
2023-07-31 11:21:22 +09:30
|
|
|
GOSSIP_STORE_FILENAME,
|
|
|
|
&num_channel_updates_rejected);
|
|
|
|
|
|
|
|
if (!pay_plugin->gossmap)
|
|
|
|
plugin_err(p, "Could not load gossmap %s: %s",
|
|
|
|
GOSSIP_STORE_FILENAME, strerror(errno));
|
|
|
|
if (num_channel_updates_rejected)
|
|
|
|
plugin_log(p, LOG_DBG,
|
|
|
|
"gossmap ignored %zu channel updates",
|
|
|
|
num_channel_updates_rejected);
|
|
|
|
|
|
|
|
uncertainty_network_update(pay_plugin->gossmap,
|
|
|
|
pay_plugin->chan_extra_map);
|
|
|
|
plugin_set_memleak_handler(p, memleak_mark);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sometimes we don't know exactly who to blame... */
|
2023-08-10 11:29:44 +09:30
|
|
|
static struct pf_result *handle_unhandleable_error(struct pay_flow *pf,
|
2023-08-10 11:29:44 +09:30
|
|
|
const char *what)
|
2023-07-31 11:21:22 +09:30
|
|
|
{
|
|
|
|
plugin_log(pay_plugin->plugin,LOG_DBG,"calling %s",__PRETTY_FUNCTION__);
|
2023-08-10 11:29:44 +09:30
|
|
|
size_t n = tal_count(pf);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
/* We got a mangled reply. We don't know who to penalize! */
|
plugins/renepay: neaten the command notifications.
It now looks like (for test_hardmpp):
```
# we have computed a set of 1 flows with probability 0.328, fees 0msat and delay 23
# Flow 1: amount=1800000000msat prob=0.328 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0->-103x3x0/1->
# Flow 1: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 1: Failure of 1800000000msat for 103x5x0/0 capacity [0msat,3000000000msat] -> [0msat,1799999999msat]
# we have computed a set of 2 flows with probability 0.115, fees 0msat and delay 23
# Flow 2: amount=500000000msat prob=0.475 fees=0msat delay=12 path=-103x6x0/0(min=max=4294967295msat)->-103x1x0/1->-103x4x0/1->
# Flow 3: amount=1300000000msat prob=0.242 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1799999999msat)->-103x3x0/1->
# Flow 3: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 3: Failure of 1300000000msat for 103x5x0/0 capacity [0msat,1799999999msat] -> [0msat,1299999999msat]
# we have computed a set of 2 flows with probability 0.084, fees 0msat and delay 23
# Flow 4: amount=260000000msat prob=0.467 fees=0msat delay=12 path=-103x6x0/0(500000000msat in 1 htlcs,min=max=4294967295msat)->-103x1x0/1(500000000msat in 1 htlcs)->-103x4x0/1(500000000msat in 1 htlcs)->
# Flow 5: amount=1040000000msat prob=0.179 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1299999999msat)->-103x3x0/1->
# Flow 5: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 5: Failure of 1040000000msat for 103x5x0/0 capacity [0msat,1299999999msat] -> [0msat,1039999999msat]
# we have computed a set of 2 flows with probability 0.052, fees 0msat and delay 23
# Flow 6: amount=120000000msat prob=0.494 fees=0msat delay=12 path=-103x6x0/0(760000000msat in 2 htlcs,min=max=4294967295msat)->-103x1x0/1(760000000msat in 2 htlcs)->-103x4x0/1(760000000msat in 2 htlcs)->
# Flow 7: amount=920000000msat prob=0.105 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1039999999msat)->-103x3x0/1->
# Flow 7: Success
```
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2023-08-21 15:08:46 +09:30
|
|
|
payflow_note(pf, LOG_UNUSUAL, "%s on route %s",
|
|
|
|
what, flow_path_to_str(tmpctx, pf));
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
if (n == 1)
|
|
|
|
{
|
2023-08-10 11:29:44 +09:30
|
|
|
/* This is a terminal error. */
|
2023-08-10 11:29:44 +09:30
|
|
|
return pay_flow_failed_final(pf, PAY_UNPARSEABLE_ONION, what);
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
/* FIXME: check chan_extra_map, since we might have succeeded though
|
|
|
|
* this node before? */
|
|
|
|
|
|
|
|
/* Prefer a node not directly connected to either end. */
|
|
|
|
if (n > 3) {
|
|
|
|
/* us ->0-> ourpeer ->1-> rando ->2-> theirpeer ->3-> dest */
|
|
|
|
n = 1 + pseudorand(n - 2);
|
|
|
|
} else
|
|
|
|
/* Assume it's not the destination */
|
|
|
|
n = pseudorand(n-1);
|
|
|
|
|
2023-08-21 15:09:05 +09:30
|
|
|
payflow_disable_chan(pf, pf->path_scidds[n].scid,
|
|
|
|
LOG_INFORM, "randomly chosen");
|
2023-08-10 11:29:44 +09:30
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
return pay_flow_failed(pf);
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
/* We hold onto the flow (and delete the timer) while we're waiting for
|
|
|
|
* gossipd to receive the channel_update we got from the error. */
|
|
|
|
struct addgossip {
|
|
|
|
struct short_channel_id scid;
|
2023-08-10 11:29:44 +09:30
|
|
|
struct pay_flow *pf;
|
2023-07-31 11:21:22 +09:30
|
|
|
};
|
|
|
|
|
|
|
|
static struct command_result *addgossip_done(struct command *cmd,
|
|
|
|
const char *buf,
|
|
|
|
const jsmntok_t *err,
|
|
|
|
struct addgossip *adg)
|
|
|
|
{
|
|
|
|
plugin_log(pay_plugin->plugin,LOG_DBG,"calling %s",__PRETTY_FUNCTION__);
|
|
|
|
|
2023-08-14 16:54:46 +09:30
|
|
|
/* This may free adg (pf is the parent), or otherwise it'll
|
|
|
|
* happen later. */
|
2023-08-10 11:29:44 +09:30
|
|
|
pay_flow_finished_adding_gossip(adg->pf);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2024-02-15 15:57:21 +01:00
|
|
|
bool gossmap_changed = gossmap_refresh(pay_plugin->gossmap, NULL);
|
|
|
|
|
|
|
|
if (pay_plugin->gossmap == NULL)
|
|
|
|
plugin_err(pay_plugin->plugin, "Failed to refresh gossmap: %s",
|
|
|
|
strerror(errno));
|
|
|
|
|
|
|
|
if (gossmap_changed)
|
|
|
|
uncertainty_network_update(pay_plugin->gossmap,
|
|
|
|
pay_plugin->chan_extra_map);
|
|
|
|
|
2023-07-31 11:21:22 +09:30
|
|
|
return command_still_pending(cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct command_result *addgossip_failure(struct command *cmd,
|
|
|
|
const char *buf,
|
|
|
|
const jsmntok_t *err,
|
|
|
|
struct addgossip *adg)
|
|
|
|
|
|
|
|
{
|
|
|
|
plugin_log(pay_plugin->plugin,LOG_DBG,"calling %s",__PRETTY_FUNCTION__);
|
|
|
|
|
2023-08-21 15:09:05 +09:30
|
|
|
payflow_disable_chan(adg->pf, adg->scid,
|
|
|
|
LOG_INFORM, "addgossip failed (%.*s)",
|
|
|
|
err->end - err->start, buf + err->start);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
return addgossip_done(cmd, buf, err, adg);
|
|
|
|
}
|
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
static struct pf_result *submit_update(struct pay_flow *pf,
|
2023-08-10 11:29:44 +09:30
|
|
|
const u8 *update,
|
|
|
|
struct short_channel_id errscid)
|
2023-07-31 11:21:22 +09:30
|
|
|
{
|
|
|
|
plugin_log(pay_plugin->plugin,LOG_DBG,"calling %s",__PRETTY_FUNCTION__);
|
|
|
|
struct out_req *req;
|
2023-08-10 11:29:44 +09:30
|
|
|
struct addgossip *adg = tal(pf, struct addgossip);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
/* We need to stash scid in case this fails, and we need to hold flow so
|
|
|
|
* we don't get a rexmit before this is complete. */
|
|
|
|
adg->scid = errscid;
|
2023-08-10 11:29:44 +09:30
|
|
|
adg->pf = pf;
|
2023-07-31 11:21:22 +09:30
|
|
|
|
plugins/renepay: neaten the command notifications.
It now looks like (for test_hardmpp):
```
# we have computed a set of 1 flows with probability 0.328, fees 0msat and delay 23
# Flow 1: amount=1800000000msat prob=0.328 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0->-103x3x0/1->
# Flow 1: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 1: Failure of 1800000000msat for 103x5x0/0 capacity [0msat,3000000000msat] -> [0msat,1799999999msat]
# we have computed a set of 2 flows with probability 0.115, fees 0msat and delay 23
# Flow 2: amount=500000000msat prob=0.475 fees=0msat delay=12 path=-103x6x0/0(min=max=4294967295msat)->-103x1x0/1->-103x4x0/1->
# Flow 3: amount=1300000000msat prob=0.242 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1799999999msat)->-103x3x0/1->
# Flow 3: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 3: Failure of 1300000000msat for 103x5x0/0 capacity [0msat,1799999999msat] -> [0msat,1299999999msat]
# we have computed a set of 2 flows with probability 0.084, fees 0msat and delay 23
# Flow 4: amount=260000000msat prob=0.467 fees=0msat delay=12 path=-103x6x0/0(500000000msat in 1 htlcs,min=max=4294967295msat)->-103x1x0/1(500000000msat in 1 htlcs)->-103x4x0/1(500000000msat in 1 htlcs)->
# Flow 5: amount=1040000000msat prob=0.179 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1299999999msat)->-103x3x0/1->
# Flow 5: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 5: Failure of 1040000000msat for 103x5x0/0 capacity [0msat,1299999999msat] -> [0msat,1039999999msat]
# we have computed a set of 2 flows with probability 0.052, fees 0msat and delay 23
# Flow 6: amount=120000000msat prob=0.494 fees=0msat delay=12 path=-103x6x0/0(760000000msat in 2 htlcs,min=max=4294967295msat)->-103x1x0/1(760000000msat in 2 htlcs)->-103x4x0/1(760000000msat in 2 htlcs)->
# Flow 7: amount=920000000msat prob=0.105 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1039999999msat)->-103x3x0/1->
# Flow 7: Success
```
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2023-08-21 15:08:46 +09:30
|
|
|
payflow_note(pf, LOG_DBG, "... extracted channel_update %s, telling gossipd", tal_hex(tmpctx, update));
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
req = jsonrpc_request_start(pay_plugin->plugin, NULL, "addgossip",
|
|
|
|
addgossip_done,
|
|
|
|
addgossip_failure,
|
|
|
|
adg);
|
|
|
|
json_add_hex_talarr(req->js, "message", update);
|
2023-08-10 11:29:44 +09:30
|
|
|
send_outreq(pay_plugin->plugin, req);
|
|
|
|
|
|
|
|
/* Don't retry until we call pay_flow_finished_adding_gossip! */
|
2023-08-10 11:29:44 +09:30
|
|
|
return pay_flow_failed_adding_gossip(pf);
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
/* Fix up the channel_update to include the type if it doesn't currently have
|
|
|
|
* one. See ElementsProject/lightning#1730 and lightningnetwork/lnd#1599 for the
|
|
|
|
* in-depth discussion on why we break message parsing here... */
|
|
|
|
static u8 *patch_channel_update(const tal_t *ctx, u8 *channel_update TAKES)
|
|
|
|
{
|
|
|
|
u8 *fixed;
|
|
|
|
if (channel_update != NULL &&
|
|
|
|
fromwire_peektype(channel_update) != WIRE_CHANNEL_UPDATE) {
|
|
|
|
/* This should be a channel_update, prefix with the
|
|
|
|
* WIRE_CHANNEL_UPDATE type, but isn't. Let's prefix it. */
|
|
|
|
fixed = tal_arr(ctx, u8, 0);
|
|
|
|
towire_u16(&fixed, WIRE_CHANNEL_UPDATE);
|
|
|
|
towire(&fixed, channel_update, tal_bytelen(channel_update));
|
|
|
|
if (taken(channel_update))
|
|
|
|
tal_free(channel_update);
|
|
|
|
return fixed;
|
|
|
|
} else {
|
|
|
|
return tal_dup_talarr(ctx, u8, channel_update);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Return NULL if the wrapped onion error message has no channel_update field,
|
|
|
|
* or return the embedded channel_update message otherwise. */
|
|
|
|
static u8 *channel_update_from_onion_error(const tal_t *ctx,
|
2023-08-10 09:31:15 +09:30
|
|
|
const u8 *onion_message)
|
2023-07-31 11:21:22 +09:30
|
|
|
{
|
|
|
|
u8 *channel_update = NULL;
|
|
|
|
struct amount_msat unused_msat;
|
|
|
|
u32 unused32;
|
|
|
|
|
|
|
|
/* Identify failcodes that have some channel_update.
|
|
|
|
*
|
|
|
|
* TODO > BOLT 1.0: Add new failcodes when updating to a
|
|
|
|
* new BOLT version. */
|
|
|
|
if (!fromwire_temporary_channel_failure(ctx,
|
|
|
|
onion_message,
|
|
|
|
&channel_update) &&
|
|
|
|
!fromwire_amount_below_minimum(ctx,
|
|
|
|
onion_message, &unused_msat,
|
|
|
|
&channel_update) &&
|
|
|
|
!fromwire_fee_insufficient(ctx,
|
|
|
|
onion_message, &unused_msat,
|
|
|
|
&channel_update) &&
|
|
|
|
!fromwire_incorrect_cltv_expiry(ctx,
|
|
|
|
onion_message, &unused32,
|
|
|
|
&channel_update) &&
|
|
|
|
!fromwire_expiry_too_soon(ctx,
|
|
|
|
onion_message,
|
|
|
|
&channel_update))
|
|
|
|
/* No channel update. */
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return patch_channel_update(ctx, take(channel_update));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Once we've sent it, we immediate wait for reply. */
|
|
|
|
static struct command_result *flow_sent(struct command *cmd,
|
|
|
|
const char *buf,
|
|
|
|
const jsmntok_t *result,
|
2023-08-10 11:29:44 +09:30
|
|
|
struct pay_flow *pf)
|
2023-07-31 11:21:22 +09:30
|
|
|
{
|
|
|
|
plugin_log(pay_plugin->plugin,LOG_DBG,"calling %s",__PRETTY_FUNCTION__);
|
|
|
|
return command_still_pending(cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sendpay really only fails immediately in two ways:
|
|
|
|
* 1. We screwed up and misused the API.
|
|
|
|
* 2. The first peer is disconnected.
|
|
|
|
*/
|
|
|
|
static struct command_result *flow_sendpay_failed(struct command *cmd,
|
|
|
|
const char *buf,
|
|
|
|
const jsmntok_t *err,
|
2023-08-10 11:29:44 +09:30
|
|
|
struct pay_flow *pf)
|
2023-07-31 11:21:22 +09:30
|
|
|
{
|
2023-08-10 11:29:44 +09:30
|
|
|
struct payment *payment = pf->payment;
|
2023-08-10 09:31:15 +09:30
|
|
|
enum jsonrpc_errcode errcode;
|
|
|
|
const char *msg;
|
|
|
|
|
2023-07-31 11:21:22 +09:30
|
|
|
plugin_log(pay_plugin->plugin,LOG_DBG,"calling %s",__PRETTY_FUNCTION__);
|
|
|
|
|
2023-09-18 14:23:46 +09:30
|
|
|
assert(payment);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-10 09:31:15 +09:30
|
|
|
if (json_scan(tmpctx, buf, err,
|
|
|
|
"{code:%,message:%}",
|
|
|
|
JSON_SCAN(json_to_jsonrpc_errcode, &errcode),
|
|
|
|
JSON_SCAN_TAL(tmpctx, json_strdup, &msg))) {
|
2023-08-29 13:51:33 +09:30
|
|
|
plugin_err(pay_plugin->plugin, "Bad fail from sendpay: %.*s",
|
2023-07-31 11:21:22 +09:30
|
|
|
json_tok_full_len(err), json_tok_full(buf, err));
|
2023-08-10 09:31:15 +09:30
|
|
|
}
|
2023-07-31 11:21:22 +09:30
|
|
|
if (errcode != PAY_TRY_OTHER_ROUTE)
|
2023-08-29 13:51:33 +09:30
|
|
|
plugin_err(pay_plugin->plugin, "Strange error from sendpay: %.*s",
|
2023-07-31 11:21:22 +09:30
|
|
|
json_tok_full_len(err), json_tok_full(buf, err));
|
|
|
|
|
|
|
|
/* There is no new knowledge from this kind of failure.
|
|
|
|
* We just disable this scid. */
|
2023-08-21 15:09:05 +09:30
|
|
|
payflow_disable_chan(pf, pf->path_scidds[0].scid,
|
|
|
|
LOG_INFORM,
|
|
|
|
"sendpay didn't like first hop: %s", msg);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
pay_flow_failed(pf);
|
2023-07-31 11:21:22 +09:30
|
|
|
return command_still_pending(cmd);
|
|
|
|
}
|
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
/* Kick off all pay_flows which are in state PAY_FLOW_NOT_STARTED */
|
|
|
|
static void sendpay_new_flows(struct payment *p)
|
2023-07-31 11:21:22 +09:30
|
|
|
{
|
2023-08-10 11:29:44 +09:30
|
|
|
struct pay_flow *pf;
|
|
|
|
|
|
|
|
list_for_each(&p->flows, pf, list) {
|
plugins/renepay: neaten the command notifications.
It now looks like (for test_hardmpp):
```
# we have computed a set of 1 flows with probability 0.328, fees 0msat and delay 23
# Flow 1: amount=1800000000msat prob=0.328 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0->-103x3x0/1->
# Flow 1: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 1: Failure of 1800000000msat for 103x5x0/0 capacity [0msat,3000000000msat] -> [0msat,1799999999msat]
# we have computed a set of 2 flows with probability 0.115, fees 0msat and delay 23
# Flow 2: amount=500000000msat prob=0.475 fees=0msat delay=12 path=-103x6x0/0(min=max=4294967295msat)->-103x1x0/1->-103x4x0/1->
# Flow 3: amount=1300000000msat prob=0.242 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1799999999msat)->-103x3x0/1->
# Flow 3: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 3: Failure of 1300000000msat for 103x5x0/0 capacity [0msat,1799999999msat] -> [0msat,1299999999msat]
# we have computed a set of 2 flows with probability 0.084, fees 0msat and delay 23
# Flow 4: amount=260000000msat prob=0.467 fees=0msat delay=12 path=-103x6x0/0(500000000msat in 1 htlcs,min=max=4294967295msat)->-103x1x0/1(500000000msat in 1 htlcs)->-103x4x0/1(500000000msat in 1 htlcs)->
# Flow 5: amount=1040000000msat prob=0.179 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1299999999msat)->-103x3x0/1->
# Flow 5: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 5: Failure of 1040000000msat for 103x5x0/0 capacity [0msat,1299999999msat] -> [0msat,1039999999msat]
# we have computed a set of 2 flows with probability 0.052, fees 0msat and delay 23
# Flow 6: amount=120000000msat prob=0.494 fees=0msat delay=12 path=-103x6x0/0(760000000msat in 2 htlcs,min=max=4294967295msat)->-103x1x0/1(760000000msat in 2 htlcs)->-103x4x0/1(760000000msat in 2 htlcs)->
# Flow 7: amount=920000000msat prob=0.105 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1039999999msat)->-103x3x0/1->
# Flow 7: Success
```
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2023-08-21 15:08:46 +09:30
|
|
|
struct out_req *req;
|
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
if (pf->state != PAY_FLOW_NOT_STARTED)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* FIXME: We don't actually want cmd to own this sendpay, so we use NULL here,
|
|
|
|
* but we should use a variant which allows us to set json id! */
|
|
|
|
req = jsonrpc_request_start(pay_plugin->plugin, NULL, "sendpay",
|
2023-07-31 11:21:22 +09:30
|
|
|
flow_sent, flow_sendpay_failed,
|
2023-08-10 11:29:44 +09:30
|
|
|
pf);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
json_array_start(req->js, "route");
|
2023-08-10 11:29:44 +09:30
|
|
|
for (size_t j = 0; j < tal_count(pf->path_nodes); j++) {
|
2023-07-31 11:21:22 +09:30
|
|
|
json_object_start(req->js, NULL);
|
|
|
|
json_add_node_id(req->js, "id",
|
2023-08-10 11:29:44 +09:30
|
|
|
&pf->path_nodes[j]);
|
2023-07-31 11:21:22 +09:30
|
|
|
json_add_short_channel_id(req->js, "channel",
|
2023-08-21 15:07:07 +09:30
|
|
|
&pf->path_scidds[j].scid);
|
2023-07-31 11:21:22 +09:30
|
|
|
json_add_amount_msat(req->js, "amount_msat",
|
2023-08-10 11:29:44 +09:30
|
|
|
pf->amounts[j]);
|
2023-07-31 11:21:22 +09:30
|
|
|
json_add_num(req->js, "direction",
|
2023-08-21 15:07:07 +09:30
|
|
|
pf->path_scidds[j].dir);
|
2023-07-31 11:21:22 +09:30
|
|
|
json_add_u32(req->js, "delay",
|
2023-08-10 11:29:44 +09:30
|
|
|
pf->cltv_delays[j]);
|
2023-07-31 11:21:22 +09:30
|
|
|
json_add_string(req->js,"style","tlv");
|
|
|
|
json_object_end(req->js);
|
|
|
|
}
|
|
|
|
json_array_end(req->js);
|
|
|
|
|
|
|
|
json_add_sha256(req->js, "payment_hash", &p->payment_hash);
|
|
|
|
json_add_secret(req->js, "payment_secret", p->payment_secret);
|
|
|
|
|
2023-08-29 14:59:16 +09:30
|
|
|
/* FIXME: sendpay has a check that we don't total more than
|
|
|
|
* the exact amount, if we're setting partid (i.e. MPP). However,
|
|
|
|
* we always set partid, and we add a shadow amount *if we've
|
|
|
|
* only have one part*, so we have to use that amount here.
|
|
|
|
*
|
|
|
|
* The spec was loosened so you are actually allowed
|
|
|
|
* to overpay, so this check is now overzealous. */
|
|
|
|
if (amount_msat_greater(payflow_delivered(pf), p->amount)) {
|
|
|
|
json_add_amount_msat(req->js, "amount_msat",
|
|
|
|
payflow_delivered(pf));
|
|
|
|
} else {
|
|
|
|
json_add_amount_msat(req->js, "amount_msat", p->amount);
|
|
|
|
}
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
json_add_u64(req->js, "partid", pf->key.partid);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
json_add_u64(req->js, "groupid", p->groupid);
|
|
|
|
if (p->payment_metadata)
|
|
|
|
json_add_hex_talarr(req->js, "payment_metadata",
|
|
|
|
p->payment_metadata);
|
|
|
|
|
|
|
|
/* FIXME: We don't need these three for all payments! */
|
|
|
|
if (p->label)
|
|
|
|
json_add_string(req->js, "label", p->label);
|
|
|
|
json_add_string(req->js, "bolt11", p->invstr);
|
|
|
|
if (p->description)
|
|
|
|
json_add_string(req->js, "description", p->description);
|
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
send_outreq(pay_plugin->plugin, req);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
/* Now you're started! */
|
|
|
|
pf->state = PAY_FLOW_IN_PROGRESS;
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
/* Safety check. */
|
|
|
|
payment_assert_delivering_all(p);
|
|
|
|
}
|
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
const char *try_paying(const tal_t *ctx,
|
|
|
|
struct payment *payment,
|
|
|
|
enum jsonrpc_errcode *ecode)
|
2023-07-31 11:21:22 +09:30
|
|
|
{
|
|
|
|
plugin_log(pay_plugin->plugin,LOG_DBG,"calling %s",__PRETTY_FUNCTION__);
|
|
|
|
|
|
|
|
struct amount_msat feebudget, fees_spent, remaining;
|
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
assert(payment->status == PAYMENT_PENDING);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
/* Total feebudget */
|
2023-08-10 09:31:08 +09:30
|
|
|
if (!amount_msat_sub(&feebudget, payment->maxspend, payment->amount))
|
2023-07-31 11:21:22 +09:30
|
|
|
{
|
|
|
|
plugin_err(pay_plugin->plugin,
|
|
|
|
"%s (line %d) could not substract maxspend=%s and amount=%s.",
|
|
|
|
__PRETTY_FUNCTION__,
|
|
|
|
__LINE__,
|
2023-08-10 09:31:08 +09:30
|
|
|
type_to_string(tmpctx, struct amount_msat, &payment->maxspend),
|
|
|
|
type_to_string(tmpctx, struct amount_msat, &payment->amount));
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
/* Fees spent so far */
|
2023-08-10 09:31:08 +09:30
|
|
|
if (!amount_msat_sub(&fees_spent, payment->total_sent, payment->total_delivering))
|
2023-07-31 11:21:22 +09:30
|
|
|
{
|
|
|
|
plugin_err(pay_plugin->plugin,
|
|
|
|
"%s (line %d) could not substract total_sent=%s and total_delivering=%s.",
|
|
|
|
__PRETTY_FUNCTION__,
|
|
|
|
__LINE__,
|
2023-08-10 09:31:08 +09:30
|
|
|
type_to_string(tmpctx, struct amount_msat, &payment->total_sent),
|
|
|
|
type_to_string(tmpctx, struct amount_msat, &payment->total_delivering));
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
/* Remaining fee budget. */
|
|
|
|
if (!amount_msat_sub(&feebudget, feebudget, fees_spent))
|
|
|
|
{
|
|
|
|
plugin_err(pay_plugin->plugin,
|
|
|
|
"%s (line %d) could not substract feebudget=%s and fees_spent=%s.",
|
|
|
|
__PRETTY_FUNCTION__,
|
|
|
|
__LINE__,
|
|
|
|
type_to_string(tmpctx, struct amount_msat, &feebudget),
|
|
|
|
type_to_string(tmpctx, struct amount_msat, &fees_spent));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* How much are we still trying to send? */
|
2023-08-10 09:31:08 +09:30
|
|
|
if (!amount_msat_sub(&remaining, payment->amount, payment->total_delivering))
|
2023-07-31 11:21:22 +09:30
|
|
|
{
|
|
|
|
plugin_err(pay_plugin->plugin,
|
|
|
|
"%s (line %d) could not substract amount=%s and total_delivering=%s.",
|
|
|
|
__PRETTY_FUNCTION__,
|
|
|
|
__LINE__,
|
2023-08-10 09:31:08 +09:30
|
|
|
type_to_string(tmpctx, struct amount_msat, &payment->amount),
|
|
|
|
type_to_string(tmpctx, struct amount_msat, &payment->total_delivering));
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
// plugin_log(pay_plugin->plugin,LOG_DBG,fmt_chan_extra_map(tmpctx,pay_plugin->chan_extra_map));
|
|
|
|
|
2023-07-31 11:21:25 +09:30
|
|
|
const char *err_msg;
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
/* We let this return an unlikely path, as it's better to try once
|
|
|
|
* than simply refuse. Plus, models are not truth! */
|
2023-08-10 09:31:08 +09:30
|
|
|
gossmap_apply_localmods(pay_plugin->gossmap, payment->local_gossmods);
|
2023-08-10 11:29:44 +09:30
|
|
|
err_msg = add_payflows(tmpctx,
|
|
|
|
payment,
|
|
|
|
remaining, feebudget,
|
|
|
|
/* is entire payment? */
|
2024-02-07 11:25:30 +01:00
|
|
|
amount_msat_eq(remaining, AMOUNT_MSAT(0)),
|
2023-08-10 11:29:44 +09:30
|
|
|
ecode);
|
2023-08-10 09:31:08 +09:30
|
|
|
gossmap_remove_localmods(pay_plugin->gossmap, payment->local_gossmods);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
/* MCF cannot find a feasible route, we stop. */
|
2023-08-10 11:29:44 +09:30
|
|
|
if (err_msg)
|
|
|
|
return err_msg;
|
|
|
|
|
2023-07-31 11:21:22 +09:30
|
|
|
/* Now begin making payments */
|
2023-08-10 11:29:44 +09:30
|
|
|
sendpay_new_flows(payment);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
return NULL;
|
2023-08-10 09:31:08 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
static void destroy_cmd_payment_ptr(struct command *cmd,
|
|
|
|
struct payment *payment)
|
|
|
|
{
|
|
|
|
assert(payment->cmd == cmd);
|
|
|
|
payment->cmd = NULL;
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
|
2023-12-13 16:05:43 +10:30
|
|
|
static void gossmod_cb(struct gossmap_localmods *mods,
|
|
|
|
const struct node_id *self,
|
|
|
|
const struct node_id *peer,
|
|
|
|
const struct short_channel_id_dir *scidd,
|
|
|
|
struct amount_msat min,
|
|
|
|
struct amount_msat max,
|
|
|
|
struct amount_msat fee_base,
|
|
|
|
u32 fee_proportional,
|
|
|
|
u32 cltv_delta,
|
|
|
|
bool enabled,
|
|
|
|
const char *buf,
|
|
|
|
const jsmntok_t *chantok,
|
|
|
|
struct payment *payment)
|
|
|
|
{
|
|
|
|
/* Add to gossmap like normal */
|
|
|
|
gossmod_add_localchan(mods, self, peer, scidd, min, max,
|
|
|
|
fee_base, fee_proportional, cltv_delta, enabled, buf, chantok, NULL);
|
|
|
|
|
|
|
|
/* Also update uncertainty map */
|
|
|
|
uncertainty_network_update_from_listpeerchannels(payment, scidd, max, enabled,
|
|
|
|
buf, chantok,
|
|
|
|
pay_plugin->chan_extra_map);
|
|
|
|
}
|
|
|
|
|
2023-07-31 11:21:22 +09:30
|
|
|
static struct command_result *listpeerchannels_done(
|
|
|
|
struct command *cmd,
|
|
|
|
const char *buf,
|
|
|
|
const jsmntok_t *result,
|
2023-08-10 09:31:08 +09:30
|
|
|
struct payment *payment)
|
2023-07-31 11:21:22 +09:30
|
|
|
{
|
|
|
|
plugin_log(pay_plugin->plugin,LOG_DBG,"calling %s",__PRETTY_FUNCTION__);
|
2023-08-10 11:29:44 +09:30
|
|
|
const char *errmsg;
|
|
|
|
enum jsonrpc_errcode ecode;
|
|
|
|
|
2023-12-13 16:05:43 +10:30
|
|
|
payment->local_gossmods = gossmods_from_listpeerchannels(payment, &pay_plugin->my_id,
|
pay: ignore fees on our own channels when determining routing.
I noticed that run-route-infloop chose some worse-looking paths after
routing was fixed, eg the second node:
Before:
Destination node, success, probability, hops, fees, cltv, scid...
02b3aa1e4ed31be83cca4bd367b2c01e39502cb25e282a9b4520ad376a1ba0a01a,1,0.991856,2,1004,40,2572260x39x0/1,2131897x45x0/0
After:
Destination node, success, probability, hops, fees, cltv, scid...
02b3aa1e4ed31be83cca4bd367b2c01e39502cb25e282a9b4520ad376a1ba0a01a,1,0.954540,3,1046,46,2570715x21x0/1,2346882x26x14/1,2131897x45x0/0
This is because although the final costs don't reflect it, routing was taking
into account local channels, and 2572260x39x0/1 has a base fee of 2970.
There's an easy fix: when we the pay plugin creates localmods for our
gossip graph, add all local channels with delay and fees equal to 0.
We do the same thing in our unit test. This improves things across
the board:
Linear success probability (when found): min-max(mean +/- stddev)
Before: 0.487040-0.999543(0.952548+/-0.075)
After: 0.486985-0.999750(0.975978+/-0.053)
Hops:
Before: 1-5(2.98374+/-0.77)
After: 1-5(2.09593+/-0.63)
Fees:
Before: 0-50848(922.457+/-2.7e+03)
After: 0-50041(861.621+/-2.7e+03)
Delay (blocks):
Before: 0-196(65.8081+/-60)
After: 0-190(60.3285+/-60)
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Changed: Plugins: `pay` route algorithm doesn't bias against our own "expensive" channels any more.
2024-03-07 13:26:58 +10:30
|
|
|
buf, result, true,
|
2023-12-13 16:05:43 +10:30
|
|
|
gossmod_cb, payment);
|
|
|
|
|
2023-07-31 11:21:22 +09:30
|
|
|
// TODO(eduardo): check that there won't be a prob. cost associated with
|
|
|
|
// any gossmap local chan. The same way there aren't fees to pay for my
|
|
|
|
// local channels.
|
2023-08-10 09:31:08 +09:30
|
|
|
|
2023-12-13 16:05:43 +10:30
|
|
|
// TODO(eduardo): are there route hints for B12?
|
|
|
|
// Add any extra hidden channel revealed by the routehints to the uncertainty network.
|
|
|
|
uncertainty_network_add_routehints(pay_plugin->chan_extra_map, payment->routes, payment);
|
|
|
|
|
2023-08-10 09:31:08 +09:30
|
|
|
/* From now on, we keep a record of the payment, so persist it beyond this cmd. */
|
|
|
|
tal_steal(pay_plugin->plugin, payment);
|
|
|
|
/* When we terminate cmd for any reason, clear it from payment so we don't do it again. */
|
2023-08-10 11:29:44 +09:30
|
|
|
assert(cmd == payment->cmd);
|
2023-08-10 09:31:08 +09:30
|
|
|
tal_add_destructor2(cmd, destroy_cmd_payment_ptr, payment);
|
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
/* This looks for a route, and if OK, fires off the sendpay commands */
|
|
|
|
errmsg = try_paying(tmpctx, payment, &ecode);
|
|
|
|
if (errmsg)
|
|
|
|
return payment_fail(payment, ecode, "%s", errmsg);
|
|
|
|
|
|
|
|
return command_still_pending(cmd);
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void destroy_payment(struct payment *p)
|
|
|
|
{
|
|
|
|
list_del_from(&pay_plugin->payments, &p->list);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct command_result *json_paystatus(struct command *cmd,
|
|
|
|
const char *buf,
|
|
|
|
const jsmntok_t *params)
|
|
|
|
{
|
|
|
|
const char *invstring;
|
|
|
|
struct json_stream *ret;
|
|
|
|
struct payment *p;
|
|
|
|
|
|
|
|
if (!param(cmd, buf, params,
|
2023-08-07 16:01:41 +09:30
|
|
|
p_opt("invstring", param_invstring, &invstring),
|
2023-07-31 11:21:22 +09:30
|
|
|
NULL))
|
|
|
|
return command_param_failed();
|
|
|
|
|
|
|
|
ret = jsonrpc_stream_success(cmd);
|
|
|
|
json_array_start(ret, "paystatus");
|
|
|
|
|
|
|
|
list_for_each(&pay_plugin->payments, p, list) {
|
|
|
|
if (invstring && !streq(invstring, p->invstr))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
json_object_start(ret, NULL);
|
|
|
|
if (p->label != NULL)
|
|
|
|
json_add_string(ret, "label", p->label);
|
|
|
|
|
|
|
|
if (p->invstr)
|
|
|
|
json_add_invstring(ret,p->invstr);
|
|
|
|
|
|
|
|
json_add_amount_msat(ret, "amount_msat", p->amount);
|
|
|
|
json_add_sha256(ret, "payment_hash", &p->payment_hash);
|
|
|
|
json_add_node_id(ret, "destination", &p->destination);
|
|
|
|
|
|
|
|
if (p->description)
|
|
|
|
json_add_string(ret, "description", p->description);
|
|
|
|
|
|
|
|
json_add_timeabs(ret,"created_at",p->start_time);
|
|
|
|
json_add_u64(ret,"groupid",p->groupid);
|
|
|
|
|
|
|
|
switch(p->status)
|
|
|
|
{
|
|
|
|
case PAYMENT_SUCCESS:
|
|
|
|
json_add_string(ret,"status","complete");
|
2023-09-18 14:23:46 +09:30
|
|
|
assert(p->preimage);
|
2023-07-31 11:21:22 +09:30
|
|
|
json_add_preimage(ret,"payment_preimage",p->preimage);
|
|
|
|
json_add_amount_msat(ret, "amount_sent_msat", p->total_sent);
|
|
|
|
|
|
|
|
break;
|
|
|
|
case PAYMENT_FAIL:
|
|
|
|
json_add_string(ret,"status","failed");
|
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
json_add_string(ret,"status","pending");
|
|
|
|
}
|
|
|
|
|
|
|
|
json_array_start(ret, "notes");
|
|
|
|
for (size_t i = 0; i < tal_count(p->paynotes); i++)
|
|
|
|
json_add_string(ret, NULL, p->paynotes[i]);
|
|
|
|
json_array_end(ret);
|
|
|
|
json_object_end(ret);
|
|
|
|
|
|
|
|
// TODO(eduardo): maybe we should add also:
|
|
|
|
// - payment_secret?
|
|
|
|
// - payment_metadata?
|
|
|
|
// - number of parts?
|
|
|
|
}
|
|
|
|
json_array_end(ret);
|
|
|
|
|
|
|
|
return command_finished(cmd, ret);
|
|
|
|
}
|
|
|
|
|
2023-11-27 14:56:07 +01:00
|
|
|
static struct command_result *selfpay_success(struct command *cmd,
|
|
|
|
const char *buf,
|
|
|
|
const jsmntok_t *result,
|
|
|
|
struct payment *p)
|
|
|
|
{
|
|
|
|
struct preimage preimage;
|
|
|
|
const char *err;
|
|
|
|
err = json_scan(tmpctx, buf, result,
|
|
|
|
"{payment_preimage:%}",
|
|
|
|
JSON_SCAN(json_to_preimage, &preimage));
|
|
|
|
p->preimage = tal_dup(p, struct preimage, &preimage);
|
|
|
|
if (err)
|
|
|
|
plugin_err(cmd->plugin,
|
|
|
|
"selfpay didn't have payment_preimage? %.*s",
|
|
|
|
json_tok_full_len(result),
|
|
|
|
json_tok_full(buf, result));
|
|
|
|
p->status = PAYMENT_SUCCESS;
|
|
|
|
payment_note(p, LOG_DBG, "Paid with self-pay.");
|
|
|
|
return payment_success(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Self-payment used in plugins/pay.c */
|
|
|
|
static struct command_result *selfpay(struct command *cmd, struct payment *p)
|
|
|
|
{
|
|
|
|
struct out_req *req;
|
|
|
|
|
|
|
|
/* From now on, we keep a record of the payment, so persist it beyond this cmd. */
|
|
|
|
tal_steal(pay_plugin->plugin, p);
|
|
|
|
assert(cmd == p->cmd);
|
|
|
|
/* When we terminate cmd for any reason, clear it from payment so we don't do it again. */
|
|
|
|
tal_add_destructor2(cmd, destroy_cmd_payment_ptr, p);
|
|
|
|
|
|
|
|
req = jsonrpc_request_start(cmd->plugin, cmd, "sendpay",
|
|
|
|
selfpay_success,
|
|
|
|
forward_error, p);
|
|
|
|
/* Empty route means "to-self" */
|
|
|
|
json_array_start(req->js, "route");
|
|
|
|
json_array_end(req->js);
|
|
|
|
json_add_sha256(req->js, "payment_hash", &p->payment_hash);
|
|
|
|
if (p->label)
|
|
|
|
json_add_string(req->js, "label", p->label);
|
|
|
|
json_add_amount_msat(req->js, "amount_msat", p->amount);
|
|
|
|
json_add_string(req->js, "bolt11", p->invstr);
|
|
|
|
if (p->payment_secret)
|
|
|
|
json_add_secret(req->js, "payment_secret", p->payment_secret);
|
|
|
|
json_add_u64(req->js, "groupid", p->groupid);
|
|
|
|
if (p->payment_metadata)
|
|
|
|
json_add_hex_talarr(req->js, "payment_metadata", p->payment_metadata);
|
|
|
|
if (p->description)
|
|
|
|
json_add_string(req->js, "description", p->description);
|
|
|
|
|
|
|
|
/* Pretend we have sent partid=1 with the total amount. */
|
|
|
|
p->next_partid = 2;
|
|
|
|
p->total_sent = p->amount;
|
|
|
|
return send_outreq(cmd->plugin, req);
|
|
|
|
}
|
2023-07-31 11:21:25 +09:30
|
|
|
|
2023-07-31 11:21:22 +09:30
|
|
|
/* Taken from ./plugins/pay.c
|
|
|
|
*
|
|
|
|
* We are interested in any prior attempts to pay this payment_hash /
|
|
|
|
* invoice so we can set the `groupid` correctly and ensure we don't
|
|
|
|
* already have a pending payment running. We also collect the summary
|
|
|
|
* about an eventual previous complete payment so we can return that
|
|
|
|
* as a no-op. */
|
|
|
|
static struct command_result *
|
|
|
|
payment_listsendpays_previous(
|
|
|
|
struct command *cmd,
|
|
|
|
const char *buf,
|
|
|
|
const jsmntok_t *result,
|
2023-08-10 09:31:08 +09:30
|
|
|
struct payment * payment)
|
2023-07-31 11:21:22 +09:30
|
|
|
{
|
|
|
|
size_t i;
|
2023-08-10 09:31:15 +09:30
|
|
|
const jsmntok_t *t, *arr;
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-10 09:31:14 +09:30
|
|
|
/* Group ID of the pending payment, this will be the one
|
2023-07-31 11:21:22 +09:30
|
|
|
* who's result gets replayed if we end up suspending. */
|
2023-08-10 09:31:14 +09:30
|
|
|
u64 pending_group_id = INVALID_ID;
|
|
|
|
u64 max_pending_partid=0;
|
|
|
|
u64 max_group_id = 0;
|
2023-07-31 11:21:22 +09:30
|
|
|
struct amount_msat pending_sent = AMOUNT_MSAT(0),
|
|
|
|
pending_msat = AMOUNT_MSAT(0);
|
|
|
|
|
|
|
|
/* Metadata for a complete payment, if one exists. */
|
|
|
|
u32 complete_parts = 0;
|
|
|
|
struct preimage complete_preimage;
|
|
|
|
struct amount_msat complete_sent = AMOUNT_MSAT(0),
|
|
|
|
complete_msat = AMOUNT_MSAT(0);
|
|
|
|
u32 complete_created_at;
|
|
|
|
|
|
|
|
arr = json_get_member(buf, result, "payments");
|
|
|
|
if (!arr || arr->type != JSMN_ARRAY)
|
|
|
|
return command_fail(
|
|
|
|
cmd, LIGHTNINGD,
|
2023-08-10 09:31:15 +09:30
|
|
|
"Unexpected non-array result from listsendpays: %.*s",
|
|
|
|
json_tok_full_len(result),
|
|
|
|
json_tok_full(buf, result));
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
json_for_each_arr(i, t, arr)
|
|
|
|
{
|
2023-11-27 14:56:07 +01:00
|
|
|
u64 partid = 0, groupid;
|
2023-07-31 11:21:22 +09:30
|
|
|
struct amount_msat this_msat, this_sent;
|
2023-08-10 09:31:14 +09:30
|
|
|
const char *status;
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-11-27 14:56:07 +01:00
|
|
|
// TODO: we assume amount_msat is always present, but according
|
|
|
|
// to the documentation this field is optional. How do I
|
|
|
|
// interpret if amount_msat is missing?
|
|
|
|
const char *err =
|
2023-07-31 11:21:22 +09:30
|
|
|
json_scan(tmpctx,buf,t,
|
2023-08-10 09:31:14 +09:30
|
|
|
"{status:%"
|
2023-11-27 14:56:07 +01:00
|
|
|
",partid?:%"
|
2023-07-31 11:21:22 +09:30
|
|
|
",groupid:%"
|
|
|
|
",amount_msat:%"
|
|
|
|
",amount_sent_msat:%}",
|
2023-08-10 09:31:14 +09:30
|
|
|
JSON_SCAN_TAL(tmpctx, json_strdup, &status),
|
2023-07-31 11:21:22 +09:30
|
|
|
JSON_SCAN(json_to_u64,&partid),
|
|
|
|
JSON_SCAN(json_to_u64,&groupid),
|
|
|
|
JSON_SCAN(json_to_msat,&this_msat),
|
|
|
|
JSON_SCAN(json_to_msat,&this_sent));
|
|
|
|
|
2023-11-27 14:56:07 +01:00
|
|
|
if(err)
|
|
|
|
plugin_err(pay_plugin->plugin,
|
|
|
|
"%s json_scan of listsendpay returns the following error: %s",
|
|
|
|
__PRETTY_FUNCTION__,
|
|
|
|
err);
|
|
|
|
|
2023-08-10 09:31:14 +09:30
|
|
|
/* If we decide to create a new group, we base it on max_group_id */
|
|
|
|
if (groupid > max_group_id)
|
2024-02-07 11:25:30 +01:00
|
|
|
max_group_id = groupid;
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-07-31 11:21:25 +09:30
|
|
|
/* status could be completed, pending or failed */
|
2023-08-10 09:31:14 +09:30
|
|
|
if (streq(status, "complete")) {
|
2023-07-31 11:21:22 +09:30
|
|
|
/* Now we know the payment completed. */
|
|
|
|
if(!amount_msat_add(&complete_msat,complete_msat,this_msat))
|
2023-09-18 14:23:46 +09:30
|
|
|
plugin_err(pay_plugin->plugin,"%s (line %d) msat overflow.",
|
2023-07-31 11:21:22 +09:30
|
|
|
__PRETTY_FUNCTION__,__LINE__);
|
|
|
|
if(!amount_msat_add(&complete_sent,complete_sent,this_sent))
|
2023-09-18 14:23:46 +09:30
|
|
|
plugin_err(pay_plugin->plugin,"%s (line %d) msat overflow.",
|
2023-07-31 11:21:22 +09:30
|
|
|
__PRETTY_FUNCTION__,__LINE__);
|
|
|
|
json_scan(tmpctx, buf, t,
|
|
|
|
"{created_at:%"
|
|
|
|
",payment_preimage:%}",
|
|
|
|
JSON_SCAN(json_to_u32, &complete_created_at),
|
|
|
|
JSON_SCAN(json_to_preimage, &complete_preimage));
|
2023-08-10 09:31:14 +09:30
|
|
|
complete_parts++;
|
2023-11-27 14:56:07 +01:00
|
|
|
|
|
|
|
plugin_log(pay_plugin->plugin,LOG_DBG,
|
|
|
|
"this part is complete then "
|
|
|
|
"complete_msat = %s",
|
|
|
|
type_to_string(tmpctx,struct amount_msat,&complete_msat));
|
2023-08-10 09:31:14 +09:30
|
|
|
} else if (streq(status, "pending")) {
|
|
|
|
/* If we have more than one pending group, something went wrong! */
|
|
|
|
if (pending_group_id != INVALID_ID
|
|
|
|
&& groupid != pending_group_id)
|
|
|
|
return command_fail(cmd, PAY_STATUS_UNEXPECTED,
|
|
|
|
"Multiple pending groups for this payment?");
|
|
|
|
pending_group_id = groupid;
|
|
|
|
if (partid > max_pending_partid)
|
|
|
|
max_pending_partid = partid;
|
2024-02-07 11:25:30 +01:00
|
|
|
|
|
|
|
if (!amount_msat_add(&pending_msat, pending_msat,
|
|
|
|
this_msat) ||
|
|
|
|
!amount_msat_add(&pending_sent, pending_sent,
|
|
|
|
this_sent))
|
|
|
|
plugin_err(pay_plugin->plugin,
|
|
|
|
"%s (line %d) msat overflow.",
|
|
|
|
__PRETTY_FUNCTION__, __LINE__);
|
|
|
|
|
2023-08-10 09:31:14 +09:30
|
|
|
} else
|
|
|
|
assert(streq(status, "failed"));
|
2023-07-31 11:21:25 +09:30
|
|
|
}
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-10 09:31:14 +09:30
|
|
|
if (complete_parts != 0) {
|
2023-07-31 11:21:25 +09:30
|
|
|
/* There are completed sendpays, we don't need to do anything
|
|
|
|
* but summarize the result. */
|
2023-07-31 11:21:22 +09:30
|
|
|
struct json_stream *ret = jsonrpc_stream_success(cmd);
|
|
|
|
json_add_preimage(ret, "payment_preimage", &complete_preimage);
|
|
|
|
json_add_string(ret, "status", "complete");
|
|
|
|
json_add_amount_msat(ret, "amount_msat", complete_msat);
|
|
|
|
json_add_amount_msat(ret, "amount_sent_msat",complete_sent);
|
2023-08-10 09:31:08 +09:30
|
|
|
json_add_node_id(ret, "destination", &payment->destination);
|
|
|
|
json_add_sha256(ret, "payment_hash", &payment->payment_hash);
|
2023-07-31 11:21:22 +09:30
|
|
|
json_add_u32(ret, "created_at", complete_created_at);
|
|
|
|
json_add_num(ret, "parts", complete_parts);
|
|
|
|
|
|
|
|
/* This payment was already completed, we don't keep record of
|
2023-08-10 09:31:08 +09:30
|
|
|
* it twice: payment will be freed with cmd */
|
2023-07-31 11:21:22 +09:30
|
|
|
return command_finished(cmd, ret);
|
2023-08-10 09:31:14 +09:30
|
|
|
} else if (pending_group_id != INVALID_ID) {
|
|
|
|
/* Continue where we left off? */
|
|
|
|
payment->groupid = pending_group_id;
|
|
|
|
payment->next_partid = max_pending_partid+1;
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-10 09:31:08 +09:30
|
|
|
payment->total_sent = pending_sent;
|
|
|
|
payment->total_delivering = pending_msat;
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
plugin_log(pay_plugin->plugin,LOG_DBG,
|
|
|
|
"There are pending sendpays to this invoice. "
|
2023-08-03 15:35:54 -04:00
|
|
|
"groupid = %"PRIu64" "
|
2023-07-31 11:21:22 +09:30
|
|
|
"delivering = %s, "
|
2023-08-03 15:35:54 -04:00
|
|
|
"last_partid = %"PRIu64,
|
2023-08-10 09:31:14 +09:30
|
|
|
pending_group_id,
|
2023-08-10 09:31:08 +09:30
|
|
|
type_to_string(tmpctx,struct amount_msat,&payment->total_delivering),
|
2023-08-10 09:31:14 +09:30
|
|
|
max_pending_partid);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-10 09:31:08 +09:30
|
|
|
if(amount_msat_greater_eq(payment->total_delivering,payment->amount))
|
2023-07-31 11:21:22 +09:30
|
|
|
{
|
|
|
|
/* Pending payment already pays the full amount, we
|
|
|
|
* better stop. */
|
2023-08-10 09:31:08 +09:30
|
|
|
return command_fail(cmd, PAY_IN_PROGRESS,
|
2023-07-31 11:21:22 +09:30
|
|
|
"Payment is pending with full amount already commited");
|
|
|
|
}
|
|
|
|
}else
|
|
|
|
{
|
2023-07-31 11:21:25 +09:30
|
|
|
/* There are no pending nor completed sendpays, get me the last
|
|
|
|
* sendpay group. */
|
2023-08-10 09:31:14 +09:30
|
|
|
/* FIXME: use groupid 0 to have sendpay assign an unused groupid,
|
|
|
|
* as this is theoretically racy against other plugins paying the
|
|
|
|
* same thing!
|
|
|
|
* *BUT* that means we have to create one flow first, so we
|
|
|
|
* can match the others. */
|
|
|
|
payment->groupid = max_group_id + 1;
|
2023-08-10 09:31:08 +09:30
|
|
|
payment->next_partid=1;
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
|
2023-11-27 14:56:07 +01:00
|
|
|
/* Bypass everything if we're doing (synchronous) self-pay */
|
|
|
|
if (node_id_eq(&pay_plugin->my_id, &payment->destination))
|
|
|
|
return selfpay(cmd, payment);
|
|
|
|
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
struct out_req *req;
|
|
|
|
/* Get local capacities... */
|
|
|
|
req = jsonrpc_request_start(cmd->plugin, cmd, "listpeerchannels",
|
|
|
|
listpeerchannels_done,
|
2023-08-10 09:31:08 +09:30
|
|
|
listpeerchannels_done, payment);
|
2023-07-31 11:21:22 +09:30
|
|
|
return send_outreq(cmd->plugin, req);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct command_result *json_pay(struct command *cmd,
|
|
|
|
const char *buf,
|
|
|
|
const jsmntok_t *params)
|
|
|
|
{
|
|
|
|
const char *invstr;
|
|
|
|
const char *label;
|
|
|
|
const char *description;
|
|
|
|
struct sha256 * local_offer_id;
|
|
|
|
u64 invexpiry;
|
|
|
|
struct amount_msat *msat, *invmsat;
|
|
|
|
struct amount_msat *maxfee;
|
2023-08-10 09:30:43 +09:30
|
|
|
struct sha256 payment_hash;
|
|
|
|
struct secret *payment_secret;
|
|
|
|
const u8 *payment_metadata;
|
|
|
|
struct node_id destination;
|
2023-07-31 11:21:22 +09:30
|
|
|
u32 *maxdelay;
|
|
|
|
u32 *retryfor;
|
2023-07-31 11:21:25 +09:30
|
|
|
u64 *base_fee_penalty;
|
|
|
|
u64 *prob_cost_factor;
|
|
|
|
u64 *riskfactor_millionths;
|
|
|
|
u64 *min_prob_success_millionths;
|
2023-07-31 11:21:22 +09:30
|
|
|
bool *use_shadow;
|
2023-08-10 09:30:43 +09:30
|
|
|
u16 final_cltv;
|
2023-08-10 09:31:17 +09:30
|
|
|
const struct route_info **routes = NULL;
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
if (!param(cmd, buf, params,
|
2023-08-07 16:01:41 +09:30
|
|
|
p_req("invstring", param_invstring, &invstr),
|
2023-07-31 11:21:22 +09:30
|
|
|
p_opt("amount_msat", param_msat, &msat),
|
|
|
|
p_opt("maxfee", param_msat, &maxfee),
|
|
|
|
|
|
|
|
p_opt_def("maxdelay", param_number, &maxdelay,
|
|
|
|
/* We're initially called to probe usage, before init! */
|
|
|
|
pay_plugin ? pay_plugin->maxdelay_default : 0),
|
|
|
|
|
|
|
|
|
|
|
|
p_opt_def("retry_for", param_number, &retryfor, 60), // 60 seconds
|
|
|
|
p_opt("localofferid", param_sha256, &local_offer_id),
|
|
|
|
p_opt("description", param_string, &description),
|
|
|
|
p_opt("label", param_string, &label),
|
2023-07-31 11:21:25 +09:30
|
|
|
// MCF parameters
|
|
|
|
// TODO(eduardo): are these parameters read correctly?
|
2023-09-21 15:06:28 +09:30
|
|
|
p_opt_dev("dev_base_fee_penalty", param_millionths, &base_fee_penalty,10),
|
|
|
|
p_opt_dev("dev_prob_cost_factor", param_millionths, &prob_cost_factor,10),
|
|
|
|
p_opt_dev("dev_riskfactor", param_millionths,&riskfactor_millionths,1),
|
|
|
|
p_opt_dev("dev_min_prob_success", param_millionths,
|
2023-07-31 11:21:25 +09:30
|
|
|
&min_prob_success_millionths,900000),// default is 90%
|
2023-09-21 15:06:28 +09:30
|
|
|
p_opt_dev("dev_use_shadow", param_bool, &use_shadow, true),
|
2023-07-31 11:21:22 +09:30
|
|
|
NULL))
|
|
|
|
return command_param_failed();
|
|
|
|
|
2023-08-10 09:30:43 +09:30
|
|
|
/* We might need to parse invstring to get amount */
|
|
|
|
if (!bolt12_has_prefix(invstr)) {
|
2023-07-31 11:21:22 +09:30
|
|
|
struct bolt11 *b11;
|
|
|
|
char *fail;
|
|
|
|
|
|
|
|
b11 =
|
2023-08-10 09:30:43 +09:30
|
|
|
bolt11_decode(tmpctx, invstr, plugin_feature_set(cmd->plugin),
|
|
|
|
description, chainparams, &fail);
|
2023-07-31 11:21:22 +09:30
|
|
|
if (b11 == NULL)
|
2023-08-10 09:30:43 +09:30
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
2023-07-31 11:21:22 +09:30
|
|
|
"Invalid bolt11: %s", fail);
|
|
|
|
|
|
|
|
invmsat = b11->msat;
|
|
|
|
invexpiry = b11->timestamp + b11->expiry;
|
|
|
|
|
2023-08-10 09:30:43 +09:30
|
|
|
destination = b11->receiver_id;
|
|
|
|
payment_hash = b11->payment_hash;
|
|
|
|
payment_secret =
|
|
|
|
tal_dup_or_null(cmd, struct secret, b11->payment_secret);
|
2023-07-31 11:21:22 +09:30
|
|
|
if (b11->metadata)
|
2023-08-10 09:30:43 +09:30
|
|
|
payment_metadata = tal_dup_talarr(cmd, u8, b11->metadata);
|
2023-07-31 11:21:22 +09:30
|
|
|
else
|
2023-08-10 09:30:43 +09:30
|
|
|
payment_metadata = NULL;
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
|
2023-08-10 09:30:43 +09:30
|
|
|
final_cltv = b11->min_final_cltv_expiry;
|
2023-07-31 11:21:22 +09:30
|
|
|
/* Sanity check */
|
|
|
|
if (feature_offered(b11->features, OPT_VAR_ONION) &&
|
|
|
|
!b11->payment_secret)
|
|
|
|
return command_fail(
|
|
|
|
cmd, JSONRPC2_INVALID_PARAMS,
|
|
|
|
"Invalid bolt11:"
|
|
|
|
" sets feature var_onion with no secret");
|
|
|
|
/* BOLT #11:
|
|
|
|
* A reader:
|
|
|
|
*...
|
|
|
|
* - MUST check that the SHA2 256-bit hash in the `h` field
|
|
|
|
* exactly matches the hashed description.
|
|
|
|
*/
|
|
|
|
if (!b11->description) {
|
|
|
|
if (!b11->description_hash) {
|
2023-08-10 09:30:43 +09:30
|
|
|
return command_fail(cmd,
|
2023-07-31 11:21:22 +09:30
|
|
|
JSONRPC2_INVALID_PARAMS,
|
|
|
|
"Invalid bolt11: missing description");
|
|
|
|
}
|
2023-08-10 09:30:43 +09:30
|
|
|
if (!description)
|
|
|
|
return command_fail(cmd,
|
2023-07-31 11:21:22 +09:30
|
|
|
JSONRPC2_INVALID_PARAMS,
|
|
|
|
"bolt11 uses description_hash, but you did not provide description parameter");
|
|
|
|
}
|
2023-08-10 09:31:17 +09:30
|
|
|
|
|
|
|
routes = cast_const2(const struct route_info **,
|
|
|
|
b11->routes);
|
2023-07-31 11:21:22 +09:30
|
|
|
} else {
|
2024-03-07 08:33:36 +01:00
|
|
|
/* FIXME We have not yet added support for BOLT12 invoices,
|
|
|
|
* refuse to pay. */
|
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
|
|
|
"BOLT12 invoices are not yet supported.");
|
|
|
|
|
2023-07-31 11:21:22 +09:30
|
|
|
// TODO(eduardo): check this, compare with `pay`
|
|
|
|
const struct tlv_invoice *b12;
|
|
|
|
char *fail;
|
2023-08-10 09:30:43 +09:30
|
|
|
b12 = invoice_decode(tmpctx, invstr, strlen(invstr),
|
2023-07-31 11:21:22 +09:30
|
|
|
plugin_feature_set(cmd->plugin),
|
|
|
|
chainparams, &fail);
|
|
|
|
if (b12 == NULL)
|
2023-08-10 09:30:43 +09:30
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
2023-07-31 11:21:22 +09:30
|
|
|
"Invalid bolt12: %s", fail);
|
|
|
|
if (!pay_plugin->exp_offers)
|
2023-08-10 09:30:43 +09:30
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
2023-07-31 11:21:22 +09:30
|
|
|
"experimental-offers disabled");
|
|
|
|
|
|
|
|
if (!b12->offer_node_id)
|
2023-08-10 09:30:43 +09:30
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
2023-07-31 11:21:22 +09:30
|
|
|
"invoice missing offer_node_id");
|
|
|
|
if (!b12->invoice_payment_hash)
|
2023-08-10 09:30:43 +09:30
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
2023-07-31 11:21:22 +09:30
|
|
|
"invoice missing payment_hash");
|
|
|
|
if (!b12->invoice_created_at)
|
2023-08-10 09:30:43 +09:30
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
2023-07-31 11:21:22 +09:30
|
|
|
"invoice missing created_at");
|
|
|
|
if (b12->invoice_amount) {
|
|
|
|
invmsat = tal(cmd, struct amount_msat);
|
|
|
|
*invmsat = amount_msat(*b12->invoice_amount);
|
|
|
|
} else
|
|
|
|
invmsat = NULL;
|
|
|
|
|
2023-08-10 09:30:43 +09:30
|
|
|
node_id_from_pubkey(&destination, b12->offer_node_id);
|
|
|
|
payment_hash = *b12->invoice_payment_hash;
|
|
|
|
if (b12->invreq_recurrence_counter && !label)
|
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
2023-07-31 11:21:22 +09:30
|
|
|
"recurring invoice requires a label");
|
|
|
|
/* FIXME payment_secret should be signature! */
|
|
|
|
{
|
|
|
|
struct sha256 merkle;
|
|
|
|
|
2023-08-10 09:30:43 +09:30
|
|
|
payment_secret = tal(cmd, struct secret);
|
2023-07-31 11:21:22 +09:30
|
|
|
merkle_tlv(b12->fields, &merkle);
|
2023-08-10 09:30:43 +09:30
|
|
|
memcpy(payment_secret, &merkle, sizeof(merkle));
|
|
|
|
BUILD_ASSERT(sizeof(*payment_secret) ==
|
2023-07-31 11:21:22 +09:30
|
|
|
sizeof(merkle));
|
|
|
|
}
|
2023-08-10 09:30:43 +09:30
|
|
|
payment_metadata = NULL;
|
2023-07-31 11:21:22 +09:30
|
|
|
/* FIXME: blinded paths! */
|
2023-08-10 09:30:43 +09:30
|
|
|
final_cltv = 18;
|
2023-07-31 11:21:22 +09:30
|
|
|
/* BOLT-offers #12:
|
|
|
|
* - if `relative_expiry` is present:
|
|
|
|
* - MUST reject the invoice if the current time since
|
|
|
|
* 1970-01-01 UTC is greater than `created_at` plus
|
|
|
|
* `seconds_from_creation`.
|
|
|
|
* - otherwise:
|
|
|
|
* - MUST reject the invoice if the current time since
|
|
|
|
* 1970-01-01 UTC is greater than `created_at` plus
|
|
|
|
* 7200.
|
|
|
|
*/
|
|
|
|
if (b12->invoice_relative_expiry)
|
|
|
|
invexpiry = *b12->invoice_created_at + *b12->invoice_relative_expiry;
|
|
|
|
else
|
|
|
|
invexpiry = *b12->invoice_created_at + BOLT12_DEFAULT_REL_EXPIRY;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set the payment amount
|
|
|
|
if (invmsat) {
|
|
|
|
// amount is written in the invoice
|
|
|
|
if (msat) {
|
2023-08-10 09:30:43 +09:30
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
2023-07-31 11:21:22 +09:30
|
|
|
"amount_msat parameter unnecessary");
|
|
|
|
}
|
2023-08-10 09:30:43 +09:30
|
|
|
msat = invmsat;
|
2023-07-31 11:21:22 +09:30
|
|
|
} else {
|
|
|
|
// amount is not written in the invoice
|
|
|
|
if (!msat) {
|
2023-08-10 09:30:43 +09:30
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
2023-07-31 11:21:22 +09:30
|
|
|
"amount_msat parameter required");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Default max fee is 5 sats, or 0.5%, whichever is *higher* */
|
|
|
|
if (!maxfee) {
|
2023-08-10 09:30:43 +09:30
|
|
|
struct amount_msat fee = amount_msat_div(*msat, 200);
|
2023-07-31 11:21:22 +09:30
|
|
|
if (amount_msat_less(fee, AMOUNT_MSAT(5000)))
|
|
|
|
fee = AMOUNT_MSAT(5000);
|
|
|
|
maxfee = tal_dup(tmpctx, struct amount_msat, &fee);
|
|
|
|
}
|
|
|
|
|
2023-07-31 11:21:25 +09:30
|
|
|
const u64 now_sec = time_now().ts.tv_sec;
|
|
|
|
if (now_sec > invexpiry)
|
2023-08-10 09:30:43 +09:30
|
|
|
return command_fail(cmd, PAY_INVOICE_EXPIRED, "Invoice expired");
|
|
|
|
|
2023-08-10 09:31:08 +09:30
|
|
|
/* Payment is allocated off cmd to start, in case we fail cmd
|
|
|
|
* (e.g. already in progress, already succeeded). Once it's
|
|
|
|
* actually started, it persists beyond the command, so we
|
|
|
|
* tal_steal. */
|
|
|
|
struct payment *payment = payment_new(cmd,
|
2023-12-13 16:05:43 +10:30
|
|
|
cmd,
|
|
|
|
take(invstr),
|
|
|
|
take(label),
|
|
|
|
take(description),
|
|
|
|
take(local_offer_id),
|
|
|
|
take(payment_secret),
|
|
|
|
take(payment_metadata),
|
|
|
|
take(routes),
|
|
|
|
&destination,
|
|
|
|
&payment_hash,
|
|
|
|
*msat,
|
|
|
|
*maxfee,
|
|
|
|
*maxdelay,
|
|
|
|
*retryfor,
|
|
|
|
final_cltv,
|
|
|
|
*base_fee_penalty,
|
|
|
|
*prob_cost_factor,
|
|
|
|
*riskfactor_millionths,
|
|
|
|
*min_prob_success_millionths,
|
|
|
|
use_shadow);
|
2023-08-10 09:30:43 +09:30
|
|
|
|
2023-08-10 09:31:08 +09:30
|
|
|
/* We immediately add this payment to the payment list. */
|
|
|
|
list_add_tail(&pay_plugin->payments, &payment->list);
|
|
|
|
tal_add_destructor(payment, destroy_payment);
|
2023-08-10 09:30:43 +09:30
|
|
|
|
|
|
|
plugin_log(pay_plugin->plugin,LOG_DBG,"Starting renepay");
|
|
|
|
bool gossmap_changed = gossmap_refresh(pay_plugin->gossmap, NULL);
|
|
|
|
|
|
|
|
if (pay_plugin->gossmap == NULL)
|
|
|
|
plugin_err(pay_plugin->plugin, "Failed to refresh gossmap: %s",
|
|
|
|
strerror(errno));
|
|
|
|
|
|
|
|
/* Free parameters which would be considered "leaks" by our fussy memleak code */
|
|
|
|
tal_free(msat);
|
|
|
|
tal_free(maxfee);
|
|
|
|
tal_free(maxdelay);
|
|
|
|
tal_free(retryfor);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
/* To construct the uncertainty network we need to perform the following
|
|
|
|
* steps:
|
|
|
|
* 1. check that there is a 1-to-1 map between channels in gossmap
|
|
|
|
* and the uncertainty network. We call `uncertainty_network_update`
|
|
|
|
*
|
|
|
|
* 2. add my local channels that could be private.
|
|
|
|
* We call `update_uncertainty_network_from_listpeerchannels`.
|
|
|
|
*
|
|
|
|
* 3. add hidden/private channels listed in the routehints.
|
|
|
|
* We call `uncertainty_network_add_routehints`.
|
|
|
|
*
|
|
|
|
* 4. check the uncertainty network invariants.
|
|
|
|
* */
|
|
|
|
if(gossmap_changed)
|
|
|
|
uncertainty_network_update(pay_plugin->gossmap,
|
|
|
|
pay_plugin->chan_extra_map);
|
|
|
|
|
|
|
|
|
2023-07-31 11:21:25 +09:30
|
|
|
/* TODO(eduardo): We use a linear function to decide how to decay the
|
|
|
|
* channel information. Other shapes could be used.
|
|
|
|
* Also the choice of the proportional parameter TIMER_FORGET_SEC is
|
|
|
|
* arbitrary.
|
|
|
|
* Another idea is to measure time in blockheight. */
|
|
|
|
const double fraction = (now_sec - pay_plugin->last_time)*1.0/TIMER_FORGET_SEC;
|
|
|
|
uncertainty_network_relax_fraction(pay_plugin->chan_extra_map,
|
|
|
|
fraction);
|
|
|
|
pay_plugin->last_time = now_sec;
|
|
|
|
|
2023-07-31 11:21:22 +09:30
|
|
|
if(!uncertainty_network_check_invariants(pay_plugin->chan_extra_map))
|
|
|
|
plugin_log(pay_plugin->plugin,
|
|
|
|
LOG_BROKEN,
|
|
|
|
"uncertainty network invariants are violated");
|
|
|
|
|
|
|
|
/* Next, request listsendpays for previous payments that use the same
|
|
|
|
* hash. */
|
|
|
|
struct out_req *req
|
|
|
|
= jsonrpc_request_start(cmd->plugin, cmd, "listsendpays",
|
|
|
|
payment_listsendpays_previous,
|
2023-08-10 09:31:08 +09:30
|
|
|
payment_listsendpays_previous, payment);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-10 09:31:08 +09:30
|
|
|
json_add_sha256(req->js, "payment_hash", &payment->payment_hash);
|
2023-07-31 11:21:22 +09:30
|
|
|
return send_outreq(cmd->plugin, req);
|
|
|
|
}
|
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
/* Terminates flow */
|
2023-08-10 11:29:44 +09:30
|
|
|
static struct pf_result *handle_sendpay_failure_payment(struct pay_flow *pf STEALS,
|
2023-08-10 11:29:44 +09:30
|
|
|
const char *message,
|
|
|
|
u32 erridx,
|
|
|
|
enum onion_wire onionerr,
|
|
|
|
const u8 *raw)
|
2023-07-31 11:21:22 +09:30
|
|
|
{
|
2023-08-10 09:31:15 +09:30
|
|
|
struct short_channel_id errscid;
|
2023-08-10 11:29:44 +09:30
|
|
|
const u8 *update;
|
2023-08-10 09:31:15 +09:30
|
|
|
|
2023-09-18 14:23:46 +09:30
|
|
|
assert(pf);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
/* Final node is usually a hard failure */
|
2023-08-21 15:07:07 +09:30
|
|
|
if (erridx == tal_count(pf->path_scidds)) {
|
2023-08-10 11:29:44 +09:30
|
|
|
if (onionerr == WIRE_MPP_TIMEOUT) {
|
2023-08-10 11:29:44 +09:30
|
|
|
return pay_flow_failed(pf);
|
2023-08-10 11:29:44 +09:30
|
|
|
}
|
2023-08-10 09:31:15 +09:30
|
|
|
|
2023-08-21 15:09:33 +09:30
|
|
|
payflow_note(pf, LOG_INFORM,
|
|
|
|
"final destination permanent failure");
|
2023-08-10 11:29:44 +09:30
|
|
|
return pay_flow_failed_final(pf, PAY_DESTINATION_PERM_FAIL, message);
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
|
2023-08-21 15:07:07 +09:30
|
|
|
errscid = pf->path_scidds[erridx].scid;
|
2023-08-10 09:31:15 +09:30
|
|
|
switch (onionerr) {
|
2023-07-31 11:21:22 +09:30
|
|
|
/* These definitely mean eliminate channel */
|
|
|
|
case WIRE_PERMANENT_CHANNEL_FAILURE:
|
|
|
|
case WIRE_REQUIRED_CHANNEL_FEATURE_MISSING:
|
|
|
|
/* FIXME: lnd returns this for disconnected peer, so don't disable perm! */
|
|
|
|
case WIRE_UNKNOWN_NEXT_PEER:
|
|
|
|
case WIRE_CHANNEL_DISABLED:
|
|
|
|
/* These mean node is weird, but we eliminate channel here too */
|
|
|
|
case WIRE_INVALID_REALM:
|
|
|
|
case WIRE_TEMPORARY_NODE_FAILURE:
|
|
|
|
case WIRE_PERMANENT_NODE_FAILURE:
|
|
|
|
case WIRE_REQUIRED_NODE_FEATURE_MISSING:
|
|
|
|
/* These shouldn't happen, but eliminate channel */
|
|
|
|
case WIRE_INVALID_ONION_VERSION:
|
|
|
|
case WIRE_INVALID_ONION_HMAC:
|
|
|
|
case WIRE_INVALID_ONION_KEY:
|
|
|
|
case WIRE_INVALID_ONION_PAYLOAD:
|
|
|
|
case WIRE_INVALID_ONION_BLINDING:
|
|
|
|
case WIRE_EXPIRY_TOO_FAR:
|
2023-08-21 15:09:05 +09:30
|
|
|
payflow_disable_chan(pf, errscid, LOG_UNUSUAL,
|
|
|
|
"%s",
|
|
|
|
onion_wire_name(onionerr));
|
2023-08-10 11:29:44 +09:30
|
|
|
return pay_flow_failed(pf);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
/* These can be fixed (maybe) by applying the included channel_update */
|
|
|
|
case WIRE_AMOUNT_BELOW_MINIMUM:
|
|
|
|
case WIRE_FEE_INSUFFICIENT:
|
|
|
|
case WIRE_INCORRECT_CLTV_EXPIRY:
|
|
|
|
case WIRE_EXPIRY_TOO_SOON:
|
|
|
|
plugin_log(pay_plugin->plugin,LOG_DBG,"sendpay_failure, apply channel_update");
|
|
|
|
/* FIXME: Check scid! */
|
|
|
|
// TODO(eduardo): check
|
2023-08-10 11:29:44 +09:30
|
|
|
update = channel_update_from_onion_error(tmpctx, raw);
|
2023-07-31 11:21:22 +09:30
|
|
|
if (update)
|
2023-08-10 11:29:44 +09:30
|
|
|
return submit_update(pf, update, errscid);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-21 15:09:05 +09:30
|
|
|
payflow_disable_chan(pf, errscid,
|
|
|
|
LOG_UNUSUAL, "missing channel_update");
|
2023-08-10 11:29:44 +09:30
|
|
|
return pay_flow_failed(pf);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
case WIRE_TEMPORARY_CHANNEL_FAILURE:
|
2023-08-10 11:29:44 +09:30
|
|
|
/* These also contain a channel_update, but in this case it's simply
|
|
|
|
* advisory, not necessary. */
|
2023-08-10 11:29:44 +09:30
|
|
|
update = channel_update_from_onion_error(tmpctx, raw);
|
2023-08-10 11:29:44 +09:30
|
|
|
if (update)
|
2023-08-10 11:29:44 +09:30
|
|
|
return submit_update(pf, update, errscid);
|
2023-08-10 11:29:44 +09:30
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
return pay_flow_failed(pf);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-10 09:31:15 +09:30
|
|
|
/* These should only come from the final distination. */
|
|
|
|
case WIRE_MPP_TIMEOUT:
|
2023-07-31 11:21:22 +09:30
|
|
|
case WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS:
|
|
|
|
case WIRE_FINAL_INCORRECT_CLTV_EXPIRY:
|
|
|
|
case WIRE_FINAL_INCORRECT_HTLC_AMOUNT:
|
2023-08-10 09:31:15 +09:30
|
|
|
break;
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
|
2023-08-21 15:09:05 +09:30
|
|
|
payflow_disable_chan(pf, errscid,
|
|
|
|
LOG_UNUSUAL, "unexpected error code %u",
|
|
|
|
onionerr);
|
2023-08-10 11:29:44 +09:30
|
|
|
return pay_flow_failed(pf);
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
static void handle_sendpay_failure_flow(struct pay_flow *pf,
|
2023-08-10 09:31:15 +09:30
|
|
|
const char *msg,
|
|
|
|
u32 erridx,
|
|
|
|
u32 onionerr)
|
2023-07-31 11:21:22 +09:30
|
|
|
{
|
2023-09-18 14:23:46 +09:30
|
|
|
assert(pf);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
|
|
|
/* we know that all channels before erridx where able to commit to this payment */
|
|
|
|
uncertainty_network_channel_can_send(
|
|
|
|
pay_plugin->chan_extra_map,
|
2023-08-10 11:29:44 +09:30
|
|
|
pf,
|
2023-07-31 11:21:22 +09:30
|
|
|
erridx);
|
|
|
|
|
2023-08-10 09:31:15 +09:30
|
|
|
/* Insufficient funds (not from final, that's weird!) */
|
|
|
|
if((enum onion_wire)onionerr == WIRE_TEMPORARY_CHANNEL_FAILURE
|
2023-08-21 15:07:07 +09:30
|
|
|
&& erridx < tal_count(pf->path_scidds))
|
2023-07-31 11:21:22 +09:30
|
|
|
{
|
2023-12-18 14:18:00 +01:00
|
|
|
const char *old_state =
|
|
|
|
fmt_chan_extra_details(tmpctx, pay_plugin->chan_extra_map,
|
|
|
|
&pf->path_scidds[erridx]);
|
|
|
|
|
|
|
|
char *fail;
|
|
|
|
if (!chan_extra_cannot_send(tmpctx, pay_plugin->chan_extra_map,
|
|
|
|
&pf->path_scidds[erridx],
|
2023-12-24 10:28:55 +01:00
|
|
|
&fail)) {
|
2023-12-18 14:18:00 +01:00
|
|
|
plugin_err(pay_plugin->plugin,
|
|
|
|
"chan_extra_cannot_send failed: %s", fail);
|
|
|
|
}
|
|
|
|
|
|
|
|
payflow_note(pf, LOG_INFORM,
|
|
|
|
"Failure to forward amount %s in channel %s, "
|
|
|
|
"state change %s -> %s",
|
|
|
|
fmt_amount_msat(tmpctx, pf->amounts[erridx]),
|
|
|
|
type_to_string(tmpctx, struct short_channel_id_dir,
|
|
|
|
&pf->path_scidds[erridx]),
|
|
|
|
old_state,
|
|
|
|
fmt_chan_extra_details(tmpctx,
|
|
|
|
pay_plugin->chan_extra_map,
|
|
|
|
&pf->path_scidds[erridx]));
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-10 09:31:15 +09:30
|
|
|
/* See if this notification is about one of our flows. */
|
|
|
|
static struct pay_flow *pay_flow_from_notification(const char *buf,
|
|
|
|
const jsmntok_t *obj)
|
|
|
|
{
|
|
|
|
struct payflow_key key;
|
|
|
|
const char *err;
|
|
|
|
|
|
|
|
/* Single part payment? No partid */
|
|
|
|
key.partid = 0;
|
|
|
|
err = json_scan(tmpctx, buf, obj, "{partid?:%,groupid:%,payment_hash:%}",
|
|
|
|
JSON_SCAN(json_to_u64, &key.partid),
|
|
|
|
JSON_SCAN(json_to_u64, &key.groupid),
|
2023-08-10 09:31:18 +09:30
|
|
|
JSON_SCAN(json_to_sha256, &key.payment_hash));
|
2023-08-10 09:31:15 +09:30
|
|
|
if (err) {
|
|
|
|
plugin_err(pay_plugin->plugin,
|
|
|
|
"Missing fields (%s) in notification: %.*s",
|
|
|
|
err,
|
|
|
|
json_tok_full_len(obj),
|
|
|
|
json_tok_full(buf, obj));
|
|
|
|
}
|
|
|
|
|
2023-08-10 09:31:18 +09:30
|
|
|
return payflow_map_get(pay_plugin->payflow_map, &key);
|
2023-08-10 09:31:15 +09:30
|
|
|
}
|
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
|
|
|
|
|
2023-07-31 11:21:22 +09:30
|
|
|
static struct command_result *notification_sendpay_success(
|
|
|
|
struct command *cmd,
|
|
|
|
const char *buf,
|
|
|
|
const jsmntok_t *params)
|
|
|
|
{
|
2023-08-10 11:29:44 +09:30
|
|
|
struct pay_flow *pf;
|
2023-08-10 09:31:16 +09:30
|
|
|
struct preimage preimage;
|
|
|
|
const char *err;
|
|
|
|
const jsmntok_t *sub = json_get_member(buf, params, "sendpay_success");
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
pf = pay_flow_from_notification(buf, sub);
|
|
|
|
if (!pf)
|
2023-08-10 09:31:16 +09:30
|
|
|
return notification_handled(cmd);
|
|
|
|
|
|
|
|
err = json_scan(tmpctx, buf, sub, "{payment_preimage:%}",
|
|
|
|
JSON_SCAN(json_to_preimage, &preimage));
|
|
|
|
if (err) {
|
|
|
|
plugin_err(pay_plugin->plugin,
|
|
|
|
"Bad payment_preimage (%s) in sendpay_success: %.*s",
|
|
|
|
err,
|
|
|
|
json_tok_full_len(params),
|
|
|
|
json_tok_full(buf, params));
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
|
plugins/renepay: neaten the command notifications.
It now looks like (for test_hardmpp):
```
# we have computed a set of 1 flows with probability 0.328, fees 0msat and delay 23
# Flow 1: amount=1800000000msat prob=0.328 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0->-103x3x0/1->
# Flow 1: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 1: Failure of 1800000000msat for 103x5x0/0 capacity [0msat,3000000000msat] -> [0msat,1799999999msat]
# we have computed a set of 2 flows with probability 0.115, fees 0msat and delay 23
# Flow 2: amount=500000000msat prob=0.475 fees=0msat delay=12 path=-103x6x0/0(min=max=4294967295msat)->-103x1x0/1->-103x4x0/1->
# Flow 3: amount=1300000000msat prob=0.242 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1799999999msat)->-103x3x0/1->
# Flow 3: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 3: Failure of 1300000000msat for 103x5x0/0 capacity [0msat,1799999999msat] -> [0msat,1299999999msat]
# we have computed a set of 2 flows with probability 0.084, fees 0msat and delay 23
# Flow 4: amount=260000000msat prob=0.467 fees=0msat delay=12 path=-103x6x0/0(500000000msat in 1 htlcs,min=max=4294967295msat)->-103x1x0/1(500000000msat in 1 htlcs)->-103x4x0/1(500000000msat in 1 htlcs)->
# Flow 5: amount=1040000000msat prob=0.179 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1299999999msat)->-103x3x0/1->
# Flow 5: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 5: Failure of 1040000000msat for 103x5x0/0 capacity [0msat,1299999999msat] -> [0msat,1039999999msat]
# we have computed a set of 2 flows with probability 0.052, fees 0msat and delay 23
# Flow 6: amount=120000000msat prob=0.494 fees=0msat delay=12 path=-103x6x0/0(760000000msat in 2 htlcs,min=max=4294967295msat)->-103x1x0/1(760000000msat in 2 htlcs)->-103x4x0/1(760000000msat in 2 htlcs)->
# Flow 7: amount=920000000msat prob=0.105 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1039999999msat)->-103x3x0/1->
# Flow 7: Success
```
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2023-08-21 15:08:46 +09:30
|
|
|
payflow_note(pf, LOG_INFORM, "Success");
|
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
// 2. update information
|
2023-08-10 11:29:44 +09:30
|
|
|
uncertainty_network_flow_success(pay_plugin->chan_extra_map, pf);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
// 3. mark as success (frees pf)
|
|
|
|
pay_flow_succeeded(pf, &preimage);
|
2023-08-10 09:31:16 +09:30
|
|
|
|
2023-07-31 11:21:22 +09:30
|
|
|
return notification_handled(cmd);
|
|
|
|
}
|
2023-08-10 09:31:15 +09:30
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
/* Dummy return ensures all paths call pay_flow_* to close flow! */
|
2023-08-10 11:29:44 +09:30
|
|
|
static struct pf_result *sendpay_failure(struct pay_flow *pf,
|
2023-08-10 11:29:44 +09:30
|
|
|
enum jsonrpc_errcode errcode,
|
|
|
|
const char *buf,
|
|
|
|
const jsmntok_t *sub)
|
2023-07-31 11:21:22 +09:30
|
|
|
{
|
2023-08-10 11:29:44 +09:30
|
|
|
const char *msg, *err;
|
|
|
|
u32 erridx, onionerr;
|
|
|
|
const u8 *raw;
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-10 09:31:15 +09:30
|
|
|
/* Only one code is really actionable */
|
|
|
|
switch (errcode) {
|
|
|
|
case PAY_UNPARSEABLE_ONION:
|
2023-08-10 11:29:44 +09:30
|
|
|
return handle_unhandleable_error(pf, "Unparsable onion reply");
|
2023-08-10 11:29:44 +09:30
|
|
|
|
2023-08-10 09:31:15 +09:30
|
|
|
case PAY_TRY_OTHER_ROUTE:
|
|
|
|
break;
|
|
|
|
case PAY_DESTINATION_PERM_FAIL:
|
2023-08-10 09:31:21 +09:30
|
|
|
break;
|
2023-08-10 09:31:15 +09:30
|
|
|
default:
|
2023-08-10 11:29:44 +09:30
|
|
|
return pay_flow_failed_final(pf,
|
2023-08-10 11:29:44 +09:30
|
|
|
errcode,
|
|
|
|
"Unexpected errorcode from sendpay_failure");
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
/* Extract remaining fields for feedback */
|
2023-08-14 15:15:10 +09:30
|
|
|
raw = NULL;
|
2023-08-10 09:31:15 +09:30
|
|
|
err = json_scan(tmpctx, buf, sub,
|
|
|
|
"{message:%"
|
|
|
|
",data:{erring_index:%"
|
|
|
|
",failcode:%"
|
2023-08-14 15:15:10 +09:30
|
|
|
",raw_message?:%}}",
|
2023-08-10 09:31:15 +09:30
|
|
|
JSON_SCAN_TAL(tmpctx, json_strdup, &msg),
|
|
|
|
JSON_SCAN(json_to_u32, &erridx),
|
|
|
|
JSON_SCAN(json_to_u32, &onionerr),
|
|
|
|
JSON_SCAN_TAL(tmpctx, json_tok_bin_from_hex, &raw));
|
|
|
|
if (err)
|
2023-08-10 11:29:44 +09:30
|
|
|
return handle_unhandleable_error(pf, err);
|
2023-07-31 11:21:22 +09:30
|
|
|
|
2023-08-10 09:31:15 +09:30
|
|
|
/* Answer must be sane: but note, erridx can be final node! */
|
2023-08-21 15:07:07 +09:30
|
|
|
if (erridx > tal_count(pf->path_scidds)) {
|
2023-08-10 09:31:15 +09:30
|
|
|
plugin_err(pay_plugin->plugin,
|
|
|
|
"Erring channel %u/%zu in path %s",
|
2023-08-21 15:07:07 +09:30
|
|
|
erridx, tal_count(pf->path_scidds),
|
2023-08-10 11:29:44 +09:30
|
|
|
flow_path_to_str(tmpctx, pf));
|
2023-08-10 09:31:15 +09:30
|
|
|
}
|
2023-07-31 11:21:22 +09:30
|
|
|
|
plugins/renepay: neaten the command notifications.
It now looks like (for test_hardmpp):
```
# we have computed a set of 1 flows with probability 0.328, fees 0msat and delay 23
# Flow 1: amount=1800000000msat prob=0.328 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0->-103x3x0/1->
# Flow 1: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 1: Failure of 1800000000msat for 103x5x0/0 capacity [0msat,3000000000msat] -> [0msat,1799999999msat]
# we have computed a set of 2 flows with probability 0.115, fees 0msat and delay 23
# Flow 2: amount=500000000msat prob=0.475 fees=0msat delay=12 path=-103x6x0/0(min=max=4294967295msat)->-103x1x0/1->-103x4x0/1->
# Flow 3: amount=1300000000msat prob=0.242 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1799999999msat)->-103x3x0/1->
# Flow 3: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 3: Failure of 1300000000msat for 103x5x0/0 capacity [0msat,1799999999msat] -> [0msat,1299999999msat]
# we have computed a set of 2 flows with probability 0.084, fees 0msat and delay 23
# Flow 4: amount=260000000msat prob=0.467 fees=0msat delay=12 path=-103x6x0/0(500000000msat in 1 htlcs,min=max=4294967295msat)->-103x1x0/1(500000000msat in 1 htlcs)->-103x4x0/1(500000000msat in 1 htlcs)->
# Flow 5: amount=1040000000msat prob=0.179 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1299999999msat)->-103x3x0/1->
# Flow 5: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 5: Failure of 1040000000msat for 103x5x0/0 capacity [0msat,1299999999msat] -> [0msat,1039999999msat]
# we have computed a set of 2 flows with probability 0.052, fees 0msat and delay 23
# Flow 6: amount=120000000msat prob=0.494 fees=0msat delay=12 path=-103x6x0/0(760000000msat in 2 htlcs,min=max=4294967295msat)->-103x1x0/1(760000000msat in 2 htlcs)->-103x4x0/1(760000000msat in 2 htlcs)->
# Flow 7: amount=920000000msat prob=0.105 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1039999999msat)->-103x3x0/1->
# Flow 7: Success
```
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2023-08-21 15:08:46 +09:30
|
|
|
payflow_note(pf, LOG_INFORM, "Failed at node #%u (%s): %s",
|
|
|
|
erridx, onion_wire_name(onionerr), msg);
|
2023-08-10 11:29:44 +09:30
|
|
|
handle_sendpay_failure_flow(pf, msg, erridx, onionerr);
|
2023-08-10 09:31:15 +09:30
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
return handle_sendpay_failure_payment(pf, msg, erridx, onionerr, raw);
|
2023-08-10 11:29:44 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
static struct command_result *notification_sendpay_failure(
|
|
|
|
struct command *cmd,
|
|
|
|
const char *buf,
|
|
|
|
const jsmntok_t *params)
|
|
|
|
{
|
2023-08-10 11:29:44 +09:30
|
|
|
struct pay_flow *pf;
|
2023-08-10 11:29:44 +09:30
|
|
|
const char *err;
|
|
|
|
enum jsonrpc_errcode errcode;
|
|
|
|
const jsmntok_t *sub = json_get_member(buf, params, "sendpay_failure");
|
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
pf = pay_flow_from_notification(buf, json_get_member(buf, sub, "data"));
|
|
|
|
if (!pf)
|
2023-08-10 11:29:44 +09:30
|
|
|
return notification_handled(cmd);
|
|
|
|
|
|
|
|
err = json_scan(tmpctx, buf, sub, "{code:%}",
|
|
|
|
JSON_SCAN(json_to_jsonrpc_errcode, &errcode));
|
|
|
|
if (err) {
|
|
|
|
plugin_err(pay_plugin->plugin,
|
|
|
|
"Bad code (%s) in sendpay_failure: %.*s",
|
|
|
|
err,
|
|
|
|
json_tok_full_len(params),
|
|
|
|
json_tok_full(buf, params));
|
|
|
|
}
|
2023-08-10 09:31:15 +09:30
|
|
|
|
2023-08-10 11:29:44 +09:30
|
|
|
sendpay_failure(pf, errcode, buf, sub);
|
2023-08-10 11:29:44 +09:30
|
|
|
return notification_handled(cmd);
|
2023-07-31 11:21:22 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
static const struct plugin_command commands[] = {
|
|
|
|
{
|
|
|
|
"renepaystatus",
|
|
|
|
"payment",
|
|
|
|
"Detail status of attempts to pay {bolt11}, or all",
|
|
|
|
"Covers both old payments and current ones.",
|
|
|
|
json_paystatus
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"renepay",
|
|
|
|
"payment",
|
|
|
|
"Send payment specified by {invstring}",
|
|
|
|
"Attempt to pay an invoice.",
|
|
|
|
json_pay
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct plugin_notification notifications[] = {
|
|
|
|
// {
|
|
|
|
// "shutdown",
|
|
|
|
// notification_shutdown,
|
|
|
|
// },
|
|
|
|
{
|
|
|
|
"sendpay_success",
|
|
|
|
notification_sendpay_success,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"sendpay_failure",
|
|
|
|
notification_sendpay_failure,
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
setup_locale();
|
2023-08-10 11:29:42 +09:30
|
|
|
|
|
|
|
/* Most gets initialized in init(), but set debug options here. */
|
|
|
|
pay_plugin = tal(NULL, struct pay_plugin);
|
|
|
|
pay_plugin->debug_mcf = pay_plugin->debug_payflow = false;
|
|
|
|
|
2023-07-31 11:21:22 +09:30
|
|
|
plugin_main(
|
|
|
|
argv,
|
|
|
|
init,
|
|
|
|
PLUGIN_RESTARTABLE,
|
|
|
|
/* init_rpc */ true,
|
|
|
|
/* features */ NULL,
|
|
|
|
commands, ARRAY_SIZE(commands),
|
|
|
|
notifications, ARRAY_SIZE(notifications),
|
|
|
|
/* hooks */ NULL, 0,
|
|
|
|
/* notification topics */ NULL, 0,
|
|
|
|
plugin_option("renepay-debug-mcf", "flag",
|
|
|
|
"Enable renepay MCF debug info.",
|
|
|
|
flag_option, &pay_plugin->debug_mcf),
|
|
|
|
plugin_option("renepay-debug-payflow", "flag",
|
|
|
|
"Enable renepay payment flows debug info.",
|
|
|
|
flag_option, &pay_plugin->debug_payflow),
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|