mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 05:12:45 +01:00
c956d9f5eb
This is a primitive mark-and-sweep-style garbage detector. The core is in common/ for later use by subdaemons, but for now it's just lightningd. We initialize it before most other allocations. We walk the tal tree to get all the pointers, then search the `ld` object for those pointers, recursing down. Some specific helpers are required for hashtables (which stash bits in the unused pointer bits, so won't be found). There's `notleak()` for annotating things that aren't leaks: things like globals and timers, and other semi-transients. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
198 lines
5.4 KiB
C
198 lines
5.4 KiB
C
#include <ccan/cast/cast.h>
|
|
#include <ccan/crypto/siphash24/siphash24.h>
|
|
#include <ccan/tal/str/str.h>
|
|
#include <ccan/tal/tal.h>
|
|
#include <common/htlc.h>
|
|
#include <common/memleak.h>
|
|
#include <common/pseudorand.h>
|
|
#include <lightningd/htlc_end.h>
|
|
#include <lightningd/log.h>
|
|
#include <stdio.h>
|
|
|
|
size_t hash_htlc_key(const struct htlc_key *k)
|
|
{
|
|
struct siphash24_ctx ctx;
|
|
siphash24_init(&ctx, siphash_seed());
|
|
/* peer doesn't move while in this hash, so we just hash pointer. */
|
|
siphash24_update(&ctx, &k->peer, sizeof(k->peer));
|
|
siphash24_u64(&ctx, k->id);
|
|
|
|
return siphash24_done(&ctx);
|
|
}
|
|
|
|
struct htlc_in *find_htlc_in(const struct htlc_in_map *map,
|
|
const struct peer *peer,
|
|
u64 htlc_id)
|
|
{
|
|
const struct htlc_key key = { (struct peer *)peer, htlc_id };
|
|
return htlc_in_map_get(map, &key);
|
|
}
|
|
|
|
static void remove_htlc_in(struct htlc_in *hend, struct htlc_in_map *map)
|
|
{
|
|
htlc_in_map_del(map, hend);
|
|
}
|
|
|
|
void connect_htlc_in(struct htlc_in_map *map, struct htlc_in *hend)
|
|
{
|
|
tal_add_destructor2(hend, remove_htlc_in, map);
|
|
htlc_in_map_add(map, hend);
|
|
}
|
|
|
|
struct htlc_out *find_htlc_out(const struct htlc_out_map *map,
|
|
const struct peer *peer,
|
|
u64 htlc_id)
|
|
{
|
|
const struct htlc_key key = { (struct peer *)peer, htlc_id };
|
|
return htlc_out_map_get(map, &key);
|
|
}
|
|
|
|
static void remove_htlc_out(struct htlc_out *hend, struct htlc_out_map *map)
|
|
{
|
|
htlc_out_map_del(map, hend);
|
|
}
|
|
|
|
void connect_htlc_out(struct htlc_out_map *map, struct htlc_out *hend)
|
|
{
|
|
tal_add_destructor2(hend, remove_htlc_out, map);
|
|
htlc_out_map_add(map, hend);
|
|
}
|
|
|
|
static void *PRINTF_FMT(3,4)
|
|
corrupt(const void *ptr, const char *abortstr, const char *fmt, ...)
|
|
{
|
|
if (abortstr) {
|
|
char *p;
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
p = tal_vfmt(NULL, fmt, ap);
|
|
fatal("%s:%s\n", abortstr, p);
|
|
va_end(ap);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
struct htlc_in *htlc_in_check(const struct htlc_in *hin, const char *abortstr)
|
|
{
|
|
if (hin->msatoshi == 0)
|
|
return corrupt(hin, abortstr, "zero msatoshi");
|
|
else if (htlc_state_owner(hin->hstate) != REMOTE)
|
|
return corrupt(hin, abortstr, "invalid state %s",
|
|
htlc_state_name(hin->hstate));
|
|
else if (hin->failuremsg && hin->preimage)
|
|
return corrupt(hin, abortstr, "Both failuremsg and succeeded");
|
|
else if (hin->failcode != 0 && hin->preimage)
|
|
return corrupt(hin, abortstr, "Both failcode and succeeded");
|
|
else if (hin->failuremsg && (hin->failcode & BADONION))
|
|
return corrupt(hin, abortstr, "Both failed and malformed");
|
|
|
|
return cast_const(struct htlc_in *, hin);
|
|
}
|
|
|
|
struct htlc_in *new_htlc_in(const tal_t *ctx,
|
|
struct peer *peer, u64 id,
|
|
u64 msatoshi, u32 cltv_expiry,
|
|
const struct sha256 *payment_hash,
|
|
const struct secret *shared_secret,
|
|
const u8 *onion_routing_packet)
|
|
{
|
|
struct htlc_in *hin = tal(ctx, struct htlc_in);
|
|
|
|
hin->dbid = 0;
|
|
hin->key.peer = peer;
|
|
hin->key.id = id;
|
|
hin->msatoshi = msatoshi;
|
|
hin->cltv_expiry = cltv_expiry;
|
|
hin->payment_hash = *payment_hash;
|
|
hin->shared_secret = *shared_secret;
|
|
memcpy(hin->onion_routing_packet, onion_routing_packet,
|
|
sizeof(hin->onion_routing_packet));
|
|
|
|
hin->hstate = RCVD_ADD_COMMIT;
|
|
hin->failcode = 0;
|
|
hin->failuremsg = NULL;
|
|
hin->preimage = NULL;
|
|
|
|
return htlc_in_check(hin, "new_htlc_in");
|
|
}
|
|
|
|
struct htlc_out *htlc_out_check(const struct htlc_out *hout,
|
|
const char *abortstr)
|
|
{
|
|
if (hout->msatoshi == 0)
|
|
return corrupt(hout, abortstr, "zero msatoshi");
|
|
else if (htlc_state_owner(hout->hstate) != LOCAL)
|
|
return corrupt(hout, abortstr, "invalid state %s",
|
|
htlc_state_name(hout->hstate));
|
|
else if (hout->failuremsg && hout->preimage)
|
|
return corrupt(hout, abortstr, "Both failed and succeeded");
|
|
else if (!hout->in && !hout->pay_command)
|
|
return corrupt(hout, abortstr,
|
|
"Neither hout->in nor paycommand");
|
|
|
|
return cast_const(struct htlc_out *, hout);
|
|
}
|
|
|
|
/* You need to set the ID, then connect_htlc_out this! */
|
|
struct htlc_out *new_htlc_out(const tal_t *ctx,
|
|
struct peer *peer,
|
|
u64 msatoshi, u32 cltv_expiry,
|
|
const struct sha256 *payment_hash,
|
|
const u8 *onion_routing_packet,
|
|
struct htlc_in *in,
|
|
struct pay_command *pc,
|
|
struct wallet_payment *payment)
|
|
{
|
|
struct htlc_out *hout = tal(ctx, struct htlc_out);
|
|
|
|
/* Mark this as an as of now unsaved HTLC */
|
|
hout->dbid = 0;
|
|
|
|
hout->key.peer = peer;
|
|
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));
|
|
|
|
hout->hstate = SENT_ADD_HTLC;
|
|
hout->failcode = 0;
|
|
hout->failuremsg = NULL;
|
|
hout->preimage = NULL;
|
|
|
|
hout->in = in;
|
|
hout->pay_command = pc;
|
|
|
|
return htlc_out_check(hout, "new_htlc_out");
|
|
}
|
|
|
|
#if DEVELOPER
|
|
void htlc_inmap_mark_pointers_used(struct htable *memtable,
|
|
const struct htlc_in_map *map)
|
|
{
|
|
struct htlc_in *hin;
|
|
struct htlc_in_map_iter it;
|
|
|
|
/* memleak can't see inside hash tables, so do them manually */
|
|
for (hin = htlc_in_map_first(map, &it);
|
|
hin;
|
|
hin = htlc_in_map_next(map, &it))
|
|
memleak_scan_region(memtable, hin);
|
|
}
|
|
|
|
void htlc_outmap_mark_pointers_used(struct htable *memtable,
|
|
const struct htlc_out_map *map)
|
|
{
|
|
struct htlc_out *hout;
|
|
struct htlc_out_map_iter it;
|
|
|
|
/* memleak can't see inside hash tables, so do them manually */
|
|
for (hout = htlc_out_map_first(map, &it);
|
|
hout;
|
|
hout = htlc_out_map_next(map, &it))
|
|
memleak_scan_region(memtable, hout);
|
|
}
|
|
#endif /* DEVELOPER */
|