From 618c39047526ebf2ed1cb0d1e6f78ea6a9f55bad Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 12 Dec 2019 10:20:22 +1030 Subject: [PATCH] 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 --- lightningd/pay.c | 313 +++++++++++++++++++++-------------------------- 1 file changed, 138 insertions(+), 175 deletions(-) diff --git a/lightningd/pay.c b/lightningd/pay.c index 809b2a3de..8c4859977 100644 --- a/lightningd/pay.c +++ b/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, - 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) +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) { - 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); - } - - 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); + 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); } + 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, - 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); + 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); } static const struct json_command sendpay_command = {