mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 15:14:23 +01:00
lightningd/pay: simplify code significantly.
We no longer need a 'sendpay_result' structure, we can pass appropriate parameter directly now they're simple calls. Every waitsendpay command ends in tell_waiters_failed or tell_waiters_success, which call sendpay_success or sendpay_fail on all matching waiters. These all return 'struct command_result *'. In cases where the result is immediately known, we call sendpay_success/sendpay_fail directly for the command. This also adds a helpful 'failcodename' field to the JSON output. [ This was four separate cleanup patches, but that contained much redundancy and was even worse to review ] Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
1c58351551
commit
4e6b8e13a4
438
lightningd/pay.c
438
lightningd/pay.c
@@ -27,29 +27,6 @@ struct routing_failure {
|
|||||||
int channel_dir;
|
int channel_dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Result of send_payment */
|
|
||||||
struct sendpay_result {
|
|
||||||
/* Did the payment succeed? */
|
|
||||||
bool succeeded;
|
|
||||||
/* Preimage. Only loaded if payment succeeded. */
|
|
||||||
struct preimage preimage;
|
|
||||||
/* Error code, one of the PAY_* macro in jsonrpc_errors.h.
|
|
||||||
* Only loaded if payment failed. */
|
|
||||||
int errorcode;
|
|
||||||
/* Pointer to the payment. Only loaded if payment
|
|
||||||
* succeeded or if error is PAY_IN_PROGRESS */
|
|
||||||
const struct wallet_payment *payment;
|
|
||||||
/* Unparseable onion reply. Only loaded if payment failed,
|
|
||||||
* and errorcode == PAY_UNPARSEABLE_ONION. */
|
|
||||||
const u8* onionreply;
|
|
||||||
/* Routing failure object. Only loaded if payment failed,
|
|
||||||
* and errorcode == PAY_DESTINATION_PERM_FAIL or
|
|
||||||
* errorcode == PAY_TRY_OTHER_ROUTE */
|
|
||||||
struct routing_failure* routing_failure;
|
|
||||||
/* Error message. Only loaded if payment failed. */
|
|
||||||
const char *details;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* sendpay command */
|
/* sendpay command */
|
||||||
struct sendpay_command {
|
struct sendpay_command {
|
||||||
struct list_node list;
|
struct list_node list;
|
||||||
@@ -63,7 +40,7 @@ static void destroy_sendpay_command(struct sendpay_command *pc)
|
|||||||
list_del(&pc->list);
|
list_del(&pc->list);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Owned by cmd, if cmd is deleted, then json_sendpay_on_resolve will
|
/* Owned by cmd, if cmd is deleted, then sendpay_success/sendpay_fail will
|
||||||
* no longer be called. */
|
* no longer be called. */
|
||||||
static void
|
static void
|
||||||
add_sendpay_waiter(struct lightningd *ld,
|
add_sendpay_waiter(struct lightningd *ld,
|
||||||
@@ -78,7 +55,7 @@ add_sendpay_waiter(struct lightningd *ld,
|
|||||||
tal_add_destructor(pc, destroy_sendpay_command);
|
tal_add_destructor(pc, destroy_sendpay_command);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Owned by cmd, if cmd is deleted, then json_waitsendpay_on_resolve will
|
/* Owned by cmd, if cmd is deleted, then sendpay_success/sendpay_fail will
|
||||||
* no longer be called. */
|
* no longer be called. */
|
||||||
static void
|
static void
|
||||||
add_waitsendpay_waiter(struct lightningd *ld,
|
add_waitsendpay_waiter(struct lightningd *ld,
|
||||||
@@ -124,210 +101,136 @@ json_add_payment_fields(struct json_stream *response,
|
|||||||
json_add_string(response, "description", t->description);
|
json_add_string(response, "description", t->description);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static struct command_result *sendpay_success(struct command *cmd,
|
||||||
json_sendpay_success(struct command *cmd,
|
const struct wallet_payment *payment)
|
||||||
const struct sendpay_result *r)
|
|
||||||
{
|
{
|
||||||
struct json_stream *response;
|
struct json_stream *response;
|
||||||
|
|
||||||
assert(r->payment->status == PAYMENT_COMPLETE);
|
assert(payment->status == PAYMENT_COMPLETE);
|
||||||
|
|
||||||
response = json_stream_success(cmd);
|
response = json_stream_success(cmd);
|
||||||
json_object_start(response, NULL);
|
json_object_start(response, NULL);
|
||||||
json_add_payment_fields(response, r->payment);
|
json_add_payment_fields(response, payment);
|
||||||
json_object_end(response);
|
json_object_end(response);
|
||||||
was_pending(command_success(cmd, response));
|
return command_success(cmd, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void json_waitsendpay_on_resolve(struct command *cmd,
|
static void
|
||||||
const struct sendpay_result *r)
|
json_add_routefail_info(struct json_stream *js,
|
||||||
|
unsigned int erring_index,
|
||||||
|
enum onion_type failcode,
|
||||||
|
const struct pubkey *erring_node,
|
||||||
|
const struct short_channel_id *erring_channel,
|
||||||
|
int channel_dir)
|
||||||
{
|
{
|
||||||
const char *msg = NULL;
|
const char *failcodename = onion_type_name(failcode);
|
||||||
struct routing_failure *fail;
|
|
||||||
|
|
||||||
if (r->succeeded)
|
json_object_start(js, NULL);
|
||||||
json_sendpay_success(cmd, r);
|
json_add_num(js, "erring_index", erring_index);
|
||||||
else {
|
json_add_num(js, "failcode", failcode);
|
||||||
|
/* FIXME: Better way to detect this? */
|
||||||
|
if (!strstarts(failcodename, "INVALID "))
|
||||||
|
json_add_string(js, "failcodename", failcodename);
|
||||||
|
json_add_pubkey(js, "erring_node", erring_node);
|
||||||
|
json_add_short_channel_id(js, "erring_channel", erring_channel);
|
||||||
|
json_add_num(js, "erring_direction", channel_dir);
|
||||||
|
json_object_end(js);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* onionreply used if pay_errcode == PAY_UNPARSEABLE_ONION */
|
||||||
|
static struct command_result *
|
||||||
|
sendpay_fail(struct command *cmd,
|
||||||
|
int pay_errcode,
|
||||||
|
const u8 *onionreply,
|
||||||
|
const struct routing_failure *fail,
|
||||||
|
const char *details)
|
||||||
|
{
|
||||||
struct json_stream *data;
|
struct json_stream *data;
|
||||||
switch (r->errorcode) {
|
|
||||||
/* We will never handle this case */
|
|
||||||
case PAY_IN_PROGRESS:
|
|
||||||
abort();
|
|
||||||
|
|
||||||
case PAY_RHASH_ALREADY_USED:
|
if (pay_errcode == PAY_UNPARSEABLE_ONION) {
|
||||||
case PAY_UNSPECIFIED_ERROR:
|
data = json_stream_fail(cmd, PAY_UNPARSEABLE_ONION,
|
||||||
case PAY_NO_SUCH_PAYMENT:
|
"Malformed error reply");
|
||||||
was_pending(command_fail(cmd, r->errorcode, "%s",
|
|
||||||
r->details));
|
|
||||||
return;
|
|
||||||
|
|
||||||
case PAY_UNPARSEABLE_ONION:
|
|
||||||
msg = tal_fmt(tmpctx,
|
|
||||||
"failed: WIRE_PERMANENT_NODE_FAILURE "
|
|
||||||
"(%s)",
|
|
||||||
r->details);
|
|
||||||
|
|
||||||
data = json_stream_fail(cmd, r->errorcode, msg);
|
|
||||||
json_object_start(data, NULL);
|
json_object_start(data, NULL);
|
||||||
json_add_hex_talarr(data, "onionreply", r->onionreply);
|
json_add_hex_talarr(data, "onionreply", onionreply);
|
||||||
json_object_end(data);
|
json_object_end(data);
|
||||||
was_pending(command_failed(cmd, data));
|
return command_failed(cmd, data);
|
||||||
return;
|
}
|
||||||
|
|
||||||
case PAY_DESTINATION_PERM_FAIL:
|
assert(fail);
|
||||||
case PAY_TRY_OTHER_ROUTE:
|
data = json_stream_fail(cmd, pay_errcode,
|
||||||
fail = r->routing_failure;
|
tal_fmt(tmpctx, "failed: %s (%s)",
|
||||||
msg = tal_fmt(cmd,
|
|
||||||
"failed: %s (%s)",
|
|
||||||
onion_type_name(fail->failcode),
|
onion_type_name(fail->failcode),
|
||||||
r->details);
|
details));
|
||||||
data = json_stream_fail(cmd, r->errorcode, msg);
|
json_add_routefail_info(data,
|
||||||
|
fail->erring_index,
|
||||||
json_object_start(data, NULL);
|
fail->failcode,
|
||||||
json_add_num(data, "erring_index",
|
&fail->erring_node,
|
||||||
fail->erring_index);
|
&fail->erring_channel,
|
||||||
json_add_num(data, "failcode",
|
|
||||||
(unsigned) fail->failcode);
|
|
||||||
json_add_pubkey(data, "erring_node", &fail->erring_node);
|
|
||||||
json_add_short_channel_id(data, "erring_channel",
|
|
||||||
&fail->erring_channel);
|
|
||||||
json_add_num(data, "erring_direction",
|
|
||||||
fail->channel_dir);
|
fail->channel_dir);
|
||||||
json_object_end(data);
|
return command_failed(cmd, data);
|
||||||
was_pending(command_failed(cmd, data));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void json_sendpay_on_resolve(struct command *cmd,
|
/* We defer sendpay "success" until we know it's pending; consumes cmd */
|
||||||
const struct sendpay_result* r)
|
static struct command_result *
|
||||||
|
json_sendpay_in_progress(struct command *cmd,
|
||||||
|
const struct wallet_payment *payment)
|
||||||
{
|
{
|
||||||
if (!r->succeeded && r->errorcode == PAY_IN_PROGRESS) {
|
|
||||||
/* This is normal for sendpay. Succeed. */
|
|
||||||
struct json_stream *response = json_stream_success(cmd);
|
struct json_stream *response = json_stream_success(cmd);
|
||||||
json_object_start(response, NULL);
|
json_object_start(response, NULL);
|
||||||
json_add_string(response, "message",
|
json_add_string(response, "message",
|
||||||
"Monitor status with listpayments or waitsendpay");
|
"Monitor status with listpayments or waitsendpay");
|
||||||
json_add_payment_fields(response, r->payment);
|
json_add_payment_fields(response, payment);
|
||||||
json_object_end(response);
|
json_object_end(response);
|
||||||
was_pending(command_success(cmd, response));
|
return command_success(cmd, response);
|
||||||
} else
|
|
||||||
json_waitsendpay_on_resolve(cmd, r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void waitsendpay_resolve(struct lightningd *ld,
|
static void tell_waiters_failed(struct lightningd *ld,
|
||||||
const struct sha256 *payment_hash,
|
const struct sha256 *payment_hash,
|
||||||
const struct sendpay_result *result)
|
int pay_errcode,
|
||||||
|
const u8 *onionreply,
|
||||||
|
const struct routing_failure *fail,
|
||||||
|
const char *details)
|
||||||
{
|
{
|
||||||
struct sendpay_command *pc;
|
struct sendpay_command *pc;
|
||||||
struct sendpay_command *next;
|
struct sendpay_command *next;
|
||||||
|
|
||||||
|
/* Careful: sendpay_fail deletes cmd */
|
||||||
list_for_each_safe(&ld->waitsendpay_commands, pc, next, list) {
|
list_for_each_safe(&ld->waitsendpay_commands, pc, next, list) {
|
||||||
if (!sha256_eq(payment_hash, &pc->payment_hash))
|
if (!sha256_eq(payment_hash, &pc->payment_hash))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Delete later if callback does not delete. */
|
sendpay_fail(pc->cmd, pay_errcode, onionreply, fail, details);
|
||||||
tal_steal(tmpctx, pc);
|
|
||||||
json_waitsendpay_on_resolve(pc->cmd, result);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sendpay_result*
|
static void tell_waiters_success(struct lightningd *ld,
|
||||||
sendpay_result_success(const tal_t *ctx,
|
|
||||||
const struct preimage *payment_preimage,
|
|
||||||
const struct wallet_payment *payment)
|
|
||||||
{
|
|
||||||
struct sendpay_result *result = tal(ctx, struct sendpay_result);
|
|
||||||
result->succeeded = true;
|
|
||||||
result->preimage = *payment_preimage;
|
|
||||||
result->payment = payment;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void payment_trigger_success(struct lightningd *ld,
|
|
||||||
const struct sha256 *payment_hash)
|
|
||||||
{
|
|
||||||
struct sendpay_result *result;
|
|
||||||
struct wallet_payment *payment;
|
|
||||||
|
|
||||||
payment = wallet_payment_by_hash(tmpctx, ld->wallet, payment_hash);
|
|
||||||
assert(payment);
|
|
||||||
|
|
||||||
result = sendpay_result_success(tmpctx, payment->payment_preimage, payment);
|
|
||||||
|
|
||||||
waitsendpay_resolve(ld, payment_hash, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct sendpay_result*
|
|
||||||
sendpay_result_route_failure(const tal_t *ctx,
|
|
||||||
bool retry_plausible,
|
|
||||||
struct routing_failure *fail,
|
|
||||||
const u8 *onionreply,
|
|
||||||
const char *details)
|
|
||||||
{
|
|
||||||
struct sendpay_result *result = tal(ctx, struct sendpay_result);
|
|
||||||
result->succeeded = false;
|
|
||||||
result->errorcode =
|
|
||||||
(!fail) ? PAY_UNPARSEABLE_ONION :
|
|
||||||
(!retry_plausible) ? PAY_DESTINATION_PERM_FAIL :
|
|
||||||
/*otherwise*/ PAY_TRY_OTHER_ROUTE ;
|
|
||||||
result->onionreply = onionreply;
|
|
||||||
result->routing_failure = fail;
|
|
||||||
result->details = details;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void payment_route_failure(struct lightningd *ld,
|
|
||||||
const struct sha256 *payment_hash,
|
const struct sha256 *payment_hash,
|
||||||
bool retry_plausible,
|
struct wallet_payment *payment)
|
||||||
struct routing_failure *fail,
|
|
||||||
const u8 *onionreply,
|
|
||||||
const char *details)
|
|
||||||
{
|
{
|
||||||
struct sendpay_result *result;
|
struct sendpay_command *pc;
|
||||||
|
struct sendpay_command *next;
|
||||||
|
|
||||||
result = sendpay_result_route_failure(tmpctx,
|
/* Careful: sendpay_success deletes cmd */
|
||||||
retry_plausible,
|
list_for_each_safe(&ld->waitsendpay_commands, pc, next, list) {
|
||||||
fail,
|
if (!sha256_eq(payment_hash, &pc->payment_hash))
|
||||||
onionreply,
|
continue;
|
||||||
details);
|
|
||||||
|
|
||||||
waitsendpay_resolve(ld, payment_hash, result);
|
sendpay_success(pc->cmd, payment);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sendpay_result *
|
|
||||||
sendpay_result_simple_fail(const tal_t *ctx,
|
|
||||||
int errorcode,
|
|
||||||
char const *details)
|
|
||||||
{
|
|
||||||
struct sendpay_result *result = tal(ctx, struct sendpay_result);
|
|
||||||
result->succeeded = false;
|
|
||||||
result->errorcode = errorcode;
|
|
||||||
result->details = details;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct sendpay_result *
|
|
||||||
sendpay_result_in_progress(const tal_t *ctx,
|
|
||||||
const struct wallet_payment* payment,
|
|
||||||
char const *details)
|
|
||||||
{
|
|
||||||
struct sendpay_result *result = tal(ctx, struct sendpay_result);
|
|
||||||
result->succeeded = false;
|
|
||||||
result->errorcode = PAY_IN_PROGRESS;
|
|
||||||
result->payment = payment;
|
|
||||||
result->details = details;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void payment_succeeded(struct lightningd *ld, struct htlc_out *hout,
|
void payment_succeeded(struct lightningd *ld, struct htlc_out *hout,
|
||||||
const struct preimage *rval)
|
const struct preimage *rval)
|
||||||
{
|
{
|
||||||
|
struct wallet_payment *payment;
|
||||||
|
|
||||||
wallet_payment_set_status(ld->wallet, &hout->payment_hash,
|
wallet_payment_set_status(ld->wallet, &hout->payment_hash,
|
||||||
PAYMENT_COMPLETE, rval);
|
PAYMENT_COMPLETE, rval);
|
||||||
payment_trigger_success(ld, &hout->payment_hash);
|
payment = wallet_payment_by_hash(tmpctx, ld->wallet,
|
||||||
|
&hout->payment_hash);
|
||||||
|
assert(payment);
|
||||||
|
|
||||||
|
tell_waiters_success(ld, &hout->payment_hash, payment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return a struct routing_failure for an immediate failure
|
/* Return a struct routing_failure for an immediate failure
|
||||||
@@ -349,11 +252,7 @@ immediate_routing_failure(const tal_t *ctx,
|
|||||||
routing_failure->failcode = failcode;
|
routing_failure->failcode = failcode;
|
||||||
routing_failure->erring_node = ld->id;
|
routing_failure->erring_node = ld->id;
|
||||||
routing_failure->erring_channel = *channel0;
|
routing_failure->erring_channel = *channel0;
|
||||||
if (dstid)
|
|
||||||
routing_failure->channel_dir = pubkey_idx(&ld->id, dstid);
|
routing_failure->channel_dir = pubkey_idx(&ld->id, dstid);
|
||||||
/* FIXME: Don't set at all unless we know. */
|
|
||||||
else
|
|
||||||
routing_failure->channel_dir = 0;
|
|
||||||
|
|
||||||
return routing_failure;
|
return routing_failure;
|
||||||
}
|
}
|
||||||
@@ -383,17 +282,14 @@ local_routing_failure(const tal_t *ctx,
|
|||||||
return routing_failure;
|
return routing_failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return false if permanent failure at the destination, true if
|
/* Fills in *pay_errcode with PAY_TRY_OTHER_ROUTE or PAY_DESTINATION_PERM_FAIL */
|
||||||
* retrying is plausible. Fill *routing_failure with NULL if
|
|
||||||
* we cannot report the remote failure, or with the routing
|
|
||||||
* failure to report (allocated from ctx) otherwise. */
|
|
||||||
static struct routing_failure*
|
static struct routing_failure*
|
||||||
remote_routing_failure(const tal_t *ctx,
|
remote_routing_failure(const tal_t *ctx,
|
||||||
struct lightningd *ld,
|
struct lightningd *ld,
|
||||||
bool *p_retry_plausible,
|
|
||||||
const struct wallet_payment *payment,
|
const struct wallet_payment *payment,
|
||||||
const struct onionreply *failure,
|
const struct onionreply *failure,
|
||||||
struct log *log)
|
struct log *log,
|
||||||
|
int *pay_errcode)
|
||||||
{
|
{
|
||||||
enum onion_type failcode = fromwire_peektype(failure->msg);
|
enum onion_type failcode = fromwire_peektype(failure->msg);
|
||||||
struct routing_failure *routing_failure;
|
struct routing_failure *routing_failure;
|
||||||
@@ -403,14 +299,12 @@ remote_routing_failure(const tal_t *ctx,
|
|||||||
const struct short_channel_id *erring_channel;
|
const struct short_channel_id *erring_channel;
|
||||||
static const struct short_channel_id dummy_channel = { 0 };
|
static const struct short_channel_id dummy_channel = { 0 };
|
||||||
int origin_index;
|
int origin_index;
|
||||||
bool retry_plausible;
|
|
||||||
int dir;
|
int dir;
|
||||||
|
|
||||||
routing_failure = tal(ctx, struct routing_failure);
|
routing_failure = tal(ctx, struct routing_failure);
|
||||||
route_nodes = payment->route_nodes;
|
route_nodes = payment->route_nodes;
|
||||||
route_channels = payment->route_channels;
|
route_channels = payment->route_channels;
|
||||||
origin_index = failure->origin_index;
|
origin_index = failure->origin_index;
|
||||||
retry_plausible = true;
|
|
||||||
|
|
||||||
assert(origin_index < tal_count(route_nodes));
|
assert(origin_index < tal_count(route_nodes));
|
||||||
|
|
||||||
@@ -427,13 +321,15 @@ remote_routing_failure(const tal_t *ctx,
|
|||||||
* - SHOULD fail the payment.
|
* - SHOULD fail the payment.
|
||||||
* */
|
* */
|
||||||
if (failcode & PERM)
|
if (failcode & PERM)
|
||||||
retry_plausible = false;
|
*pay_errcode = PAY_DESTINATION_PERM_FAIL;
|
||||||
else
|
else
|
||||||
retry_plausible = true;
|
*pay_errcode = PAY_TRY_OTHER_ROUTE;
|
||||||
erring_node = &route_nodes[origin_index];
|
erring_node = &route_nodes[origin_index];
|
||||||
} else {
|
} else {
|
||||||
u8 *gossip_msg;
|
u8 *gossip_msg;
|
||||||
|
|
||||||
|
*pay_errcode = PAY_TRY_OTHER_ROUTE;
|
||||||
|
|
||||||
/* Report the *next* channel as failing. */
|
/* Report the *next* channel as failing. */
|
||||||
erring_channel = &route_channels[origin_index + 1];
|
erring_channel = &route_channels[origin_index + 1];
|
||||||
|
|
||||||
@@ -466,35 +362,26 @@ remote_routing_failure(const tal_t *ctx,
|
|||||||
routing_failure->erring_channel = *erring_channel;
|
routing_failure->erring_channel = *erring_channel;
|
||||||
routing_failure->channel_dir = dir;
|
routing_failure->channel_dir = dir;
|
||||||
|
|
||||||
*p_retry_plausible = retry_plausible;
|
|
||||||
|
|
||||||
return routing_failure;
|
return routing_failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
void payment_store(struct lightningd *ld,
|
void payment_store(struct lightningd *ld, const struct sha256 *payment_hash)
|
||||||
const struct sha256 *payment_hash)
|
|
||||||
{
|
{
|
||||||
struct sendpay_command *pc;
|
struct sendpay_command *pc;
|
||||||
struct sendpay_command *next;
|
struct sendpay_command *next;
|
||||||
struct sendpay_result *result;
|
|
||||||
const struct wallet_payment *payment;
|
const struct wallet_payment *payment;
|
||||||
|
|
||||||
wallet_payment_store(ld->wallet, payment_hash);
|
wallet_payment_store(ld->wallet, payment_hash);
|
||||||
payment = wallet_payment_by_hash(tmpctx, ld->wallet, payment_hash);
|
payment = wallet_payment_by_hash(tmpctx, ld->wallet, payment_hash);
|
||||||
assert(payment);
|
assert(payment);
|
||||||
|
|
||||||
/* Invent a sendpay result with PAY_IN_PROGRESS. */
|
|
||||||
result = sendpay_result_in_progress(tmpctx, payment,
|
|
||||||
"Payment is still in progress");
|
|
||||||
|
|
||||||
/* Trigger any sendpay commands waiting for the store to occur. */
|
/* Trigger any sendpay commands waiting for the store to occur. */
|
||||||
list_for_each_safe(&ld->sendpay_commands, pc, next, list) {
|
list_for_each_safe(&ld->sendpay_commands, pc, next, list) {
|
||||||
if (!sha256_eq(payment_hash, &pc->payment_hash))
|
if (!sha256_eq(payment_hash, &pc->payment_hash))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Delete later if callback does not delete. */
|
/* Deletes from list, frees pc */
|
||||||
tal_steal(tmpctx, pc);
|
json_sendpay_in_progress(pc->cmd, payment);
|
||||||
json_sendpay_on_resolve(pc->cmd, result);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,7 +391,7 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
|
|||||||
struct wallet_payment *payment;
|
struct wallet_payment *payment;
|
||||||
struct routing_failure* fail = NULL;
|
struct routing_failure* fail = NULL;
|
||||||
const char *failmsg;
|
const char *failmsg;
|
||||||
bool retry_plausible;
|
int pay_errcode;
|
||||||
|
|
||||||
payment = wallet_payment_by_hash(tmpctx, ld->wallet,
|
payment = wallet_payment_by_hash(tmpctx, ld->wallet,
|
||||||
&hout->payment_hash);
|
&hout->payment_hash);
|
||||||
@@ -543,7 +430,7 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
|
|||||||
if (localfail) {
|
if (localfail) {
|
||||||
fail = local_routing_failure(tmpctx, ld, hout, payment);
|
fail = local_routing_failure(tmpctx, ld, hout, payment);
|
||||||
failmsg = localfail;
|
failmsg = localfail;
|
||||||
retry_plausible = true;
|
pay_errcode = PAY_TRY_OTHER_ROUTE;
|
||||||
} else {
|
} else {
|
||||||
/* Must be remote fail. */
|
/* Must be remote fail. */
|
||||||
assert(!hout->failcode);
|
assert(!hout->failcode);
|
||||||
@@ -562,7 +449,7 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
|
|||||||
tal_hex(tmpctx, hout->failuremsg));
|
tal_hex(tmpctx, hout->failuremsg));
|
||||||
/* Cannot record failure. */
|
/* Cannot record failure. */
|
||||||
fail = NULL;
|
fail = NULL;
|
||||||
retry_plausible = true;
|
pay_errcode = PAY_UNPARSEABLE_ONION;
|
||||||
} else {
|
} else {
|
||||||
enum onion_type failcode = fromwire_peektype(reply->msg);
|
enum onion_type failcode = fromwire_peektype(reply->msg);
|
||||||
log_info(hout->key.channel->log,
|
log_info(hout->key.channel->log,
|
||||||
@@ -573,9 +460,9 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
|
|||||||
reply->origin_index,
|
reply->origin_index,
|
||||||
failcode, onion_type_name(failcode));
|
failcode, onion_type_name(failcode));
|
||||||
fail = remote_routing_failure(tmpctx, ld,
|
fail = remote_routing_failure(tmpctx, ld,
|
||||||
&retry_plausible,
|
|
||||||
payment, reply,
|
payment, reply,
|
||||||
hout->key.channel->log);
|
hout->key.channel->log,
|
||||||
|
&pay_errcode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -586,7 +473,7 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
|
|||||||
wallet_payment_set_failinfo(ld->wallet,
|
wallet_payment_set_failinfo(ld->wallet,
|
||||||
&hout->payment_hash,
|
&hout->payment_hash,
|
||||||
fail ? NULL : hout->failuremsg,
|
fail ? NULL : hout->failuremsg,
|
||||||
(fail && !retry_plausible),
|
pay_errcode == PAY_DESTINATION_PERM_FAIL,
|
||||||
fail ? fail->erring_index : -1,
|
fail ? fail->erring_index : -1,
|
||||||
fail ? fail->failcode : 0,
|
fail ? fail->failcode : 0,
|
||||||
fail ? &fail->erring_node : NULL,
|
fail ? &fail->erring_node : NULL,
|
||||||
@@ -595,24 +482,18 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
|
|||||||
failmsg,
|
failmsg,
|
||||||
fail ? fail->channel_dir : 0);
|
fail ? fail->channel_dir : 0);
|
||||||
|
|
||||||
/* Report to client. */
|
tell_waiters_failed(ld, &hout->payment_hash, pay_errcode,
|
||||||
payment_route_failure(ld, &hout->payment_hash,
|
hout->failuremsg, fail, failmsg);
|
||||||
retry_plausible, fail, hout->failuremsg,
|
|
||||||
failmsg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for a payment. If cmd is deleted, then json_waitsendpay_on_resolve
|
/* Wait for a payment. If cmd is deleted, then json_waitsendpay_on_resolve
|
||||||
* no longer be called.
|
* no longer be called.
|
||||||
* Return false if we called callback already, true if
|
* Return callback if we called already, otherwise NULL. */
|
||||||
* callback is scheduled for later. */
|
static struct command_result *wait_payment(struct lightningd *ld,
|
||||||
static bool wait_payment(struct lightningd *ld,
|
|
||||||
struct command *cmd,
|
struct command *cmd,
|
||||||
const struct sha256 *payment_hash)
|
const struct sha256 *payment_hash)
|
||||||
{
|
{
|
||||||
struct wallet_payment *payment;
|
struct wallet_payment *payment;
|
||||||
struct sendpay_result *result;
|
|
||||||
char const *details;
|
|
||||||
bool cb_not_called;
|
|
||||||
u8 *failonionreply;
|
u8 *failonionreply;
|
||||||
bool faildestperm;
|
bool faildestperm;
|
||||||
int failindex;
|
int failindex;
|
||||||
@@ -626,31 +507,19 @@ static bool wait_payment(struct lightningd *ld,
|
|||||||
|
|
||||||
payment = wallet_payment_by_hash(tmpctx, ld->wallet, payment_hash);
|
payment = wallet_payment_by_hash(tmpctx, ld->wallet, payment_hash);
|
||||||
if (!payment) {
|
if (!payment) {
|
||||||
details = tal_fmt(tmpctx,
|
return command_fail(cmd, PAY_NO_SUCH_PAYMENT,
|
||||||
"Never attempted payment for '%s'",
|
"Never attempted payment for '%s'",
|
||||||
type_to_string(tmpctx, struct sha256,
|
type_to_string(tmpctx, struct sha256,
|
||||||
payment_hash));
|
payment_hash));
|
||||||
result = sendpay_result_simple_fail(tmpctx,
|
|
||||||
PAY_NO_SUCH_PAYMENT,
|
|
||||||
details);
|
|
||||||
json_waitsendpay_on_resolve(cmd, result);
|
|
||||||
cb_not_called = false;
|
|
||||||
goto end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (payment->status) {
|
switch (payment->status) {
|
||||||
case PAYMENT_PENDING:
|
case PAYMENT_PENDING:
|
||||||
add_waitsendpay_waiter(ld, cmd, payment_hash);
|
add_waitsendpay_waiter(ld, cmd, payment_hash);
|
||||||
cb_not_called = true;
|
return NULL;
|
||||||
goto end;
|
|
||||||
|
|
||||||
case PAYMENT_COMPLETE:
|
case PAYMENT_COMPLETE:
|
||||||
result = sendpay_result_success(tmpctx,
|
return sendpay_success(cmd, payment);
|
||||||
payment->payment_preimage,
|
|
||||||
payment);
|
|
||||||
json_waitsendpay_on_resolve(cmd, result);
|
|
||||||
cb_not_called = false;
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
case PAYMENT_FAILED:
|
case PAYMENT_FAILED:
|
||||||
/* Get error from DB */
|
/* Get error from DB */
|
||||||
@@ -665,13 +534,14 @@ static bool wait_payment(struct lightningd *ld,
|
|||||||
&faildetail,
|
&faildetail,
|
||||||
&faildirection);
|
&faildirection);
|
||||||
/* Old DB might not save failure information */
|
/* Old DB might not save failure information */
|
||||||
if (!failonionreply && !failnode)
|
if (!failonionreply && !failnode) {
|
||||||
result = sendpay_result_simple_fail(tmpctx,
|
return command_fail(cmd, PAY_UNSPECIFIED_ERROR,
|
||||||
PAY_UNSPECIFIED_ERROR,
|
|
||||||
"Payment failure reason unknown");
|
"Payment failure reason unknown");
|
||||||
else if (failonionreply) {
|
} else if (failonionreply) {
|
||||||
/* failed to parse returned onion error */
|
/* failed to parse returned onion error */
|
||||||
result = sendpay_result_route_failure(tmpctx, true, NULL, failonionreply, faildetail);
|
return sendpay_fail(cmd, PAY_UNPARSEABLE_ONION,
|
||||||
|
failonionreply,
|
||||||
|
NULL, faildetail);
|
||||||
} else {
|
} else {
|
||||||
/* Parsed onion error, get its details */
|
/* Parsed onion error, get its details */
|
||||||
assert(failnode);
|
assert(failnode);
|
||||||
@@ -682,23 +552,21 @@ static bool wait_payment(struct lightningd *ld,
|
|||||||
fail->erring_node = *failnode;
|
fail->erring_node = *failnode;
|
||||||
fail->erring_channel = *failchannel;
|
fail->erring_channel = *failchannel;
|
||||||
fail->channel_dir = faildirection;
|
fail->channel_dir = faildirection;
|
||||||
result = sendpay_result_route_failure(tmpctx, !faildestperm, fail, NULL, faildetail);
|
return sendpay_fail(cmd,
|
||||||
|
faildestperm
|
||||||
|
? PAY_DESTINATION_PERM_FAIL
|
||||||
|
: PAY_TRY_OTHER_ROUTE,
|
||||||
|
NULL,
|
||||||
|
fail, faildetail);
|
||||||
}
|
}
|
||||||
|
|
||||||
json_waitsendpay_on_resolve(cmd, result);
|
|
||||||
cb_not_called = false;
|
|
||||||
goto end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Impossible. */
|
/* Impossible. */
|
||||||
abort();
|
abort();
|
||||||
|
|
||||||
end:
|
|
||||||
return cb_not_called;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns false if json_sendpay_on_resolve was called, true if not yet called. */
|
/* Returns command_result if cmd was resolved, NULL if not yet called. */
|
||||||
static bool
|
static struct command_result *
|
||||||
send_payment(struct lightningd *ld,
|
send_payment(struct lightningd *ld,
|
||||||
struct command *cmd,
|
struct command *cmd,
|
||||||
const struct sha256 *rhash,
|
const struct sha256 *rhash,
|
||||||
@@ -720,7 +588,6 @@ send_payment(struct lightningd *ld,
|
|||||||
struct short_channel_id *channels;
|
struct short_channel_id *channels;
|
||||||
struct routing_failure *fail;
|
struct routing_failure *fail;
|
||||||
struct channel *channel;
|
struct channel *channel;
|
||||||
struct sendpay_result *result;
|
|
||||||
|
|
||||||
/* Expiry for HTLCs is absolute. And add one to give some margin. */
|
/* Expiry for HTLCs is absolute. And add one to give some margin. */
|
||||||
base_expiry = get_block_height(ld->topology) + 1;
|
base_expiry = get_block_height(ld->topology) + 1;
|
||||||
@@ -751,61 +618,40 @@ send_payment(struct lightningd *ld,
|
|||||||
log_debug(ld->log, "send_payment: found previous");
|
log_debug(ld->log, "send_payment: found previous");
|
||||||
if (payment->status == PAYMENT_PENDING) {
|
if (payment->status == PAYMENT_PENDING) {
|
||||||
log_add(ld->log, "Payment is still in progress");
|
log_add(ld->log, "Payment is still in progress");
|
||||||
result = sendpay_result_in_progress(tmpctx,
|
return json_sendpay_in_progress(cmd, payment);
|
||||||
payment,
|
|
||||||
"Payment is still in progress");
|
|
||||||
json_sendpay_on_resolve(cmd, result);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (payment->status == PAYMENT_COMPLETE) {
|
if (payment->status == PAYMENT_COMPLETE) {
|
||||||
log_add(ld->log, "... succeeded");
|
log_add(ld->log, "... succeeded");
|
||||||
/* Must match successful payment parameters. */
|
/* Must match successful payment parameters. */
|
||||||
if (payment->msatoshi != msatoshi) {
|
if (payment->msatoshi != msatoshi) {
|
||||||
char *msg = tal_fmt(tmpctx,
|
return command_fail(cmd, PAY_RHASH_ALREADY_USED,
|
||||||
"Already succeeded "
|
"Already succeeded "
|
||||||
"with amount %"PRIu64,
|
"with amount %"PRIu64,
|
||||||
payment->msatoshi);
|
payment->msatoshi);
|
||||||
result = sendpay_result_simple_fail(tmpctx,
|
|
||||||
PAY_RHASH_ALREADY_USED,
|
|
||||||
msg);
|
|
||||||
json_sendpay_on_resolve(cmd, result);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (!pubkey_eq(&payment->destination, &ids[n_hops-1])) {
|
if (!pubkey_eq(&payment->destination, &ids[n_hops-1])) {
|
||||||
char *msg = tal_fmt(tmpctx,
|
return command_fail(cmd, PAY_RHASH_ALREADY_USED,
|
||||||
"Already succeeded to %s",
|
"Already succeeded to %s",
|
||||||
type_to_string(tmpctx,
|
type_to_string(tmpctx,
|
||||||
struct pubkey,
|
struct pubkey,
|
||||||
&payment->destination));
|
&payment->destination));
|
||||||
result = sendpay_result_simple_fail(tmpctx,
|
|
||||||
PAY_RHASH_ALREADY_USED,
|
|
||||||
msg);
|
|
||||||
json_sendpay_on_resolve(cmd, result);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
result = sendpay_result_success(tmpctx,
|
return sendpay_success(cmd, payment);
|
||||||
payment->payment_preimage,
|
|
||||||
payment);
|
|
||||||
json_sendpay_on_resolve(cmd, result);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
log_add(ld->log, "... retrying");
|
log_add(ld->log, "... retrying");
|
||||||
}
|
}
|
||||||
|
|
||||||
channel = active_channel_by_id(ld, &ids[0], NULL);
|
channel = active_channel_by_id(ld, &ids[0], NULL);
|
||||||
if (!channel) {
|
if (!channel) {
|
||||||
/* Report routing failure to gossipd */
|
struct json_stream *data
|
||||||
fail = immediate_routing_failure(cmd, ld,
|
= json_stream_fail(cmd, PAY_TRY_OTHER_ROUTE,
|
||||||
WIRE_UNKNOWN_NEXT_PEER,
|
|
||||||
&route[0].channel_id,
|
|
||||||
0);
|
|
||||||
|
|
||||||
/* Report routing failure to caller */
|
|
||||||
result = sendpay_result_route_failure(tmpctx, true, fail, NULL,
|
|
||||||
"No connection to first "
|
"No connection to first "
|
||||||
"peer found");
|
"peer found");
|
||||||
json_sendpay_on_resolve(cmd, result);
|
|
||||||
return false;
|
json_add_routefail_info(data, 0, WIRE_UNKNOWN_NEXT_PEER,
|
||||||
|
&ld->id, &route[0].channel_id,
|
||||||
|
pubkey_idx(&ld->id, &route[0].nodeid));
|
||||||
|
return command_failed(cmd, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
randombytes_buf(&sessionkey, sizeof(sessionkey));
|
randombytes_buf(&sessionkey, sizeof(sessionkey));
|
||||||
@@ -822,17 +668,13 @@ send_payment(struct lightningd *ld,
|
|||||||
base_expiry + route[0].delay,
|
base_expiry + route[0].delay,
|
||||||
rhash, onion, NULL, &hout);
|
rhash, onion, NULL, &hout);
|
||||||
if (failcode) {
|
if (failcode) {
|
||||||
/* Report routing failure to gossipd */
|
|
||||||
fail = immediate_routing_failure(cmd, ld,
|
fail = immediate_routing_failure(cmd, ld,
|
||||||
failcode,
|
failcode,
|
||||||
&route[0].channel_id,
|
&route[0].channel_id,
|
||||||
&channel->peer->id);
|
&channel->peer->id);
|
||||||
|
|
||||||
/* Report routing failure to caller */
|
return sendpay_fail(cmd, PAY_TRY_OTHER_ROUTE, NULL,
|
||||||
result = sendpay_result_route_failure(tmpctx, true, fail, NULL,
|
fail, "First peer not ready");
|
||||||
"First peer not ready");
|
|
||||||
json_sendpay_on_resolve(cmd, result);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy channels used along the route. */
|
/* Copy channels used along the route. */
|
||||||
@@ -872,8 +714,7 @@ send_payment(struct lightningd *ld,
|
|||||||
wallet_payment_setup(ld->wallet, payment);
|
wallet_payment_setup(ld->wallet, payment);
|
||||||
|
|
||||||
add_sendpay_waiter(ld, cmd, rhash);
|
add_sendpay_waiter(ld, cmd, rhash);
|
||||||
|
return NULL;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
@@ -892,6 +733,7 @@ static struct command_result *json_sendpay(struct command *cmd,
|
|||||||
struct route_hop *route;
|
struct route_hop *route;
|
||||||
u64 *msatoshi;
|
u64 *msatoshi;
|
||||||
const char *description;
|
const char *description;
|
||||||
|
struct command_result *res;
|
||||||
|
|
||||||
if (!param(cmd, buffer, params,
|
if (!param(cmd, buffer, params,
|
||||||
p_req("route", param_array, &routetok),
|
p_req("route", param_array, &routetok),
|
||||||
@@ -942,12 +784,12 @@ static struct command_result *json_sendpay(struct command *cmd,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (send_payment(cmd->ld, cmd, rhash, route,
|
res = send_payment(cmd->ld, cmd, rhash, route,
|
||||||
msatoshi ? *msatoshi : route[routetok->size-1].amount,
|
msatoshi ? *msatoshi : route[routetok->size-1].amount,
|
||||||
description))
|
description);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
return command_still_pending(cmd);
|
return command_still_pending(cmd);
|
||||||
return command_its_complicated("send_payment is called in multiple paths,"
|
|
||||||
" patching return value through is hard");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct json_command sendpay_command = {
|
static const struct json_command sendpay_command = {
|
||||||
@@ -970,6 +812,7 @@ static struct command_result *json_waitsendpay(struct command *cmd,
|
|||||||
{
|
{
|
||||||
struct sha256 *rhash;
|
struct sha256 *rhash;
|
||||||
unsigned int *timeout;
|
unsigned int *timeout;
|
||||||
|
struct command_result *res;
|
||||||
|
|
||||||
if (!param(cmd, buffer, params,
|
if (!param(cmd, buffer, params,
|
||||||
p_req("payment_hash", param_sha256, &rhash),
|
p_req("payment_hash", param_sha256, &rhash),
|
||||||
@@ -977,10 +820,9 @@ static struct command_result *json_waitsendpay(struct command *cmd,
|
|||||||
NULL))
|
NULL))
|
||||||
return command_param_failed();
|
return command_param_failed();
|
||||||
|
|
||||||
if (!wait_payment(cmd->ld, cmd, rhash))
|
res = wait_payment(cmd->ld, cmd, rhash);
|
||||||
return command_its_complicated("wait_payment called in multiple"
|
if (res)
|
||||||
" paths, patching return value"
|
return res;
|
||||||
" through is hard");
|
|
||||||
|
|
||||||
if (timeout)
|
if (timeout)
|
||||||
new_reltimer(&cmd->ld->timers, cmd, time_from_sec(*timeout),
|
new_reltimer(&cmd->ld->timers, cmd, time_from_sec(*timeout),
|
||||||
|
|||||||
Reference in New Issue
Block a user