From 79443d6f94c1db01f69b297b01eca44ebaec4d12 Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Thu, 23 Nov 2017 21:54:19 +0100 Subject: [PATCH] htlc: Defer saving the outgoing payment until we store the HTLC This addresses a performance regression introduced by 6ceb375650af30682027cdc22e6d029b4382f423. We were storing it in an otherwise empty DB transaction, which means that DB transaction was no longer a no-op. Now we defer storing until we need to store the corresponding HTLC anyway, so we can just piggyback on top of that transaction. This is also more consistent since we'd be forgetting the payment anyway if we restart between adding the HTLC and committing to it. Signed-off-by: Christian Decker --- lightningd/htlc_end.c | 4 +++- lightningd/htlc_end.h | 6 +++++- lightningd/pay.c | 31 ++++++++++++------------------- lightningd/peer_htlcs.c | 21 ++++++++++++++++++--- lightningd/peer_htlcs.h | 1 + 5 files changed, 39 insertions(+), 24 deletions(-) diff --git a/lightningd/htlc_end.c b/lightningd/htlc_end.c index c38068ea1..459525428 100644 --- a/lightningd/htlc_end.c +++ b/lightningd/htlc_end.c @@ -138,7 +138,8 @@ struct htlc_out *new_htlc_out(const tal_t *ctx, const struct sha256 *payment_hash, const u8 *onion_routing_packet, struct htlc_in *in, - struct pay_command *pc) + struct pay_command *pc, + struct wallet_payment *payment) { struct htlc_out *hout = tal(ctx, struct htlc_out); @@ -149,6 +150,7 @@ struct htlc_out *new_htlc_out(const tal_t *ctx, hout->msatoshi = msatoshi; hout->cltv_expiry = cltv_expiry; hout->payment_hash = *payment_hash; + hout->payment = payment; memcpy(hout->onion_routing_packet, onion_routing_packet, sizeof(hout->onion_routing_packet)); diff --git a/lightningd/htlc_end.h b/lightningd/htlc_end.h index 9a502d2cc..d3e758785 100644 --- a/lightningd/htlc_end.h +++ b/lightningd/htlc_end.h @@ -72,6 +72,9 @@ struct htlc_out { /* Otherwise, payment command which created it. */ struct pay_command *pay_command; + + /* Temporary payment store, so we can save everything in one go */ + struct wallet_payment *payment; }; static inline const struct htlc_key *keyof_htlc_in(const struct htlc_in *in) @@ -127,7 +130,8 @@ struct htlc_out *new_htlc_out(const tal_t *ctx, const struct sha256 *payment_hash, const u8 *onion_routing_packet, struct htlc_in *in, - struct pay_command *pc); + struct pay_command *pc, + struct wallet_payment *payment); void connect_htlc_in(struct htlc_in_map *map, struct htlc_in *hin); void connect_htlc_out(struct htlc_out_map *map, struct htlc_out *hout); diff --git a/lightningd/pay.c b/lightningd/pay.c index da065479e..6e9372e17 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -165,7 +165,7 @@ static void send_payment(struct command *cmd, size_t i, n_hops = tal_count(route); struct hop_data *hop_data = tal_arr(cmd, struct hop_data, n_hops); struct pubkey *ids = tal_arr(cmd, struct pubkey, n_hops); - struct wallet_payment payment; + struct wallet_payment *payment = NULL; /* Expiry for HTLCs is absolute. And add one to give some margin. */ base_expiry = get_block_height(cmd->ld->topology) + 1; @@ -223,23 +223,6 @@ static void send_payment(struct command *cmd, log_add(cmd->ld->log, "... retrying"); } - /* If this is a new payment, then store the payment so we can - * later show it in the history */ - if (!pc) { - payment.id = 0; - payment.incoming = false; - payment.payment_hash = *rhash; - payment.destination = &ids[n_hops - 1]; - payment.status = PAYMENT_PENDING; - payment.msatoshi = route[n_hops-1].amount; - payment.timestamp = time_now().ts.tv_sec; - - if (!wallet_payment_add(cmd->ld->wallet, &payment)) { - command_fail(cmd, "Unable to record payment in the database."); - return; - } - } - peer = peer_by_id(cmd->ld, &ids[0]); if (!peer) { command_fail(cmd, "no connection to first peer found"); @@ -259,6 +242,15 @@ static void send_payment(struct command *cmd, pc = tal(cmd->ld, struct pay_command); list_add_tail(&cmd->ld->pay_commands, &pc->list); tal_add_destructor(pc, pay_command_destroyed); + + payment = tal(pc, struct wallet_payment); + payment->id = 0; + payment->incoming = false; + payment->payment_hash = *rhash; + payment->destination = &ids[n_hops - 1]; + payment->status = PAYMENT_PENDING; + payment->msatoshi = route[n_hops-1].amount; + payment->timestamp = time_now().ts.tv_sec; } pc->cmd = cmd; pc->rhash = *rhash; @@ -280,7 +272,8 @@ static void send_payment(struct command *cmd, failcode = send_htlc_out(peer, route[0].amount, base_expiry + route[0].delay, - rhash, onion, NULL, pc, &pc->out); + rhash, onion, NULL, payment, pc, + &pc->out); if (failcode) { command_fail(cmd, "first peer not ready: %s", onion_type_name(failcode)); diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index 2350d5183..cdc816ef7 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -447,6 +447,7 @@ enum onion_type send_htlc_out(struct peer *out, u64 amount, u32 cltv, const struct sha256 *payment_hash, const u8 *onion_routing_packet, struct htlc_in *in, + struct wallet_payment *payment, struct pay_command *pc, struct htlc_out **houtp) { @@ -467,7 +468,8 @@ enum onion_type send_htlc_out(struct peer *out, u64 amount, u32 cltv, /* Make peer's daemon own it, catch if it dies. */ hout = new_htlc_out(out->owner, out, amount, cltv, - payment_hash, onion_routing_packet, in, pc); + payment_hash, onion_routing_packet, in, + pc, payment); tal_add_destructor(hout, hout_subd_died); msg = towire_channel_offer_htlc(out, amount, cltv, payment_hash, @@ -558,7 +560,7 @@ static void forward_htlc(struct htlc_in *hin, failcode = send_htlc_out(next, amt_to_forward, outgoing_cltv_value, &hin->payment_hash, - next_onion, hin, NULL, NULL); + next_onion, hin, NULL, NULL, NULL); if (!failcode) return; @@ -927,8 +929,21 @@ static bool update_out_htlc(struct peer *peer, u64 id, enum htlc_state newstate) return false; } - if (!hout->dbid) + if (!hout->dbid) { wallet_htlc_save_out(peer->ld->wallet, peer->channel, hout); + } + + /* We only have a payment if we initiated the payment. */ + if (hout->payment) { + /* Now that we are committed, and inside the + * transaction context of the update, add the payment + * to the history. */ + wallet_payment_add(peer->ld->wallet, hout->payment); + + /* No need to carry the payment info around anymore, + * we'll update in the database directly */ + hout->payment = tal_free(hout->payment); + } if (!htlc_out_update_state(peer, hout, newstate)) return false; diff --git a/lightningd/peer_htlcs.h b/lightningd/peer_htlcs.h index c5ea41a44..79828e0af 100644 --- a/lightningd/peer_htlcs.h +++ b/lightningd/peer_htlcs.h @@ -39,6 +39,7 @@ enum onion_type send_htlc_out(struct peer *out, u64 amount, u32 cltv, const struct sha256 *payment_hash, const u8 *onion_routing_packet, struct htlc_in *in, + struct wallet_payment *payment, struct pay_command *pc, struct htlc_out **houtp);