core-lightning/plugins/askrene/reserve.c

120 lines
3 KiB
C
Raw Normal View History

#include "config.h"
#include <assert.h>
#include <ccan/htable/htable_type.h>
#include <plugins/askrene/reserve.h>
/* Hash table for reservations */
static const struct short_channel_id_dir *
reserve_scidd(const struct reserve *r)
{
return &r->scidd;
}
static size_t hash_scidd(const struct short_channel_id_dir *scidd)
{
/* scids cost money to generate, so simple hash works here */
return (scidd->scid.u64 >> 32) ^ (scidd->scid.u64 >> 16) ^ (scidd->scid.u64 << 1) ^ scidd->dir;
}
static bool reserve_eq_scidd(const struct reserve *r,
const struct short_channel_id_dir *scidd)
{
return short_channel_id_dir_eq(scidd, &r->scidd);
}
HTABLE_DEFINE_TYPE(struct reserve, reserve_scidd, hash_scidd,
reserve_eq_scidd, reserve_hash);
struct reserve_hash *new_reserve_hash(const tal_t *ctx)
{
struct reserve_hash *reserved = tal(ctx, struct reserve_hash);
reserve_hash_init(reserved);
return reserved;
}
/* Find a reservation for this scidd (if any!) */
const struct reserve *find_reserve(const struct reserve_hash *reserved,
const struct short_channel_id_dir *scidd)
{
return reserve_hash_get(reserved, scidd);
}
/* Create a new (empty) reservation */
static struct reserve *new_reserve(struct reserve_hash *reserved,
const struct short_channel_id_dir *scidd)
{
struct reserve *r = tal(reserved, struct reserve);
r->num_htlcs = 0;
r->amount = AMOUNT_MSAT(0);
r->scidd = *scidd;
reserve_hash_add(reserved, r);
return r;
}
static void del_reserve(struct reserve_hash *reserved, struct reserve *r)
{
assert(r->num_htlcs == 0);
reserve_hash_del(reserved, r);
tal_free(r);
}
/* Add to existing reservation (false if would overflow). */
static bool add(struct reserve *r, struct amount_msat amount)
{
if (!amount_msat_add(&r->amount, r->amount, amount))
return false;
r->num_htlcs++;
return true;
}
static bool remove(struct reserve *r, struct amount_msat amount)
{
if (r->num_htlcs == 0)
return false;
if (!amount_msat_sub(&r->amount, r->amount, amount))
return false;
r->num_htlcs--;
return true;
}
/* Atomically add to reserves, or fail.
* Returns offset of failure, or num on success */
size_t reserves_add(struct reserve_hash *reserved,
const struct short_channel_id_dir *scidds,
const struct amount_msat *amounts,
size_t num)
{
for (size_t i = 0; i < num; i++) {
struct reserve *r = reserve_hash_get(reserved, &scidds[i]);
if (!r)
r = new_reserve(reserved, &scidds[i]);
if (!add(r, amounts[i])) {
reserves_remove(reserved, scidds, amounts, i);
return i;
}
}
return num;
}
/* Atomically remove from reserves, to fail.
* Returns offset of failure or tal_count(scidds) */
size_t reserves_remove(struct reserve_hash *reserved,
const struct short_channel_id_dir *scidds,
const struct amount_msat *amounts,
size_t num)
{
for (size_t i = 0; i < num; i++) {
struct reserve *r = reserve_hash_get(reserved, &scidds[i]);
if (!r || !remove(r, amounts[i])) {
reserves_add(reserved, scidds, amounts, i);
return i;
}
if (r->num_htlcs == 0)
del_reserve(reserved, r);
}
return num;
}