mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-26 20:30:59 +01:00
askrene: rework constraints to exist in pairs.
This is a bit more efficient, but moreover the JSONRPC API is more logical this way. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
3c5c22b17a
commit
321ec0875f
9 changed files with 75 additions and 103 deletions
|
@ -727,13 +727,13 @@
|
|||
"maximum_msat": {
|
||||
"type": "msat",
|
||||
"description": [
|
||||
"The maximum value which this channel could pass. This or *minimum_msat* will be present, but not both."
|
||||
"The maximum value which this channel could pass."
|
||||
]
|
||||
},
|
||||
"minimum_msat": {
|
||||
"type": "msat",
|
||||
"description": [
|
||||
"The minimum value which this channel could pass. This or *minimum_msat* will be present, but not both."
|
||||
"The minimum value which this channel could pass."
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -909,13 +909,13 @@
|
|||
"maximum_msat": {
|
||||
"type": "msat",
|
||||
"description": [
|
||||
"The maximum value which this channel could pass. This or *minimum_msat* will be present, but not both."
|
||||
"The maximum value which this channel could pass."
|
||||
]
|
||||
},
|
||||
"minimum_msat": {
|
||||
"type": "msat",
|
||||
"description": [
|
||||
"The minimum value which this channel could pass. This or *minimum_msat* will be present, but not both."
|
||||
"The minimum value which this channel could pass."
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,13 +70,13 @@
|
|||
"maximum_msat": {
|
||||
"type": "msat",
|
||||
"description": [
|
||||
"The maximum value which this channel could pass. This or *minimum_msat* will be present, but not both."
|
||||
"The maximum value which this channel could pass."
|
||||
]
|
||||
},
|
||||
"minimum_msat": {
|
||||
"type": "msat",
|
||||
"description": [
|
||||
"The minimum value which this channel could pass. This or *minimum_msat* will be present, but not both."
|
||||
"The minimum value which this channel could pass."
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -152,13 +152,13 @@
|
|||
"maximum_msat": {
|
||||
"type": "msat",
|
||||
"description": [
|
||||
"The maximum value which this channel could pass. This or *minimum_msat* will be present, but not both."
|
||||
"The maximum value which this channel could pass."
|
||||
]
|
||||
},
|
||||
"minimum_msat": {
|
||||
"type": "msat",
|
||||
"description": [
|
||||
"The minimum value which this channel could pass. This or *minimum_msat* will be present, but not both."
|
||||
"The minimum value which this channel could pass."
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,12 +35,6 @@ per_htlc_cost_key(const struct per_htlc_cost *phc)
|
|||
return &phc->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 << 1) ^ scidd->dir;
|
||||
}
|
||||
|
||||
static inline bool per_htlc_cost_eq_key(const struct per_htlc_cost *phc,
|
||||
const struct short_channel_id_dir *scidd)
|
||||
{
|
||||
|
@ -462,15 +456,17 @@ void get_constraints(const struct route_query *rq,
|
|||
scidd.dir = dir;
|
||||
*max = AMOUNT_MSAT(-1ULL);
|
||||
|
||||
/* Look through layers for any constraints */
|
||||
/* Look through layers for any constraints (might be dummy
|
||||
* ones, for created channels!) */
|
||||
for (size_t i = 0; i < tal_count(rq->layers); i++) {
|
||||
const struct constraint *cmin, *cmax;
|
||||
cmin = layer_find_constraint(rq->layers[i], &scidd, CONSTRAINT_MIN);
|
||||
if (cmin && amount_msat_greater(cmin->limit, *min))
|
||||
*min = cmin->limit;
|
||||
cmax = layer_find_constraint(rq->layers[i], &scidd, CONSTRAINT_MAX);
|
||||
if (cmax && amount_msat_less(cmax->limit, *max))
|
||||
*max = cmax->limit;
|
||||
const struct constraint *c;
|
||||
c = layer_find_constraint(rq->layers[i], &scidd);
|
||||
if (c) {
|
||||
if (amount_msat_greater(c->min, *min))
|
||||
*min = c->min;
|
||||
if (amount_msat_less(c->max, *max))
|
||||
*max = c->max;
|
||||
}
|
||||
}
|
||||
|
||||
/* Might be here because it's reserved, but capacity is normal. */
|
||||
|
@ -617,8 +613,7 @@ static void add_localchan(struct gossmap_localmods *mods,
|
|||
}
|
||||
|
||||
/* Known capacity on local channels (ts = max) */
|
||||
layer_update_constraint(info->local_layer, scidd, CONSTRAINT_MIN, UINT64_MAX, spendable);
|
||||
layer_update_constraint(info->local_layer, scidd, CONSTRAINT_MAX, UINT64_MAX, spendable);
|
||||
layer_update_constraint(info->local_layer, scidd, UINT64_MAX, &spendable, &spendable);
|
||||
}
|
||||
|
||||
static struct command_result *
|
||||
|
@ -838,16 +833,16 @@ static struct command_result *json_askrene_inform_channel(struct command *cmd,
|
|||
"Amount overflow with reserves");
|
||||
if (command_check_only(cmd))
|
||||
return command_check_done(cmd);
|
||||
c = layer_update_constraint(layer, scidd, CONSTRAINT_MAX,
|
||||
time_now().ts.tv_sec, *amount);
|
||||
c = layer_update_constraint(layer, scidd, time_now().ts.tv_sec,
|
||||
NULL, amount);
|
||||
goto output;
|
||||
case INFORM_UNCONSTRAINED:
|
||||
/* It passed, so the capacity is at least this much (minimal assumption is
|
||||
* that no reserves were used) */
|
||||
if (command_check_only(cmd))
|
||||
return command_check_done(cmd);
|
||||
c = layer_update_constraint(layer, scidd, CONSTRAINT_MIN,
|
||||
time_now().ts.tv_sec, *amount);
|
||||
c = layer_update_constraint(layer, scidd, time_now().ts.tv_sec,
|
||||
amount, NULL);
|
||||
goto output;
|
||||
case INFORM_SUCCEEDED:
|
||||
/* FIXME: We could do something useful here! */
|
||||
|
|
|
@ -74,4 +74,11 @@ static inline struct askrene *get_askrene(struct plugin *plugin)
|
|||
return plugin_get_data(plugin, struct askrene);
|
||||
}
|
||||
|
||||
/* Convenience routine for hash tables */
|
||||
static inline 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;
|
||||
}
|
||||
|
||||
#endif /* LIGHTNING_PLUGINS_ASKRENE_ASKRENE_H */
|
||||
|
|
|
@ -25,27 +25,20 @@ struct local_channel {
|
|||
} half[2];
|
||||
};
|
||||
|
||||
static const struct constraint_key *
|
||||
constraint_key(const struct constraint *c)
|
||||
static const struct short_channel_id_dir *
|
||||
constraint_scidd(const struct constraint *c)
|
||||
{
|
||||
return &c->key;
|
||||
return &c->scidd;
|
||||
}
|
||||
|
||||
static size_t hash_constraint_key(const struct constraint_key *key)
|
||||
static inline bool constraint_eq_scidd(const struct constraint *c,
|
||||
const struct short_channel_id_dir *scidd)
|
||||
{
|
||||
/* scids cost money to generate, so simple hash works here */
|
||||
return (key->scidd.scid.u64 >> 32) ^ (key->scidd.scid.u64)
|
||||
^ (key->scidd.dir << 1) ^ (key->type);
|
||||
return short_channel_id_dir_eq(scidd, &c->scidd);
|
||||
}
|
||||
|
||||
static inline bool constraint_eq_key(const struct constraint *c,
|
||||
const struct constraint_key *key)
|
||||
{
|
||||
return short_channel_id_dir_eq(&key->scidd, &c->key.scidd) && key->type == c->key.type;
|
||||
}
|
||||
|
||||
HTABLE_DEFINE_TYPE(struct constraint, constraint_key, hash_constraint_key,
|
||||
constraint_eq_key, constraint_hash);
|
||||
HTABLE_DEFINE_TYPE(struct constraint, constraint_scidd, hash_scidd,
|
||||
constraint_eq_scidd, constraint_hash);
|
||||
|
||||
static struct short_channel_id
|
||||
local_channel_scid(const struct local_channel *lc)
|
||||
|
@ -208,7 +201,7 @@ void layer_update_local_channel(struct layer *layer,
|
|||
* lookups. You can tell it's a fake one by the timestamp. */
|
||||
scidd.scid = scid;
|
||||
scidd.dir = dir;
|
||||
layer_update_constraint(layer, &scidd, CONSTRAINT_MAX, UINT64_MAX, capacity);
|
||||
layer_update_constraint(layer, &scidd, UINT64_MAX, NULL, &capacity);
|
||||
}
|
||||
|
||||
struct amount_msat local_channel_capacity(const struct local_channel *lc)
|
||||
|
@ -223,48 +216,41 @@ const struct local_channel *layer_find_local_channel(const struct layer *layer,
|
|||
}
|
||||
|
||||
static struct constraint *layer_find_constraint_nonconst(const struct layer *layer,
|
||||
const struct short_channel_id_dir *scidd,
|
||||
enum constraint_type type)
|
||||
const struct short_channel_id_dir *scidd)
|
||||
{
|
||||
struct constraint_key k = { *scidd, type };
|
||||
return constraint_hash_get(layer->constraints, &k);
|
||||
return constraint_hash_get(layer->constraints, scidd);
|
||||
}
|
||||
|
||||
/* Public one returns const */
|
||||
const struct constraint *layer_find_constraint(const struct layer *layer,
|
||||
const struct short_channel_id_dir *scidd,
|
||||
enum constraint_type type)
|
||||
const struct short_channel_id_dir *scidd)
|
||||
{
|
||||
return layer_find_constraint_nonconst(layer, scidd, type);
|
||||
return layer_find_constraint_nonconst(layer, scidd);
|
||||
}
|
||||
|
||||
const struct constraint *layer_update_constraint(struct layer *layer,
|
||||
const struct short_channel_id_dir *scidd,
|
||||
enum constraint_type type,
|
||||
u64 timestamp,
|
||||
struct amount_msat limit)
|
||||
const struct amount_msat *min,
|
||||
const struct amount_msat *max)
|
||||
{
|
||||
struct constraint *c = layer_find_constraint_nonconst(layer, scidd, type);
|
||||
struct constraint *c = layer_find_constraint_nonconst(layer, scidd);
|
||||
if (!c) {
|
||||
c = tal(layer, struct constraint);
|
||||
c->key.scidd = *scidd;
|
||||
c->key.type = type;
|
||||
c->limit = limit;
|
||||
c->scidd = *scidd;
|
||||
c->min = AMOUNT_MSAT(0);
|
||||
c->max = AMOUNT_MSAT(UINT64_MAX);
|
||||
constraint_hash_add(layer->constraints, c);
|
||||
} else {
|
||||
switch (type) {
|
||||
case CONSTRAINT_MIN:
|
||||
/* Increase minimum? */
|
||||
if (amount_msat_greater(limit, c->limit))
|
||||
c->limit = limit;
|
||||
break;
|
||||
case CONSTRAINT_MAX:
|
||||
/* Decrease maximum? */
|
||||
if (amount_msat_less(limit, c->limit))
|
||||
c->limit = limit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Increase minimum? */
|
||||
if (min && amount_msat_greater(*min, c->min))
|
||||
c->min = *min;
|
||||
|
||||
/* Decrease maximum? */
|
||||
if (max && amount_msat_less(*max, c->max))
|
||||
c->max = *max;
|
||||
|
||||
c->timestamp = timestamp;
|
||||
return c;
|
||||
}
|
||||
|
@ -279,7 +265,7 @@ void layer_clear_overridden_capacities(const struct layer *layer,
|
|||
for (con = constraint_hash_first(layer->constraints, &conit);
|
||||
con;
|
||||
con = constraint_hash_next(layer->constraints, &conit)) {
|
||||
struct gossmap_chan *c = gossmap_find_chan(gossmap, &con->key.scidd.scid);
|
||||
struct gossmap_chan *c = gossmap_find_chan(gossmap, &con->scidd.scid);
|
||||
size_t idx;
|
||||
if (!c)
|
||||
continue;
|
||||
|
@ -425,16 +411,12 @@ void json_add_constraint(struct json_stream *js,
|
|||
json_object_start(js, fieldname);
|
||||
if (layer)
|
||||
json_add_string(js, "layer", layer->name);
|
||||
json_add_short_channel_id_dir(js, "short_channel_id_dir", c->key.scidd);
|
||||
json_add_short_channel_id_dir(js, "short_channel_id_dir", c->scidd);
|
||||
json_add_u64(js, "timestamp", c->timestamp);
|
||||
switch (c->key.type) {
|
||||
case CONSTRAINT_MIN:
|
||||
json_add_amount_msat(js, "minimum_msat", c->limit);
|
||||
break;
|
||||
case CONSTRAINT_MAX:
|
||||
json_add_amount_msat(js, "maximum_msat", c->limit);
|
||||
break;
|
||||
}
|
||||
if (!amount_msat_is_zero(c->min))
|
||||
json_add_amount_msat(js, "minimum_msat", c->min);
|
||||
if (!amount_msat_eq(c->max, AMOUNT_MSAT(UINT64_MAX)))
|
||||
json_add_amount_msat(js, "maximum_msat", c->max);
|
||||
json_object_end(js);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,22 +17,15 @@ struct askrene;
|
|||
struct layer;
|
||||
struct json_stream;
|
||||
|
||||
enum constraint_type {
|
||||
CONSTRAINT_MIN,
|
||||
CONSTRAINT_MAX,
|
||||
};
|
||||
|
||||
struct constraint_key {
|
||||
struct short_channel_id_dir scidd;
|
||||
enum constraint_type type;
|
||||
};
|
||||
|
||||
/* A constraint reflects something we learned about a channel */
|
||||
struct constraint {
|
||||
struct constraint_key key;
|
||||
struct short_channel_id_dir scidd;
|
||||
/* Time this constraint was last updated */
|
||||
u64 timestamp;
|
||||
struct amount_msat limit;
|
||||
/* Non-zero means set */
|
||||
struct amount_msat min;
|
||||
/* Non-0xFFFFF.... means set */
|
||||
struct amount_msat max;
|
||||
};
|
||||
|
||||
/* Look up a layer by name. */
|
||||
|
@ -80,15 +73,14 @@ void layer_clear_overridden_capacities(const struct layer *layer,
|
|||
|
||||
/* Find a constraint in a layer. */
|
||||
const struct constraint *layer_find_constraint(const struct layer *layer,
|
||||
const struct short_channel_id_dir *scidd,
|
||||
enum constraint_type type);
|
||||
const struct short_channel_id_dir *scidd);
|
||||
|
||||
/* Add/update a constraint on a layer. */
|
||||
/* Add/update one or more constraints on a layer. */
|
||||
const struct constraint *layer_update_constraint(struct layer *layer,
|
||||
const struct short_channel_id_dir *scidd,
|
||||
enum constraint_type type,
|
||||
u64 timestamp,
|
||||
struct amount_msat limit);
|
||||
const struct amount_msat *min,
|
||||
const struct amount_msat *max);
|
||||
|
||||
/* Add local channels from this layer. zero_cost means set fees and delay to 0. */
|
||||
void layer_add_localmods(const struct layer *layer,
|
||||
|
|
|
@ -25,12 +25,6 @@ reserve_scidd(const struct reserve *r)
|
|||
return &r->rhop.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)
|
||||
{
|
||||
|
|
|
@ -161,7 +161,9 @@ def test_layers(node_factory):
|
|||
100000,
|
||||
'unconstrained')
|
||||
last_timestamp = int(time.time()) + 1
|
||||
# Maximum for created channels is the real capacity.
|
||||
expect['constraints'].append({'short_channel_id_dir': '0x0x1/1',
|
||||
'maximum_msat': 1000000000,
|
||||
'minimum_msat': 100000})
|
||||
# Check timestamp first.
|
||||
listlayers = l2.rpc.askrene_listlayers('test_layers')
|
||||
|
|
Loading…
Add table
Reference in a new issue