mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 22:45:27 +01:00
htlcs: remove origin_htlc_id from htlc_out.
This is a transient field, so rework things so we don't leave it in struct htlc_out. Instead, load htlc_in first and connect htlc_out to them as we go. This also changes one place where we use it instead of the am_origin flag. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
345ca9b122
commit
12985331f7
11 changed files with 170 additions and 148 deletions
|
@ -28,6 +28,22 @@ struct htlc_in *find_htlc_in(const struct htlc_in_map *map,
|
||||||
return htlc_in_map_get(map, &key);
|
return htlc_in_map_get(map, &key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct htlc_in *remove_htlc_in_by_dbid(struct htlc_in_map *remaining_htlcs_in,
|
||||||
|
u64 dbid)
|
||||||
|
{
|
||||||
|
struct htlc_in *hin;
|
||||||
|
struct htlc_in_map_iter ini;
|
||||||
|
|
||||||
|
for (hin = htlc_in_map_first(remaining_htlcs_in, &ini); hin;
|
||||||
|
hin = htlc_in_map_next(remaining_htlcs_in, &ini)) {
|
||||||
|
if (hin->dbid == dbid) {
|
||||||
|
htlc_in_map_del(remaining_htlcs_in, hin);
|
||||||
|
return hin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void destroy_htlc_in(struct htlc_in *hend, struct htlc_in_map *map)
|
static void destroy_htlc_in(struct htlc_in *hend, struct htlc_in_map *map)
|
||||||
{
|
{
|
||||||
htlc_in_map_del(map, hend);
|
htlc_in_map_del(map, hend);
|
||||||
|
|
|
@ -58,7 +58,6 @@ struct htlc_out {
|
||||||
* is saved to the database, must be >0 after saving to the
|
* is saved to the database, must be >0 after saving to the
|
||||||
* database. */
|
* database. */
|
||||||
u64 dbid;
|
u64 dbid;
|
||||||
u64 origin_htlc_id;
|
|
||||||
struct htlc_key key;
|
struct htlc_key key;
|
||||||
struct amount_msat msat;
|
struct amount_msat msat;
|
||||||
u32 cltv_expiry;
|
u32 cltv_expiry;
|
||||||
|
@ -123,6 +122,10 @@ struct htlc_in *find_htlc_in(const struct htlc_in_map *map,
|
||||||
const struct channel *channel,
|
const struct channel *channel,
|
||||||
u64 htlc_id);
|
u64 htlc_id);
|
||||||
|
|
||||||
|
/* FIXME: Slow function only used at startup. */
|
||||||
|
struct htlc_in *remove_htlc_in_by_dbid(struct htlc_in_map *remaining_htlcs_in,
|
||||||
|
u64 dbid);
|
||||||
|
|
||||||
struct htlc_out *find_htlc_out(const struct htlc_out_map *map,
|
struct htlc_out *find_htlc_out(const struct htlc_out_map *map,
|
||||||
const struct channel *channel,
|
const struct channel *channel,
|
||||||
u64 htlc_id);
|
u64 htlc_id);
|
||||||
|
|
|
@ -630,7 +630,7 @@ int main(int argc, char *argv[])
|
||||||
int stop_fd;
|
int stop_fd;
|
||||||
struct timers *timers;
|
struct timers *timers;
|
||||||
const char *stop_response;
|
const char *stop_response;
|
||||||
struct htlc_in_map *unprocessed_htlcs;
|
struct htlc_in_map *unconnected_htlcs_in;
|
||||||
struct rlimit nofile = {1024, 1024};
|
struct rlimit nofile = {1024, 1024};
|
||||||
|
|
||||||
/*~ Make sure that we limit ourselves to something reasonable. Modesty
|
/*~ Make sure that we limit ourselves to something reasonable. Modesty
|
||||||
|
@ -778,7 +778,7 @@ int main(int argc, char *argv[])
|
||||||
* topology is initialized since some decisions rely on being able to
|
* topology is initialized since some decisions rely on being able to
|
||||||
* know the blockheight. */
|
* know the blockheight. */
|
||||||
db_begin_transaction(ld->wallet->db);
|
db_begin_transaction(ld->wallet->db);
|
||||||
unprocessed_htlcs = load_channels_from_wallet(ld);
|
unconnected_htlcs_in = load_channels_from_wallet(ld);
|
||||||
db_commit_transaction(ld->wallet->db);
|
db_commit_transaction(ld->wallet->db);
|
||||||
|
|
||||||
/*~ Create RPC socket: now lightning-cli can send us JSON RPC commands
|
/*~ Create RPC socket: now lightning-cli can send us JSON RPC commands
|
||||||
|
@ -792,7 +792,7 @@ int main(int argc, char *argv[])
|
||||||
/*~ Process any HTLCs we were in the middle of when we exited, now
|
/*~ Process any HTLCs we were in the middle of when we exited, now
|
||||||
* that plugins (who might want to know via htlc_accepted hook) are
|
* that plugins (who might want to know via htlc_accepted hook) are
|
||||||
* active. */
|
* active. */
|
||||||
htlcs_resubmit(ld, unprocessed_htlcs);
|
htlcs_resubmit(ld, unconnected_htlcs_in);
|
||||||
|
|
||||||
/*~ Activate connect daemon. Needs to be after the initialization of
|
/*~ Activate connect daemon. Needs to be after the initialization of
|
||||||
* chaintopology, otherwise peers may connect and ask for
|
* chaintopology, otherwise peers may connect and ask for
|
||||||
|
|
|
@ -1579,27 +1579,47 @@ void activate_peers(struct lightningd *ld)
|
||||||
struct htlc_in_map *load_channels_from_wallet(struct lightningd *ld)
|
struct htlc_in_map *load_channels_from_wallet(struct lightningd *ld)
|
||||||
{
|
{
|
||||||
struct peer *peer;
|
struct peer *peer;
|
||||||
|
struct htlc_in_map *unconnected_htlcs_in = tal(ld, struct htlc_in_map);
|
||||||
|
|
||||||
/* Load channels from database */
|
/* Load channels from database */
|
||||||
if (!wallet_init_channels(ld->wallet))
|
if (!wallet_init_channels(ld->wallet))
|
||||||
fatal("Could not load channels from the database");
|
fatal("Could not load channels from the database");
|
||||||
|
|
||||||
/* This is a poor-man's db join :( */
|
/* First we load the incoming htlcs */
|
||||||
list_for_each(&ld->peers, peer, list) {
|
list_for_each(&ld->peers, peer, list) {
|
||||||
struct channel *channel;
|
struct channel *channel;
|
||||||
|
|
||||||
list_for_each(&peer->channels, channel, list) {
|
list_for_each(&peer->channels, channel, list) {
|
||||||
if (!wallet_htlcs_load_for_channel(ld->wallet,
|
if (!wallet_htlcs_load_in_for_channel(ld->wallet,
|
||||||
channel,
|
channel,
|
||||||
&ld->htlcs_in,
|
&ld->htlcs_in)) {
|
||||||
&ld->htlcs_out)) {
|
|
||||||
fatal("could not load htlcs for channel");
|
fatal("could not load htlcs for channel");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now connect HTLC pointers together */
|
/* Make a copy of the htlc_map: entries removed as they're matched */
|
||||||
return htlcs_reconnect(ld, &ld->htlcs_in, &ld->htlcs_out);
|
htlc_in_map_copy(unconnected_htlcs_in, &ld->htlcs_in);
|
||||||
|
|
||||||
|
/* Now we load the outgoing HTLCs, so we can connect them. */
|
||||||
|
list_for_each(&ld->peers, peer, list) {
|
||||||
|
struct channel *channel;
|
||||||
|
|
||||||
|
list_for_each(&peer->channels, channel, list) {
|
||||||
|
if (!wallet_htlcs_load_out_for_channel(ld->wallet,
|
||||||
|
channel,
|
||||||
|
&ld->htlcs_out,
|
||||||
|
unconnected_htlcs_in)) {
|
||||||
|
fatal("could not load outgoing htlcs for channel");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef COMPAT_V061
|
||||||
|
fixup_htlcs_out(ld);
|
||||||
|
#endif /* COMPAT_V061 */
|
||||||
|
|
||||||
|
return unconnected_htlcs_in;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command_result *json_disconnect(struct command *cmd,
|
static struct command_result *json_disconnect(struct command *cmd,
|
||||||
|
|
|
@ -1274,7 +1274,7 @@ static bool update_out_htlc(struct channel *channel,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For our own HTLCs, we commit payment to db lazily */
|
/* For our own HTLCs, we commit payment to db lazily */
|
||||||
if (hout->origin_htlc_id == 0)
|
if (hout->am_origin)
|
||||||
payment_store(ld,
|
payment_store(ld,
|
||||||
&hout->payment_hash, hout->partid);
|
&hout->payment_hash, hout->partid);
|
||||||
}
|
}
|
||||||
|
@ -2089,94 +2089,35 @@ static void fixup_hout(struct lightningd *ld, struct htlc_out *hout)
|
||||||
&hout->key.channel->peer->id),
|
&hout->key.channel->peer->id),
|
||||||
fix);
|
fix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fixup_htlcs_out(struct lightningd *ld)
|
||||||
|
{
|
||||||
|
struct htlc_out_map_iter outi;
|
||||||
|
struct htlc_out *hout;
|
||||||
|
|
||||||
|
for (hout = htlc_out_map_first(&ld->htlcs_out, &outi);
|
||||||
|
hout;
|
||||||
|
hout = htlc_out_map_next(&ld->htlcs_out, &outi)) {
|
||||||
|
if (!hout->am_origin)
|
||||||
|
fixup_hout(ld, hout);
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif /* COMPAT_V061 */
|
#endif /* COMPAT_V061 */
|
||||||
|
|
||||||
/**
|
void htlcs_resubmit(struct lightningd *ld,
|
||||||
* htlcs_reconnect -- Link outgoing HTLCs to their origins after initial db load
|
struct htlc_in_map *unconnected_htlcs_in)
|
||||||
*
|
|
||||||
* For each outgoing HTLC find the incoming HTLC that triggered it. If
|
|
||||||
* we are the origin of the transfer then we cannot resolve the
|
|
||||||
* incoming HTLC in which case we just leave it `NULL`.
|
|
||||||
*
|
|
||||||
* Returns a map of any htlcs we need to retry.
|
|
||||||
*/
|
|
||||||
struct htlc_in_map *htlcs_reconnect(struct lightningd *ld,
|
|
||||||
struct htlc_in_map *htlcs_in,
|
|
||||||
struct htlc_out_map *htlcs_out)
|
|
||||||
{
|
|
||||||
struct htlc_in_map_iter ini;
|
|
||||||
struct htlc_out_map_iter outi;
|
|
||||||
struct htlc_in *hin;
|
|
||||||
struct htlc_out *hout;
|
|
||||||
struct htlc_in_map *unprocessed = tal(NULL, struct htlc_in_map);
|
|
||||||
|
|
||||||
/* Any HTLCs which happened to be incoming and weren't forwarded before
|
|
||||||
* we shutdown/crashed: fail them now.
|
|
||||||
*
|
|
||||||
* Note that since we do local processing synchronously, so this never
|
|
||||||
* captures local payments. But if it did, it would be a tiny corner
|
|
||||||
* case. */
|
|
||||||
htlc_in_map_init(unprocessed);
|
|
||||||
for (hin = htlc_in_map_first(htlcs_in, &ini); hin;
|
|
||||||
hin = htlc_in_map_next(htlcs_in, &ini)) {
|
|
||||||
if (hin->hstate == RCVD_ADD_ACK_REVOCATION)
|
|
||||||
htlc_in_map_add(unprocessed, hin);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (hout = htlc_out_map_first(htlcs_out, &outi); hout;
|
|
||||||
hout = htlc_out_map_next(htlcs_out, &outi)) {
|
|
||||||
|
|
||||||
if (hout->am_origin) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For fulfilled HTLCs, we fulfill incoming before outgoing is
|
|
||||||
* completely resolved, so it's possible that we don't find
|
|
||||||
* the incoming. */
|
|
||||||
for (hin = htlc_in_map_first(htlcs_in, &ini); hin;
|
|
||||||
hin = htlc_in_map_next(htlcs_in, &ini)) {
|
|
||||||
if (hout->origin_htlc_id == hin->dbid) {
|
|
||||||
log_debug(ld->log,
|
|
||||||
"Found corresponding htlc_in %" PRIu64
|
|
||||||
" for htlc_out %" PRIu64,
|
|
||||||
hin->dbid, hout->dbid);
|
|
||||||
htlc_out_connect_htlc_in(hout, hin);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hout->in && !hout->preimage) {
|
|
||||||
#ifdef COMPAT_V061
|
|
||||||
log_broken(ld->log,
|
|
||||||
"Missing preimage for orphaned HTLC; replacing with zeros");
|
|
||||||
hout->preimage = talz(hout, struct preimage);
|
|
||||||
#else
|
|
||||||
fatal("Unable to find corresponding htlc_in %"PRIu64
|
|
||||||
" for unfulfilled htlc_out %"PRIu64,
|
|
||||||
hout->origin_htlc_id, hout->dbid);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#ifdef COMPAT_V061
|
|
||||||
fixup_hout(ld, hout);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (hout->in)
|
|
||||||
htlc_in_map_del(unprocessed, hout->in);
|
|
||||||
}
|
|
||||||
|
|
||||||
return unprocessed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void htlcs_resubmit(struct lightningd *ld, struct htlc_in_map *unprocessed)
|
|
||||||
{
|
{
|
||||||
struct htlc_in *hin;
|
struct htlc_in *hin;
|
||||||
struct htlc_in_map_iter ini;
|
struct htlc_in_map_iter ini;
|
||||||
enum onion_type failcode COMPILER_WANTS_INIT("gcc7.4.0 bad, 8.3 OK");
|
enum onion_type failcode COMPILER_WANTS_INIT("gcc7.4.0 bad, 8.3 OK");
|
||||||
|
|
||||||
/* Now fail any which were stuck. */
|
/* Now retry any which were stuck. */
|
||||||
for (hin = htlc_in_map_first(unprocessed, &ini);
|
for (hin = htlc_in_map_first(unconnected_htlcs_in, &ini);
|
||||||
hin;
|
hin;
|
||||||
hin = htlc_in_map_next(unprocessed, &ini)) {
|
hin = htlc_in_map_next(unconnected_htlcs_in, &ini)) {
|
||||||
|
if (hin->hstate != RCVD_ADD_ACK_REVOCATION)
|
||||||
|
continue;
|
||||||
|
|
||||||
log_unusual(hin->key.channel->log,
|
log_unusual(hin->key.channel->log,
|
||||||
"Replaying old unprocessed HTLC #%"PRIu64,
|
"Replaying old unprocessed HTLC #%"PRIu64,
|
||||||
hin->key.id);
|
hin->key.id);
|
||||||
|
@ -2192,8 +2133,8 @@ void htlcs_resubmit(struct lightningd *ld, struct htlc_in_map *unprocessed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't leak memory! */
|
/* Don't leak memory! */
|
||||||
htlc_in_map_clear(unprocessed);
|
htlc_in_map_clear(unconnected_htlcs_in);
|
||||||
tal_free(unprocessed);
|
tal_free(unconnected_htlcs_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEVELOPER
|
#if DEVELOPER
|
||||||
|
|
|
@ -64,11 +64,11 @@ void onchain_fulfilled_htlc(struct channel *channel,
|
||||||
|
|
||||||
void htlcs_notify_new_block(struct lightningd *ld, u32 height);
|
void htlcs_notify_new_block(struct lightningd *ld, u32 height);
|
||||||
|
|
||||||
struct htlc_in_map *htlcs_reconnect(struct lightningd *ld,
|
/* Only defined if COMPAT_V061 */
|
||||||
struct htlc_in_map *htlcs_in,
|
void fixup_htlcs_out(struct lightningd *ld);
|
||||||
struct htlc_out_map *htlcs_out);
|
|
||||||
|
|
||||||
void htlcs_resubmit(struct lightningd *ld, struct htlc_in_map *unprocessed);
|
void htlcs_resubmit(struct lightningd *ld,
|
||||||
|
struct htlc_in_map *unconnected_htlcs_in);
|
||||||
|
|
||||||
/* For HTLCs which terminate here, invoice payment calls one of these. */
|
/* For HTLCs which terminate here, invoice payment calls one of these. */
|
||||||
void fulfill_htlc(struct htlc_in *hin, const struct preimage *preimage);
|
void fulfill_htlc(struct htlc_in *hin, const struct preimage *preimage);
|
||||||
|
|
|
@ -97,7 +97,8 @@ void hsm_init(struct lightningd *ld UNNEEDED)
|
||||||
void htlcs_notify_new_block(struct lightningd *ld UNNEEDED, u32 height UNNEEDED)
|
void htlcs_notify_new_block(struct lightningd *ld UNNEEDED, u32 height UNNEEDED)
|
||||||
{ fprintf(stderr, "htlcs_notify_new_block called!\n"); abort(); }
|
{ fprintf(stderr, "htlcs_notify_new_block called!\n"); abort(); }
|
||||||
/* Generated stub for htlcs_resubmit */
|
/* Generated stub for htlcs_resubmit */
|
||||||
void htlcs_resubmit(struct lightningd *ld UNNEEDED, struct htlc_in_map *unprocessed UNNEEDED)
|
void htlcs_resubmit(struct lightningd *ld UNNEEDED,
|
||||||
|
struct htlc_in_map *unconnected_htlcs_in UNNEEDED)
|
||||||
{ fprintf(stderr, "htlcs_resubmit called!\n"); abort(); }
|
{ fprintf(stderr, "htlcs_resubmit called!\n"); abort(); }
|
||||||
/* Generated stub for jsonrpc_listen */
|
/* Generated stub for jsonrpc_listen */
|
||||||
void jsonrpc_listen(struct jsonrpc *rpc UNNEEDED, struct lightningd *ld UNNEEDED)
|
void jsonrpc_listen(struct jsonrpc *rpc UNNEEDED, struct lightningd *ld UNNEEDED)
|
||||||
|
|
|
@ -96,6 +96,9 @@ void fatal(const char *fmt UNNEEDED, ...)
|
||||||
/* Generated stub for feature_is_set */
|
/* Generated stub for feature_is_set */
|
||||||
bool feature_is_set(const u8 *features UNNEEDED, size_t bit UNNEEDED)
|
bool feature_is_set(const u8 *features UNNEEDED, size_t bit UNNEEDED)
|
||||||
{ fprintf(stderr, "feature_is_set called!\n"); abort(); }
|
{ fprintf(stderr, "feature_is_set called!\n"); abort(); }
|
||||||
|
/* Generated stub for fixup_htlcs_out */
|
||||||
|
void fixup_htlcs_out(struct lightningd *ld UNNEEDED)
|
||||||
|
{ fprintf(stderr, "fixup_htlcs_out called!\n"); abort(); }
|
||||||
/* Generated stub for fromwire_channel_dev_memleak_reply */
|
/* Generated stub for fromwire_channel_dev_memleak_reply */
|
||||||
bool fromwire_channel_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED)
|
bool fromwire_channel_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED)
|
||||||
{ fprintf(stderr, "fromwire_channel_dev_memleak_reply called!\n"); abort(); }
|
{ fprintf(stderr, "fromwire_channel_dev_memleak_reply called!\n"); abort(); }
|
||||||
|
@ -133,11 +136,6 @@ bool htlc_is_trimmed(enum side htlc_owner UNNEEDED,
|
||||||
struct amount_sat dust_limit UNNEEDED,
|
struct amount_sat dust_limit UNNEEDED,
|
||||||
enum side side UNNEEDED)
|
enum side side UNNEEDED)
|
||||||
{ fprintf(stderr, "htlc_is_trimmed called!\n"); abort(); }
|
{ fprintf(stderr, "htlc_is_trimmed called!\n"); abort(); }
|
||||||
/* Generated stub for htlcs_reconnect */
|
|
||||||
struct htlc_in_map *htlcs_reconnect(struct lightningd *ld UNNEEDED,
|
|
||||||
struct htlc_in_map *htlcs_in UNNEEDED,
|
|
||||||
struct htlc_out_map *htlcs_out UNNEEDED)
|
|
||||||
{ fprintf(stderr, "htlcs_reconnect called!\n"); abort(); }
|
|
||||||
/* Generated stub for json_add_address */
|
/* Generated stub for json_add_address */
|
||||||
void json_add_address(struct json_stream *response UNNEEDED, const char *fieldname UNNEEDED,
|
void json_add_address(struct json_stream *response UNNEEDED, const char *fieldname UNNEEDED,
|
||||||
const struct wireaddr *addr UNNEEDED)
|
const struct wireaddr *addr UNNEEDED)
|
||||||
|
@ -504,12 +502,17 @@ void wallet_channeltxs_add(struct wallet *w UNNEEDED, struct channel *chan UNNEE
|
||||||
const int type UNNEEDED, const struct bitcoin_txid *txid UNNEEDED,
|
const int type UNNEEDED, const struct bitcoin_txid *txid UNNEEDED,
|
||||||
const u32 input_num UNNEEDED, const u32 blockheight UNNEEDED)
|
const u32 input_num UNNEEDED, const u32 blockheight UNNEEDED)
|
||||||
{ fprintf(stderr, "wallet_channeltxs_add called!\n"); abort(); }
|
{ fprintf(stderr, "wallet_channeltxs_add called!\n"); abort(); }
|
||||||
/* Generated stub for wallet_htlcs_load_for_channel */
|
/* Generated stub for wallet_htlcs_load_in_for_channel */
|
||||||
bool wallet_htlcs_load_for_channel(struct wallet *wallet UNNEEDED,
|
bool wallet_htlcs_load_in_for_channel(struct wallet *wallet UNNEEDED,
|
||||||
struct channel *chan UNNEEDED,
|
struct channel *chan UNNEEDED,
|
||||||
struct htlc_in_map *htlcs_in UNNEEDED,
|
struct htlc_in_map *htlcs_in UNNEEDED)
|
||||||
struct htlc_out_map *htlcs_out UNNEEDED)
|
{ fprintf(stderr, "wallet_htlcs_load_in_for_channel called!\n"); abort(); }
|
||||||
{ fprintf(stderr, "wallet_htlcs_load_for_channel called!\n"); abort(); }
|
/* Generated stub for wallet_htlcs_load_out_for_channel */
|
||||||
|
bool wallet_htlcs_load_out_for_channel(struct wallet *wallet UNNEEDED,
|
||||||
|
struct channel *chan UNNEEDED,
|
||||||
|
struct htlc_out_map *htlcs_out UNNEEDED,
|
||||||
|
struct htlc_in_map *remaining_htlcs_in UNNEEDED)
|
||||||
|
{ fprintf(stderr, "wallet_htlcs_load_out_for_channel called!\n"); abort(); }
|
||||||
/* Generated stub for wallet_init_channels */
|
/* Generated stub for wallet_init_channels */
|
||||||
bool wallet_init_channels(struct wallet *w UNNEEDED)
|
bool wallet_init_channels(struct wallet *w UNNEEDED)
|
||||||
{ fprintf(stderr, "wallet_init_channels called!\n"); abort(); }
|
{ fprintf(stderr, "wallet_init_channels called!\n"); abort(); }
|
||||||
|
|
|
@ -1156,7 +1156,7 @@ static bool test_htlc_crud(struct lightningd *ld, const tal_t *ctx)
|
||||||
struct channel *chan = tal(ctx, struct channel);
|
struct channel *chan = tal(ctx, struct channel);
|
||||||
struct peer *peer = talz(ctx, struct peer);
|
struct peer *peer = talz(ctx, struct peer);
|
||||||
struct wallet *w = create_test_wallet(ld, ctx);
|
struct wallet *w = create_test_wallet(ld, ctx);
|
||||||
struct htlc_in_map *htlcs_in = tal(ctx, struct htlc_in_map);
|
struct htlc_in_map *htlcs_in = tal(ctx, struct htlc_in_map), *rem;
|
||||||
struct htlc_out_map *htlcs_out = tal(ctx, struct htlc_out_map);
|
struct htlc_out_map *htlcs_out = tal(ctx, struct htlc_out_map);
|
||||||
|
|
||||||
/* Make sure we have our references correct */
|
/* Make sure we have our references correct */
|
||||||
|
@ -1220,11 +1220,16 @@ static bool test_htlc_crud(struct lightningd *ld, const tal_t *ctx)
|
||||||
db_begin_transaction(w->db);
|
db_begin_transaction(w->db);
|
||||||
CHECK(!wallet_err);
|
CHECK(!wallet_err);
|
||||||
|
|
||||||
CHECK_MSG(wallet_htlcs_load_for_channel(w, chan, htlcs_in, htlcs_out),
|
CHECK_MSG(wallet_htlcs_load_in_for_channel(w, chan, htlcs_in),
|
||||||
"Failed loading HTLCs");
|
"Failed loading in HTLCs");
|
||||||
|
/* Freed by htlcs_resubmit */
|
||||||
|
rem = tal(NULL, struct htlc_in_map);
|
||||||
|
htlc_in_map_copy(rem, htlcs_in);
|
||||||
|
CHECK_MSG(wallet_htlcs_load_out_for_channel(w, chan, htlcs_out, rem),
|
||||||
|
"Failed loading out HTLCs");
|
||||||
db_commit_transaction(w->db);
|
db_commit_transaction(w->db);
|
||||||
|
|
||||||
htlcs_resubmit(w->ld, htlcs_reconnect(w->ld, htlcs_in, htlcs_out));
|
htlcs_resubmit(w->ld, rem);
|
||||||
CHECK(!wallet_err);
|
CHECK(!wallet_err);
|
||||||
|
|
||||||
hin = htlc_in_map_get(htlcs_in, &in.key);
|
hin = htlc_in_map_get(htlcs_in, &in.key);
|
||||||
|
|
|
@ -1647,7 +1647,6 @@ void wallet_htlc_save_out(struct wallet *wallet,
|
||||||
/* We absolutely need the incoming HTLC to be persisted before
|
/* We absolutely need the incoming HTLC to be persisted before
|
||||||
* we can persist it's dependent */
|
* we can persist it's dependent */
|
||||||
assert(out->in == NULL || out->in->dbid != 0);
|
assert(out->in == NULL || out->in->dbid != 0);
|
||||||
out->origin_htlc_id = out->in?out->in->dbid:0;
|
|
||||||
|
|
||||||
stmt = db_prepare_v2(
|
stmt = db_prepare_v2(
|
||||||
wallet->db,
|
wallet->db,
|
||||||
|
@ -1770,8 +1769,11 @@ static bool wallet_stmt2htlc_in(struct channel *channel,
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool wallet_stmt2htlc_out(struct channel *channel,
|
/* Removes matching htlc from unconnected_htlcs_in */
|
||||||
struct db_stmt *stmt, struct htlc_out *out)
|
static bool wallet_stmt2htlc_out(struct wallet *wallet,
|
||||||
|
struct channel *channel,
|
||||||
|
struct db_stmt *stmt, struct htlc_out *out,
|
||||||
|
struct htlc_in_map *unconnected_htlcs_in)
|
||||||
{
|
{
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
out->dbid = db_column_u64(stmt, 0);
|
out->dbid = db_column_u64(stmt, 0);
|
||||||
|
@ -1795,20 +1797,32 @@ static bool wallet_stmt2htlc_out(struct channel *channel,
|
||||||
|
|
||||||
out->failuremsg = db_column_arr(out, stmt, 8, u8);
|
out->failuremsg = db_column_arr(out, stmt, 8, u8);
|
||||||
out->failcode = db_column_int_or_default(stmt, 9, 0);
|
out->failcode = db_column_int_or_default(stmt, 9, 0);
|
||||||
|
out->in = NULL;
|
||||||
|
|
||||||
if (!db_column_is_null(stmt, 10)) {
|
if (!db_column_is_null(stmt, 10)) {
|
||||||
out->origin_htlc_id = db_column_u64(stmt, 10);
|
u64 in_id = db_column_u64(stmt, 10);
|
||||||
|
struct htlc_in *hin;
|
||||||
|
|
||||||
|
hin = remove_htlc_in_by_dbid(unconnected_htlcs_in, in_id);
|
||||||
|
if (hin)
|
||||||
|
htlc_out_connect_htlc_in(out, hin);
|
||||||
out->am_origin = false;
|
out->am_origin = false;
|
||||||
|
if (!out->in && !out->preimage) {
|
||||||
|
#ifdef COMPAT_V061
|
||||||
|
log_broken(wallet->log,
|
||||||
|
"Missing preimage for orphaned HTLC; replacing with zeros");
|
||||||
|
out->preimage = talz(out, struct preimage);
|
||||||
|
#else
|
||||||
|
fatal("Unable to find corresponding htlc_in %"PRIu64
|
||||||
|
" for unfulfilled htlc_out %"PRIu64,
|
||||||
|
in_id, out->dbid);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
out->origin_htlc_id = 0;
|
|
||||||
out->partid = db_column_u64(stmt, 13);
|
out->partid = db_column_u64(stmt, 13);
|
||||||
out->am_origin = true;
|
out->am_origin = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Need to defer wiring until we can look up all incoming
|
|
||||||
* htlcs, will wire using origin_htlc_id */
|
|
||||||
out->in = NULL;
|
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1849,16 +1863,15 @@ static void fixup_hin(struct wallet *wallet, struct htlc_in *hin)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wallet_htlcs_load_for_channel(struct wallet *wallet,
|
bool wallet_htlcs_load_in_for_channel(struct wallet *wallet,
|
||||||
struct channel *chan,
|
struct channel *chan,
|
||||||
struct htlc_in_map *htlcs_in,
|
struct htlc_in_map *htlcs_in)
|
||||||
struct htlc_out_map *htlcs_out)
|
|
||||||
{
|
{
|
||||||
struct db_stmt *stmt;
|
struct db_stmt *stmt;
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
int incount = 0, outcount = 0;
|
int incount = 0;
|
||||||
|
|
||||||
log_debug(wallet->log, "Loading HTLCs for channel %"PRIu64, chan->dbid);
|
log_debug(wallet->log, "Loading in HTLCs for channel %"PRIu64, chan->dbid);
|
||||||
stmt = db_prepare_v2(wallet->db, SQL("SELECT"
|
stmt = db_prepare_v2(wallet->db, SQL("SELECT"
|
||||||
" id"
|
" id"
|
||||||
", channel_htlc_id"
|
", channel_htlc_id"
|
||||||
|
@ -1892,6 +1905,19 @@ bool wallet_htlcs_load_for_channel(struct wallet *wallet,
|
||||||
}
|
}
|
||||||
tal_free(stmt);
|
tal_free(stmt);
|
||||||
|
|
||||||
|
log_debug(wallet->log, "Restored %d incoming HTLCS", incount);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wallet_htlcs_load_out_for_channel(struct wallet *wallet,
|
||||||
|
struct channel *chan,
|
||||||
|
struct htlc_out_map *htlcs_out,
|
||||||
|
struct htlc_in_map *unconnected_htlcs_in)
|
||||||
|
{
|
||||||
|
struct db_stmt *stmt;
|
||||||
|
bool ok = true;
|
||||||
|
int outcount = 0;
|
||||||
|
|
||||||
stmt = db_prepare_v2(wallet->db, SQL("SELECT"
|
stmt = db_prepare_v2(wallet->db, SQL("SELECT"
|
||||||
" id"
|
" id"
|
||||||
", channel_htlc_id"
|
", channel_htlc_id"
|
||||||
|
@ -1918,7 +1944,8 @@ bool wallet_htlcs_load_for_channel(struct wallet *wallet,
|
||||||
|
|
||||||
while (db_step(stmt)) {
|
while (db_step(stmt)) {
|
||||||
struct htlc_out *out = tal(chan, struct htlc_out);
|
struct htlc_out *out = tal(chan, struct htlc_out);
|
||||||
ok &= wallet_stmt2htlc_out(chan, stmt, out);
|
ok &= wallet_stmt2htlc_out(wallet, chan, stmt, out,
|
||||||
|
unconnected_htlcs_in);
|
||||||
connect_htlc_out(htlcs_out, out);
|
connect_htlc_out(htlcs_out, out);
|
||||||
/* Cannot htlc_out_check because we haven't wired the
|
/* Cannot htlc_out_check because we haven't wired the
|
||||||
* dependencies in yet */
|
* dependencies in yet */
|
||||||
|
@ -1926,7 +1953,7 @@ bool wallet_htlcs_load_for_channel(struct wallet *wallet,
|
||||||
}
|
}
|
||||||
tal_free(stmt);
|
tal_free(stmt);
|
||||||
|
|
||||||
log_debug(wallet->log, "Restored %d incoming and %d outgoing HTLCS", incount, outcount);
|
log_debug(wallet->log, "Restored %d outgoing HTLCS", outcount);
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -594,29 +594,35 @@ void wallet_htlc_update(struct wallet *wallet, const u64 htlc_dbid,
|
||||||
enum onion_type failcode, const u8 *failuremsg);
|
enum onion_type failcode, const u8 *failuremsg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wallet_htlcs_load_for_channel - Load HTLCs associated with chan from DB.
|
* wallet_htlcs_load_in_for_channel - Load incoming HTLCs associated with chan from DB.
|
||||||
*
|
*
|
||||||
* @wallet: wallet to load from
|
* @wallet: wallet to load from
|
||||||
* @chan: load HTLCs associated with this channel
|
* @chan: load HTLCs associated with this channel
|
||||||
* @htlcs_in: htlc_in_map to store loaded htlc_in in
|
* @htlcs_in: htlc_in_map to store loaded htlc_in in
|
||||||
* @htlcs_out: htlc_out_map to store loaded htlc_out in
|
|
||||||
*
|
*
|
||||||
* This function looks for HTLCs that are associated with the given
|
* This function looks for incoming HTLCs that are associated with the given
|
||||||
* channel and loads them into the provided maps. One caveat is that
|
* channel and loads them into the provided map.
|
||||||
* the `struct htlc_out` instances are not wired up with the
|
|
||||||
* corresponding `struct htlc_in` in the forwarding case nor are they
|
|
||||||
* associated with a `struct pay_command` in the case we originated
|
|
||||||
* the payment. In the former case the corresponding `struct htlc_in`
|
|
||||||
* may not have been loaded yet. In the latter case the pay_command
|
|
||||||
* does not exist anymore since we restarted.
|
|
||||||
*
|
|
||||||
* Use `htlcs_reconnect` to wire htlc_out instances to the
|
|
||||||
* corresponding htlc_in after loading all channels.
|
|
||||||
*/
|
*/
|
||||||
bool wallet_htlcs_load_for_channel(struct wallet *wallet,
|
bool wallet_htlcs_load_in_for_channel(struct wallet *wallet,
|
||||||
struct channel *chan,
|
struct channel *chan,
|
||||||
struct htlc_in_map *htlcs_in,
|
struct htlc_in_map *htlcs_in);
|
||||||
struct htlc_out_map *htlcs_out);
|
|
||||||
|
/**
|
||||||
|
* wallet_htlcs_load_out_for_channel - Load outgoing HTLCs associated with chan from DB.
|
||||||
|
*
|
||||||
|
* @wallet: wallet to load from
|
||||||
|
* @chan: load HTLCs associated with this channel
|
||||||
|
* @htlcs_out: htlc_out_map to store loaded htlc_out in.
|
||||||
|
* @remaining_htlcs_in: htlc_in_map with unconnected htlcs (removed as we progress)
|
||||||
|
*
|
||||||
|
* We populate htlc_out->in by looking up in remaining_htlcs_in. It's
|
||||||
|
* possible that it's still NULL, since we can have outgoing HTLCs
|
||||||
|
* outlive their corresponding incoming.
|
||||||
|
*/
|
||||||
|
bool wallet_htlcs_load_out_for_channel(struct wallet *wallet,
|
||||||
|
struct channel *chan,
|
||||||
|
struct htlc_out_map *htlcs_out,
|
||||||
|
struct htlc_in_map *remaining_htlcs_in);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wallet_announcement_save - Save remote announcement information with channel.
|
* wallet_announcement_save - Save remote announcement information with channel.
|
||||||
|
|
Loading…
Add table
Reference in a new issue