Browse Source

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>
travis-debug
Rusty Russell 5 years ago
committed by Christian Decker
parent
commit
618c390475
  1. 287
      lightningd/pay.c

287
lightningd/pay.c

@ -715,84 +715,29 @@ static enum onion_type send_onion(struct lightningd *ld,
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(struct lightningd *ld,
send_payment_core(struct lightningd *ld,
struct command *cmd,
const struct sha256 *rhash,
u64 partid,
const struct route_hop *route,
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 secret *payment_secret)
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)
{
unsigned int base_expiry;
struct onionpacket *packet;
struct secret *path_secrets;
struct wallet_payment *payment;
struct channel *channel;
enum onion_type failcode;
size_t i, n_hops = tal_count(route);
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 routing_failure *fail;
struct channel *channel;
struct sphinx_path *path;
struct pubkey pubkey;
bool final_tlv, ret;
u8 *onion;
/* Expiry for HTLCs is absolute. And add one to give some margin. */
base_expiry = get_block_height(ld->topology) + 1;
path = sphinx_path_new(tmpctx, rhash->u.u8);
/* Extract IDs for each hop: create_onionpacket wants array. */
for (i = 0; i < n_hops; i++)
ids[i] = route[i].nodeid;
/* Create sphinx path */
for (i = 0; i < n_hops - 1; i++) {
ret = pubkey_from_node_id(&pubkey, &ids[i]);
assert(ret);
sphinx_add_hop(path, &pubkey,
take(onion_nonfinal_hop(NULL,
should_use_tlv(route[i].style),
&route[i + 1].channel_id,
route[i + 1].amount,
base_expiry + route[i + 1].delay)));
}
/* And finally set the final hop to the special values in
* BOLT04 */
ret = pubkey_from_node_id(&pubkey, &ids[i]);
assert(ret);
final_tlv = should_use_tlv(route[i].style);
/* BOLT-3a09bc54f8443c4757b47541a5310aff6377ee21 #4:
* - Unless `node_announcement`, `init` message or the
* [BOLT #11](11-payment-encoding.md#tagged-fields) offers feature
* `var_onion_optin`:
* - MUST use the legacy payload format instead.
*/
/* In our case, we don't use it unless we also have a payment_secret;
* everyone should support this eventually */
if (!final_tlv && payment_secret)
final_tlv = true;
onion = onion_final_hop(cmd,
final_tlv,
route[i].amount,
base_expiry + route[i].delay,
route[i].amount, payment_secret);
if (!onion) {
return command_fail(cmd, PAY_DESTINATION_PERM_FAIL,
"Destination does not support"
" payment_secret");
}
sphinx_add_hop(path, &pubkey, onion);
/* Now, do we already have a payment? */
payment = wallet_payment_by_hash(tmpctx, ld->wallet, rhash, partid);
@ -813,9 +758,8 @@ send_payment(struct lightningd *ld,
struct amount_msat,
&payment->msatoshi));
}
if (payment->destination &&
!node_id_eq(payment->destination,
&ids[n_hops - 1])) {
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,
@ -827,7 +771,7 @@ send_payment(struct lightningd *ld,
log_debug(ld->log, "send_payment: found previous, retrying");
}
channel = active_channel_by_id(ld, &ids[0], NULL);
channel = active_channel_by_id(ld, &first_hop->nodeid, NULL);
if (!channel) {
struct json_stream *data
= json_stream_fail(cmd, PAY_TRY_OTHER_ROUTE,
@ -835,35 +779,26 @@ send_payment(struct lightningd *ld,
"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),
&ld->id, &first_hop->channel_id,
node_id_idx(&ld->id, &first_hop->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,
failcode = send_onion(ld, packet, first_hop, 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,
&first_hop->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. */
channels = tal_arr(tmpctx, struct short_channel_id, n_hops);
for (i = 0; i < n_hops; ++i)
channels[i] = route[i].channel_id;
/* 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->
@ -880,16 +815,25 @@ send_payment(struct lightningd *ld,
payment->id = 0;
payment->payment_hash = *rhash;
payment->partid = partid;
payment->destination = tal_dup(payment, struct node_id, &ids[n_hops - 1]);
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 = route[0].amount;
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);
payment->route_nodes = tal_steal(payment, ids);
payment->route_channels = tal_steal(payment, channels);
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);
@ -904,7 +848,95 @@ send_payment(struct lightningd *ld,
wallet_payment_setup(ld->wallet, payment);
add_sendpay_waiter(ld, cmd, rhash);
return NULL;
return command_still_pending(cmd);
}
static struct command_result *
send_payment(struct lightningd *ld,
struct command *cmd,
const struct sha256 *rhash,
u64 partid,
const struct route_hop *route,
struct amount_msat msat,
struct amount_msat total_msat,
const char *label TAKES,
const char *b11str TAKES,
const struct secret *payment_secret)
{
unsigned int base_expiry;
struct onionpacket *packet;
struct secret *path_secrets;
size_t i, n_hops = tal_count(route);
struct node_id *ids = tal_arr(tmpctx, struct node_id, n_hops);
struct short_channel_id *channels;
struct sphinx_path *path;
struct pubkey pubkey;
bool final_tlv, ret;
u8 *onion;
/* Expiry for HTLCs is absolute. And add one to give some margin. */
base_expiry = get_block_height(ld->topology) + 1;
path = sphinx_path_new(tmpctx, rhash->u.u8);
/* Extract IDs for each hop: create_onionpacket wants array. */
for (i = 0; i < n_hops; i++)
ids[i] = route[i].nodeid;
/* Create sphinx path */
for (i = 0; i < n_hops - 1; i++) {
ret = pubkey_from_node_id(&pubkey, &ids[i]);
assert(ret);
sphinx_add_hop(path, &pubkey,
take(onion_nonfinal_hop(NULL,
should_use_tlv(route[i].style),
&route[i + 1].channel_id,
route[i + 1].amount,
base_expiry + route[i + 1].delay)));
}
/* And finally set the final hop to the special values in
* BOLT04 */
ret = pubkey_from_node_id(&pubkey, &ids[i]);
assert(ret);
final_tlv = should_use_tlv(route[i].style);
/* BOLT-3a09bc54f8443c4757b47541a5310aff6377ee21 #4:
* - Unless `node_announcement`, `init` message or the
* [BOLT #11](11-payment-encoding.md#tagged-fields) offers feature
* `var_onion_optin`:
* - MUST use the legacy payload format instead.
*/
/* In our case, we don't use it unless we also have a payment_secret;
* everyone should support this eventually */
if (!final_tlv && payment_secret)
final_tlv = true;
onion = onion_final_hop(cmd,
final_tlv,
route[i].amount,
base_expiry + route[i].delay,
route[i].amount, payment_secret);
if (!onion) {
return command_fail(cmd, PAY_DESTINATION_PERM_FAIL,
"Destination does not support"
" payment_secret");
}
sphinx_add_hop(path, &pubkey, onion);
/* Copy channels used along the route. */
channels = tal_arr(tmpctx, struct short_channel_id, n_hops);
for (i = 0; i < n_hops; ++i)
channels[i] = route[i].channel_id;
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));
packet = create_onionpacket(tmpctx, path, &path_secrets);
return send_payment_core(ld, cmd, rhash, partid, &route[0],
msat, total_msat, label, b11str,
packet, &ids[n_hops - 1], ids,
channels, path_secrets);
}
static struct command_result *
@ -991,12 +1023,9 @@ static struct command_result *json_sendonion(struct command *cmd,
u8 *onion;
struct onionpacket packet;
enum onion_type failcode;
struct htlc_out *hout;
struct route_hop *first_hop;
struct sha256 *payment_hash;
struct channel *channel;
struct lightningd *ld = cmd->ld;
struct wallet_payment *payment;
const char *label;
struct secret *path_secrets;
@ -1017,74 +1046,12 @@ static struct command_result *json_sendonion(struct command *cmd,
"with failcode=%d",
failcode);
/* Now, do we already have a payment? */
payment = wallet_payment_by_hash(tmpctx, ld->wallet, payment_hash, /* FIXME: Set partid! */0);
if (payment) {
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");
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);
return send_payment_core(ld, cmd, payment_hash, /* FIXME: Set partid! */0,
first_hop, AMOUNT_MSAT(0), AMOUNT_MSAT(0),
label, NULL, &packet, NULL, NULL, NULL,
path_secrets);
}
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 = {
"sendonion",
"payment",
@ -1130,7 +1097,6 @@ static struct command_result *json_sendpay(struct command *cmd,
struct route_hop *route;
struct amount_msat *msat;
const char *b11str, *label = NULL;
struct command_result *res;
struct secret *payment_secret;
/* For generating help, give new-style. */
@ -1267,15 +1233,12 @@ static struct command_result *json_sendpay(struct command *cmd,
}
#endif
res = send_payment(cmd->ld, cmd, rhash, /* FIXME: Set partid! */ 0,
return send_payment(cmd->ld, cmd, rhash, /* FIXME: Set partid! */ 0,
route,
msat ? *msat : route[routetok->size-1].amount,
/* FIXME: Set total_msat! */
msat ? *msat : route[routetok->size-1].amount,
label, b11str, payment_secret);
if (res)
return res;
return command_still_pending(cmd);
}
static const struct json_command sendpay_command = {

Loading…
Cancel
Save