mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 15:14:23 +01:00
pay: inject channel updates from errors ourselves.
Cut & paste from gossipd. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
3c5502426b
commit
780fc25413
@@ -12,6 +12,7 @@
|
|||||||
#include <common/type_to_string.h>
|
#include <common/type_to_string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <plugins/libplugin-pay.h>
|
#include <plugins/libplugin-pay.h>
|
||||||
|
#include <wire/peer_wire.h>
|
||||||
|
|
||||||
static struct gossmap *global_gossmap;
|
static struct gossmap *global_gossmap;
|
||||||
|
|
||||||
@@ -1340,12 +1341,105 @@ static bool assign_blame(const struct payment *p,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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,
|
||||||
|
const u8 *onion_message)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct command_result *
|
||||||
|
payment_addgossip_success(struct command *cmd, const char *buffer,
|
||||||
|
const jsmntok_t *toks, struct payment *p)
|
||||||
|
{
|
||||||
|
const struct node_id *errnode;
|
||||||
|
const struct route_hop *errchan;
|
||||||
|
|
||||||
|
if (!assign_blame(p, &errnode, &errchan)) {
|
||||||
|
paymod_log(p, LOG_UNUSUAL,
|
||||||
|
"No erring_index set in `waitsendpay` result: %.*s",
|
||||||
|
json_tok_full_len(toks),
|
||||||
|
json_tok_full(buffer, toks));
|
||||||
|
/* FIXME: Pick a random channel to fail? */
|
||||||
|
payment_set_step(p, PAYMENT_STEP_FAILED);
|
||||||
|
payment_continue(p);
|
||||||
|
return command_still_pending(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!errchan)
|
||||||
|
return handle_final_failure(cmd, p, errnode,
|
||||||
|
p->result->failcode);
|
||||||
|
|
||||||
|
return handle_intermediate_failure(cmd, p, errnode, errchan,
|
||||||
|
p->result->failcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If someone gives us an invalid update, all we can do is log it */
|
||||||
|
static struct command_result *
|
||||||
|
payment_addgossip_failure(struct command *cmd, const char *buffer,
|
||||||
|
const jsmntok_t *toks, struct payment *p)
|
||||||
|
{
|
||||||
|
paymod_log(p, LOG_DBG, "Invalid channel_update: %.*s",
|
||||||
|
json_tok_full_len(toks),
|
||||||
|
json_tok_full(buffer, toks));
|
||||||
|
|
||||||
|
return payment_addgossip_success(cmd, NULL, NULL, p);
|
||||||
|
}
|
||||||
|
|
||||||
static struct command_result *
|
static struct command_result *
|
||||||
payment_waitsendpay_finished(struct command *cmd, const char *buffer,
|
payment_waitsendpay_finished(struct command *cmd, const char *buffer,
|
||||||
const jsmntok_t *toks, struct payment *p)
|
const jsmntok_t *toks, struct payment *p)
|
||||||
{
|
{
|
||||||
const struct node_id *errnode;
|
u8 *update;
|
||||||
const struct route_hop *errchan;
|
|
||||||
|
|
||||||
assert(p->route != NULL);
|
assert(p->route != NULL);
|
||||||
|
|
||||||
@@ -1372,23 +1466,19 @@ payment_waitsendpay_finished(struct command *cmd, const char *buffer,
|
|||||||
|
|
||||||
payment_chanhints_apply_route(p, true);
|
payment_chanhints_apply_route(p, true);
|
||||||
|
|
||||||
if (!assign_blame(p, &errnode, &errchan)) {
|
/* Tell gossipd, if we received an update */
|
||||||
paymod_log(p, LOG_UNUSUAL,
|
update = channel_update_from_onion_error(tmpctx, p->result->raw_message);
|
||||||
"No erring_index set in `waitsendpay` result: %.*s",
|
if (update) {
|
||||||
json_tok_full_len(toks),
|
struct out_req *req;
|
||||||
json_tok_full(buffer, toks));
|
req = jsonrpc_request_start(p->plugin, NULL, "addgossip",
|
||||||
/* FIXME: Pick a random channel to fail? */
|
payment_addgossip_success,
|
||||||
payment_set_step(p, PAYMENT_STEP_FAILED);
|
payment_addgossip_failure, p);
|
||||||
payment_continue(p);
|
json_add_hex_talarr(req->js, "message", update);
|
||||||
|
send_outreq(p->plugin, req);
|
||||||
return command_still_pending(cmd);
|
return command_still_pending(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!errchan)
|
return payment_addgossip_success(cmd, NULL, NULL, p);
|
||||||
return handle_final_failure(cmd, p, errnode,
|
|
||||||
p->result->failcode);
|
|
||||||
|
|
||||||
return handle_intermediate_failure(cmd, p, errnode, errchan,
|
|
||||||
p->result->failcode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command_result *payment_sendonion_success(struct command *cmd,
|
static struct command_result *payment_sendonion_success(struct command *cmd,
|
||||||
|
|||||||
Reference in New Issue
Block a user