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:
Rusty Russell
2019-01-18 17:07:06 +10:30
committed by Christian Decker
parent 1c58351551
commit 4e6b8e13a4

View File

@@ -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),