mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 07:04:22 +01:00
lightningd: share more code between sendpay and sendonion.
In particular, we're about to do surgery on the detection-of-previous-payments logic, and we should not do this in two places. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
12985331f7
commit
618c390475
347
lightningd/pay.c
347
lightningd/pay.c
@@ -715,7 +715,142 @@ static enum onion_type send_onion(struct lightningd *ld,
|
|||||||
payment_hash, partid, onion, NULL, hout);
|
payment_hash, partid, onion, NULL, hout);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns command_result if cmd was resolved, NULL if not yet called. */
|
/* destination/route_channels/route_nodes are NULL (and path_secrets may be NULL)
|
||||||
|
* if we're sending a raw onion. */
|
||||||
|
static struct command_result *
|
||||||
|
send_payment_core(struct lightningd *ld,
|
||||||
|
struct command *cmd,
|
||||||
|
const struct sha256 *rhash,
|
||||||
|
u64 partid,
|
||||||
|
const struct route_hop *first_hop,
|
||||||
|
struct amount_msat msat,
|
||||||
|
struct amount_msat total_msat,
|
||||||
|
const char *label TAKES,
|
||||||
|
const char *b11str TAKES,
|
||||||
|
const struct onionpacket *packet,
|
||||||
|
const struct node_id *destination,
|
||||||
|
struct node_id *route_nodes TAKES,
|
||||||
|
struct short_channel_id *route_channels TAKES,
|
||||||
|
struct secret *path_secrets)
|
||||||
|
{
|
||||||
|
struct wallet_payment *payment;
|
||||||
|
struct channel *channel;
|
||||||
|
enum onion_type failcode;
|
||||||
|
struct htlc_out *hout;
|
||||||
|
struct routing_failure *fail;
|
||||||
|
|
||||||
|
/* Now, do we already have a payment? */
|
||||||
|
payment = wallet_payment_by_hash(tmpctx, ld->wallet, rhash, partid);
|
||||||
|
if (payment) {
|
||||||
|
/* FIXME: We should really do something smarter here! */
|
||||||
|
if (payment->status == PAYMENT_PENDING) {
|
||||||
|
log_debug(ld->log, "send_payment: previous still in progress");
|
||||||
|
return json_sendpay_in_progress(cmd, payment);
|
||||||
|
}
|
||||||
|
if (payment->status == PAYMENT_COMPLETE) {
|
||||||
|
log_debug(ld->log, "send_payment: previous succeeded");
|
||||||
|
/* Must match successful payment parameters. */
|
||||||
|
if (!amount_msat_eq(payment->msatoshi, msat)) {
|
||||||
|
return command_fail(cmd, PAY_RHASH_ALREADY_USED,
|
||||||
|
"Already succeeded "
|
||||||
|
"with amount %s",
|
||||||
|
type_to_string(tmpctx,
|
||||||
|
struct amount_msat,
|
||||||
|
&payment->msatoshi));
|
||||||
|
}
|
||||||
|
if (payment->destination && destination
|
||||||
|
&& !node_id_eq(payment->destination, destination)) {
|
||||||
|
return command_fail(cmd, PAY_RHASH_ALREADY_USED,
|
||||||
|
"Already succeeded to %s",
|
||||||
|
type_to_string(tmpctx,
|
||||||
|
struct node_id,
|
||||||
|
payment->destination));
|
||||||
|
}
|
||||||
|
return sendpay_success(cmd, payment);
|
||||||
|
}
|
||||||
|
log_debug(ld->log, "send_payment: found previous, retrying");
|
||||||
|
}
|
||||||
|
|
||||||
|
channel = active_channel_by_id(ld, &first_hop->nodeid, NULL);
|
||||||
|
if (!channel) {
|
||||||
|
struct json_stream *data
|
||||||
|
= json_stream_fail(cmd, PAY_TRY_OTHER_ROUTE,
|
||||||
|
"No connection to first "
|
||||||
|
"peer found");
|
||||||
|
|
||||||
|
json_add_routefail_info(data, 0, WIRE_UNKNOWN_NEXT_PEER,
|
||||||
|
&ld->id, &first_hop->channel_id,
|
||||||
|
node_id_idx(&ld->id, &first_hop->nodeid),
|
||||||
|
NULL);
|
||||||
|
json_object_end(data);
|
||||||
|
return command_failed(cmd, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
failcode = send_onion(ld, packet, first_hop, rhash, partid,
|
||||||
|
channel, &hout);
|
||||||
|
|
||||||
|
if (failcode) {
|
||||||
|
fail = immediate_routing_failure(cmd, ld,
|
||||||
|
failcode,
|
||||||
|
&first_hop->channel_id,
|
||||||
|
&channel->peer->id);
|
||||||
|
|
||||||
|
return sendpay_fail(cmd, payment, PAY_TRY_OTHER_ROUTE,
|
||||||
|
NULL, fail, "First peer not ready");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we're retrying, delete all trace of previous one. We delete
|
||||||
|
* outgoing HTLC, too, otherwise it gets reported to onchaind as
|
||||||
|
* a possibility, and we end up in handle_missing_htlc_output->
|
||||||
|
* onchain_failed_our_htlc->payment_failed with no payment.
|
||||||
|
*/
|
||||||
|
if (payment) {
|
||||||
|
wallet_payment_delete(ld->wallet, rhash, payment->partid);
|
||||||
|
wallet_local_htlc_out_delete(ld->wallet, channel, rhash,
|
||||||
|
payment->partid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If hout fails, payment should be freed too. */
|
||||||
|
payment = tal(hout, struct wallet_payment);
|
||||||
|
payment->id = 0;
|
||||||
|
payment->payment_hash = *rhash;
|
||||||
|
payment->partid = partid;
|
||||||
|
if (destination)
|
||||||
|
payment->destination = tal_dup(payment, struct node_id, destination);
|
||||||
|
else
|
||||||
|
payment->destination = NULL;
|
||||||
|
payment->status = PAYMENT_PENDING;
|
||||||
|
payment->msatoshi = msat;
|
||||||
|
payment->msatoshi_sent = first_hop->amount;
|
||||||
|
payment->total_msat = total_msat;
|
||||||
|
payment->timestamp = time_now().ts.tv_sec;
|
||||||
|
payment->payment_preimage = NULL;
|
||||||
|
payment->path_secrets = tal_steal(payment, path_secrets);
|
||||||
|
if (route_nodes)
|
||||||
|
payment->route_nodes = tal_steal(payment, route_nodes);
|
||||||
|
else
|
||||||
|
payment->route_nodes = NULL;
|
||||||
|
if (route_channels)
|
||||||
|
payment->route_channels = tal_steal(payment, route_channels);
|
||||||
|
else
|
||||||
|
payment->route_channels = NULL;
|
||||||
|
payment->failonion = NULL;
|
||||||
|
if (label != NULL)
|
||||||
|
payment->label = tal_strdup(payment, label);
|
||||||
|
else
|
||||||
|
payment->label = NULL;
|
||||||
|
if (b11str != NULL)
|
||||||
|
payment->bolt11 = tal_strdup(payment, b11str);
|
||||||
|
else
|
||||||
|
payment->bolt11 = NULL;
|
||||||
|
|
||||||
|
/* We write this into db when HTLC is actually sent. */
|
||||||
|
wallet_payment_setup(ld->wallet, payment);
|
||||||
|
|
||||||
|
add_sendpay_waiter(ld, cmd, rhash);
|
||||||
|
return command_still_pending(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
static struct command_result *
|
static struct command_result *
|
||||||
send_payment(struct lightningd *ld,
|
send_payment(struct lightningd *ld,
|
||||||
struct command *cmd,
|
struct command *cmd,
|
||||||
@@ -731,14 +866,9 @@ send_payment(struct lightningd *ld,
|
|||||||
unsigned int base_expiry;
|
unsigned int base_expiry;
|
||||||
struct onionpacket *packet;
|
struct onionpacket *packet;
|
||||||
struct secret *path_secrets;
|
struct secret *path_secrets;
|
||||||
enum onion_type failcode;
|
|
||||||
size_t i, n_hops = tal_count(route);
|
size_t i, n_hops = tal_count(route);
|
||||||
struct node_id *ids = tal_arr(tmpctx, struct node_id, n_hops);
|
struct node_id *ids = tal_arr(tmpctx, struct node_id, n_hops);
|
||||||
struct wallet_payment *payment = NULL;
|
|
||||||
struct htlc_out *hout;
|
|
||||||
struct short_channel_id *channels;
|
struct short_channel_id *channels;
|
||||||
struct routing_failure *fail;
|
|
||||||
struct channel *channel;
|
|
||||||
struct sphinx_path *path;
|
struct sphinx_path *path;
|
||||||
struct pubkey pubkey;
|
struct pubkey pubkey;
|
||||||
bool final_tlv, ret;
|
bool final_tlv, ret;
|
||||||
@@ -794,117 +924,19 @@ send_payment(struct lightningd *ld,
|
|||||||
}
|
}
|
||||||
sphinx_add_hop(path, &pubkey, onion);
|
sphinx_add_hop(path, &pubkey, onion);
|
||||||
|
|
||||||
/* Now, do we already have a payment? */
|
|
||||||
payment = wallet_payment_by_hash(tmpctx, ld->wallet, rhash, partid);
|
|
||||||
if (payment) {
|
|
||||||
/* FIXME: We should really do something smarter here! */
|
|
||||||
if (payment->status == PAYMENT_PENDING) {
|
|
||||||
log_debug(ld->log, "send_payment: previous still in progress");
|
|
||||||
return json_sendpay_in_progress(cmd, payment);
|
|
||||||
}
|
|
||||||
if (payment->status == PAYMENT_COMPLETE) {
|
|
||||||
log_debug(ld->log, "send_payment: previous succeeded");
|
|
||||||
/* Must match successful payment parameters. */
|
|
||||||
if (!amount_msat_eq(payment->msatoshi, msat)) {
|
|
||||||
return command_fail(cmd, PAY_RHASH_ALREADY_USED,
|
|
||||||
"Already succeeded "
|
|
||||||
"with amount %s",
|
|
||||||
type_to_string(tmpctx,
|
|
||||||
struct amount_msat,
|
|
||||||
&payment->msatoshi));
|
|
||||||
}
|
|
||||||
if (payment->destination &&
|
|
||||||
!node_id_eq(payment->destination,
|
|
||||||
&ids[n_hops - 1])) {
|
|
||||||
return command_fail(cmd, PAY_RHASH_ALREADY_USED,
|
|
||||||
"Already succeeded to %s",
|
|
||||||
type_to_string(tmpctx,
|
|
||||||
struct node_id,
|
|
||||||
payment->destination));
|
|
||||||
}
|
|
||||||
return sendpay_success(cmd, payment);
|
|
||||||
}
|
|
||||||
log_debug(ld->log, "send_payment: found previous, retrying");
|
|
||||||
}
|
|
||||||
|
|
||||||
channel = active_channel_by_id(ld, &ids[0], NULL);
|
|
||||||
if (!channel) {
|
|
||||||
struct json_stream *data
|
|
||||||
= json_stream_fail(cmd, PAY_TRY_OTHER_ROUTE,
|
|
||||||
"No connection to first "
|
|
||||||
"peer found");
|
|
||||||
|
|
||||||
json_add_routefail_info(data, 0, WIRE_UNKNOWN_NEXT_PEER,
|
|
||||||
&ld->id, &route[0].channel_id,
|
|
||||||
node_id_idx(&ld->id, &route[0].nodeid),
|
|
||||||
NULL);
|
|
||||||
json_object_end(data);
|
|
||||||
return command_failed(cmd, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
packet = create_onionpacket(tmpctx, path, &path_secrets);
|
|
||||||
failcode = send_onion(ld, packet, &route[0], rhash, partid,
|
|
||||||
channel, &hout);
|
|
||||||
log_info(ld->log, "Sending %s over %zu hops to deliver %s",
|
|
||||||
type_to_string(tmpctx, struct amount_msat, &route[0].amount),
|
|
||||||
n_hops, type_to_string(tmpctx, struct amount_msat, &msat));
|
|
||||||
|
|
||||||
if (failcode) {
|
|
||||||
fail = immediate_routing_failure(cmd, ld,
|
|
||||||
failcode,
|
|
||||||
&route[0].channel_id,
|
|
||||||
&channel->peer->id);
|
|
||||||
|
|
||||||
return sendpay_fail(cmd, payment, PAY_TRY_OTHER_ROUTE,
|
|
||||||
NULL, fail, "First peer not ready");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy channels used along the route. */
|
/* Copy channels used along the route. */
|
||||||
channels = tal_arr(tmpctx, struct short_channel_id, n_hops);
|
channels = tal_arr(tmpctx, struct short_channel_id, n_hops);
|
||||||
for (i = 0; i < n_hops; ++i)
|
for (i = 0; i < n_hops; ++i)
|
||||||
channels[i] = route[i].channel_id;
|
channels[i] = route[i].channel_id;
|
||||||
|
|
||||||
/* If we're retrying, delete all trace of previous one. We delete
|
log_info(ld->log, "Sending %s over %zu hops to deliver %s",
|
||||||
* outgoing HTLC, too, otherwise it gets reported to onchaind as
|
type_to_string(tmpctx, struct amount_msat, &route[0].amount),
|
||||||
* a possibility, and we end up in handle_missing_htlc_output->
|
n_hops, type_to_string(tmpctx, struct amount_msat, &msat));
|
||||||
* onchain_failed_our_htlc->payment_failed with no payment.
|
packet = create_onionpacket(tmpctx, path, &path_secrets);
|
||||||
*/
|
return send_payment_core(ld, cmd, rhash, partid, &route[0],
|
||||||
if (payment) {
|
msat, total_msat, label, b11str,
|
||||||
wallet_payment_delete(ld->wallet, rhash, payment->partid);
|
packet, &ids[n_hops - 1], ids,
|
||||||
wallet_local_htlc_out_delete(ld->wallet, channel, rhash,
|
channels, path_secrets);
|
||||||
payment->partid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If hout fails, payment should be freed too. */
|
|
||||||
payment = tal(hout, struct wallet_payment);
|
|
||||||
payment->id = 0;
|
|
||||||
payment->payment_hash = *rhash;
|
|
||||||
payment->partid = partid;
|
|
||||||
payment->destination = tal_dup(payment, struct node_id, &ids[n_hops - 1]);
|
|
||||||
payment->status = PAYMENT_PENDING;
|
|
||||||
payment->msatoshi = msat;
|
|
||||||
payment->msatoshi_sent = route[0].amount;
|
|
||||||
payment->total_msat = total_msat;
|
|
||||||
payment->timestamp = time_now().ts.tv_sec;
|
|
||||||
payment->payment_preimage = NULL;
|
|
||||||
payment->path_secrets = tal_steal(payment, path_secrets);
|
|
||||||
payment->route_nodes = tal_steal(payment, ids);
|
|
||||||
payment->route_channels = tal_steal(payment, channels);
|
|
||||||
payment->failonion = NULL;
|
|
||||||
if (label != NULL)
|
|
||||||
payment->label = tal_strdup(payment, label);
|
|
||||||
else
|
|
||||||
payment->label = NULL;
|
|
||||||
if (b11str != NULL)
|
|
||||||
payment->bolt11 = tal_strdup(payment, b11str);
|
|
||||||
else
|
|
||||||
payment->bolt11 = NULL;
|
|
||||||
|
|
||||||
/* We write this into db when HTLC is actually sent. */
|
|
||||||
wallet_payment_setup(ld->wallet, payment);
|
|
||||||
|
|
||||||
add_sendpay_waiter(ld, cmd, rhash);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command_result *
|
static struct command_result *
|
||||||
@@ -991,12 +1023,9 @@ static struct command_result *json_sendonion(struct command *cmd,
|
|||||||
u8 *onion;
|
u8 *onion;
|
||||||
struct onionpacket packet;
|
struct onionpacket packet;
|
||||||
enum onion_type failcode;
|
enum onion_type failcode;
|
||||||
struct htlc_out *hout;
|
|
||||||
struct route_hop *first_hop;
|
struct route_hop *first_hop;
|
||||||
struct sha256 *payment_hash;
|
struct sha256 *payment_hash;
|
||||||
struct channel *channel;
|
|
||||||
struct lightningd *ld = cmd->ld;
|
struct lightningd *ld = cmd->ld;
|
||||||
struct wallet_payment *payment;
|
|
||||||
const char *label;
|
const char *label;
|
||||||
struct secret *path_secrets;
|
struct secret *path_secrets;
|
||||||
|
|
||||||
@@ -1017,74 +1046,12 @@ static struct command_result *json_sendonion(struct command *cmd,
|
|||||||
"with failcode=%d",
|
"with failcode=%d",
|
||||||
failcode);
|
failcode);
|
||||||
|
|
||||||
/* Now, do we already have a payment? */
|
return send_payment_core(ld, cmd, payment_hash, /* FIXME: Set partid! */0,
|
||||||
payment = wallet_payment_by_hash(tmpctx, ld->wallet, payment_hash, /* FIXME: Set partid! */0);
|
first_hop, AMOUNT_MSAT(0), AMOUNT_MSAT(0),
|
||||||
if (payment) {
|
label, NULL, &packet, NULL, NULL, NULL,
|
||||||
if (payment->status == PAYMENT_PENDING) {
|
path_secrets);
|
||||||
log_debug(ld->log, "send_payment: previous still in progress");
|
|
||||||
return json_sendpay_in_progress(cmd, payment);
|
|
||||||
}
|
|
||||||
if (payment->status == PAYMENT_COMPLETE) {
|
|
||||||
log_debug(ld->log, "send_payment: previous succeeded");
|
|
||||||
return sendpay_success(cmd, payment);
|
|
||||||
}
|
|
||||||
log_debug(ld->log, "send_payment: found previous, retrying");
|
|
||||||
}
|
|
||||||
|
|
||||||
channel = active_channel_by_id(ld, &first_hop->nodeid, NULL);
|
|
||||||
if (!channel) {
|
|
||||||
struct json_stream *data
|
|
||||||
= json_stream_fail(cmd, PAY_TRY_OTHER_ROUTE,
|
|
||||||
"No connection to first "
|
|
||||||
"peer found");
|
|
||||||
|
|
||||||
json_add_routefail_info(data, 0, WIRE_UNKNOWN_NEXT_PEER,
|
|
||||||
&ld->id, &first_hop->channel_id,
|
|
||||||
node_id_idx(&ld->id, &first_hop->nodeid),
|
|
||||||
NULL);
|
|
||||||
json_object_end(data);
|
|
||||||
return command_failed(cmd, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cleanup any prior payment. We're about to retry. */
|
|
||||||
if (payment) {
|
|
||||||
wallet_payment_delete(ld->wallet, payment_hash, /* FIXME: Set partid! */0);
|
|
||||||
wallet_local_htlc_out_delete(ld->wallet, channel, payment_hash, /* FIXME: Set partid! */0);
|
|
||||||
}
|
|
||||||
|
|
||||||
failcode = send_onion(cmd->ld, &packet, first_hop, payment_hash, /* FIXME: Set partid! */0, channel,
|
|
||||||
&hout);
|
|
||||||
|
|
||||||
payment = tal(hout, struct wallet_payment);
|
|
||||||
payment->id = 0;
|
|
||||||
payment->payment_hash = *payment_hash;
|
|
||||||
payment->status = PAYMENT_PENDING;
|
|
||||||
payment->msatoshi = AMOUNT_MSAT(0);
|
|
||||||
payment->msatoshi_sent = first_hop->amount;
|
|
||||||
payment->timestamp = time_now().ts.tv_sec;
|
|
||||||
|
|
||||||
/* These are not available for sendonion payments since the onion is
|
|
||||||
* opaque and we can't extract them. Errors have to be handled
|
|
||||||
* externally, since we can't decrypt them.*/
|
|
||||||
payment->destination = NULL;
|
|
||||||
payment->payment_preimage = NULL;
|
|
||||||
payment->route_nodes = NULL;
|
|
||||||
payment->route_channels = NULL;
|
|
||||||
payment->bolt11 = NULL;
|
|
||||||
payment->failonion = NULL;
|
|
||||||
payment->path_secrets = tal_steal(payment, path_secrets);
|
|
||||||
|
|
||||||
if (label != NULL)
|
|
||||||
payment->label = tal_strdup(payment, label);
|
|
||||||
else
|
|
||||||
payment->label = NULL;
|
|
||||||
|
|
||||||
/* We write this into db when HTLC is actually sent. */
|
|
||||||
wallet_payment_setup(ld->wallet, payment);
|
|
||||||
|
|
||||||
add_sendpay_waiter(ld, cmd, payment_hash);
|
|
||||||
return command_still_pending(cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct json_command sendonion_command = {
|
static const struct json_command sendonion_command = {
|
||||||
"sendonion",
|
"sendonion",
|
||||||
"payment",
|
"payment",
|
||||||
@@ -1130,7 +1097,6 @@ static struct command_result *json_sendpay(struct command *cmd,
|
|||||||
struct route_hop *route;
|
struct route_hop *route;
|
||||||
struct amount_msat *msat;
|
struct amount_msat *msat;
|
||||||
const char *b11str, *label = NULL;
|
const char *b11str, *label = NULL;
|
||||||
struct command_result *res;
|
|
||||||
struct secret *payment_secret;
|
struct secret *payment_secret;
|
||||||
|
|
||||||
/* For generating help, give new-style. */
|
/* For generating help, give new-style. */
|
||||||
@@ -1267,15 +1233,12 @@ static struct command_result *json_sendpay(struct command *cmd,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
res = send_payment(cmd->ld, cmd, rhash, /* FIXME: Set partid! */ 0,
|
return send_payment(cmd->ld, cmd, rhash, /* FIXME: Set partid! */ 0,
|
||||||
route,
|
route,
|
||||||
msat ? *msat : route[routetok->size-1].amount,
|
msat ? *msat : route[routetok->size-1].amount,
|
||||||
/* FIXME: Set total_msat! */
|
/* FIXME: Set total_msat! */
|
||||||
msat ? *msat : route[routetok->size-1].amount,
|
msat ? *msat : route[routetok->size-1].amount,
|
||||||
label, b11str, payment_secret);
|
label, b11str, payment_secret);
|
||||||
if (res)
|
|
||||||
return res;
|
|
||||||
return command_still_pending(cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct json_command sendpay_command = {
|
static const struct json_command sendpay_command = {
|
||||||
|
|||||||
Reference in New Issue
Block a user