liquidity-ads: pipe through request to funder, update policy

When a request comes through, we forward it over to the funder who
uses the currently set policy to figure out how to handle it.

Includes small update to the policy engine which decides whether or not
to fund a request.

Changelog-Experimental: Plugins: `openchannel2` hook now includes optional fields for a channel lease request
This commit is contained in:
niftynei
2021-06-08 16:42:45 -05:00
committed by neil saitug
parent 3a7b3762a1
commit f1b7e5fffe
9 changed files with 239 additions and 4 deletions

View File

@@ -282,6 +282,9 @@ struct open_info {
struct amount_sat channel_max;
u64 funding_feerate_perkw;
u32 locktime;
u32 lease_blockheight;
u32 node_blockheight;
struct amount_sat requested_lease;
};
static struct command_result *
@@ -322,6 +325,11 @@ psbt_funded(struct command *cmd,
json_add_amount_msat_only(response, "our_funding_msat",
our_funding_msat);
/* If we're accepting an lease request, *and* they've
* requested one, fill in our most recent infos */
if (current_policy->rates && !amount_sat_zero(info->requested_lease))
json_add_lease_rates(response, current_policy->rates);
return command_finished(cmd, response);
}
@@ -419,6 +427,7 @@ listfunds_success(struct command *cmd,
info->their_funding,
available_funds,
info->channel_max,
info->requested_lease,
&info->our_funding);
plugin_log(cmd->plugin, LOG_DBG,
"Policy %s returned funding amount of %s. %s",
@@ -531,6 +540,21 @@ json_openchannel2_call(struct command *cmd,
err, json_tok_full_len(params),
json_tok_full(buf, params));
err = json_scan(tmpctx, buf, params,
"{openchannel2:{"
"requested_lease_msat:%"
",lease_blockheight_start:%"
",node_blockheight:%}}",
JSON_SCAN(json_to_sat, &info->requested_lease),
JSON_SCAN(json_to_u32, &info->node_blockheight),
JSON_SCAN(json_to_u32, &info->lease_blockheight));
/* These aren't necessarily included */
if (err) {
info->requested_lease = AMOUNT_SAT(0);
info->node_blockheight = 0;
info->lease_blockheight = 0;
}
/* If there's no channel_max, it's actually infinity */
err = json_scan(tmpctx, buf, params,
@@ -553,6 +577,40 @@ json_openchannel2_call(struct command *cmd,
return command_hook_success(cmd);
}
/* Check that their block height isn't too far behind */
if (!amount_sat_zero(info->requested_lease)) {
u32 upper_bound, lower_bound;
/* BOLT- #2:
* The receiving node:
* - MAY fail the negotiation if: ...
* - if the `option_will_fund` tlv is present and:
* - the `blockheight` is considered too far in the
* past or future
*/
/* We consider 24 hrs too far out */
upper_bound = info->node_blockheight + 24 * 6;
lower_bound = info->node_blockheight - 24 * 6;
/* Check overflow */
if (upper_bound < info->node_blockheight)
upper_bound = -1;
if (lower_bound > info->node_blockheight)
lower_bound = 0;
if (upper_bound < info->lease_blockheight
|| lower_bound > info->lease_blockheight) {
plugin_log(cmd->plugin, LOG_DBG,
"their blockheight %d is out of"
" our bounds (ours is %d)",
info->lease_blockheight,
info->node_blockheight);
return command_hook_success(cmd);
}
}
/* Figure out what our funds are */
req = jsonrpc_request_start(cmd->plugin, cmd,
"listfunds",

View File

@@ -174,12 +174,17 @@ apply_fuzz(u32 fuzz_factor, struct amount_sat val)
static struct amount_sat
apply_policy(struct funder_policy *policy,
struct amount_sat their_funding,
struct amount_sat requested_lease,
struct amount_sat available_funds)
{
struct amount_sat our_funding;
switch (policy->opt) {
case MATCH:
/* For matches, we use requested funding, if availalbe */
if (!amount_sat_zero(requested_lease))
their_funding = requested_lease;
/* if this fails, it implies ludicrous funding offer, *and*
* > 100% match. Just Say No, kids. */
if (!amount_sat_scale(&our_funding, their_funding,
@@ -207,12 +212,23 @@ calculate_our_funding(struct funder_policy *policy,
struct amount_sat their_funding,
struct amount_sat available_funds,
struct amount_sat channel_max,
struct amount_sat requested_lease,
struct amount_sat *our_funding)
{
struct amount_sat avail_channel_space, net_available_funds;
/* Are we only funding lease requests ? */
if (policy->leases_only && amount_sat_zero(requested_lease)) {
*our_funding = AMOUNT_SAT(0);
return tal_fmt(tmpctx,
"Skipping funding open; leases-only=true"
" and this open isn't asking for a lease");
}
/* Are we skipping this one? */
if (pseudorand(100) >= policy->fund_probability) {
if (pseudorand(100) >= policy->fund_probability
/* We don't skip lease requests */
&& amount_sat_zero(requested_lease)) {
*our_funding = AMOUNT_SAT(0);
return tal_fmt(tmpctx,
"Skipping, failed fund_probability test");
@@ -269,7 +285,10 @@ calculate_our_funding(struct funder_policy *policy,
}
/* What's our amount, given our policy */
*our_funding = apply_policy(policy, their_funding, available_funds);
*our_funding = apply_policy(policy,
their_funding,
requested_lease,
available_funds);
/* Don't return an 'error' if we're already at 0 */
if (amount_sat_zero(*our_funding))

View File

@@ -9,7 +9,7 @@ struct node_id;
/* Policy Options */
enum funder_opt {
/* Use their_funding as the starting
/* Use their_funding/requested_amt as the starting
* point for your contribution */
MATCH,
@@ -96,6 +96,7 @@ calculate_our_funding(struct funder_policy *policy,
struct amount_sat their_funding,
struct amount_sat available_funds,
struct amount_sat channel_max,
struct amount_sat lease_request,
struct amount_sat *our_funding);
/* Get the name of this policy option */

View File

@@ -33,6 +33,7 @@ struct test_case {
struct amount_sat their_funds;
struct amount_sat available_funds;
struct amount_sat channel_max;
struct amount_sat lease_request;
struct funder_policy policy;
@@ -46,6 +47,7 @@ struct test_case cases[] = {
.their_funds = AMOUNT_SAT(5000),
.available_funds = AMOUNT_SAT(100000),
.channel_max = AMOUNT_SAT(11000),
.lease_request = AMOUNT_SAT(0),
.policy = {
.opt = FIXED,
.mod = 1111,
@@ -56,6 +58,7 @@ struct test_case cases[] = {
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(0),
.fund_probability = 100,
.leases_only = false,
},
.exp_our_funds = AMOUNT_SAT(1111),
@@ -66,6 +69,7 @@ struct test_case cases[] = {
.their_funds = AMOUNT_SAT(5000),
.available_funds = AMOUNT_SAT(500),
.channel_max = AMOUNT_SAT(11000),
.lease_request = AMOUNT_SAT(0),
.policy = {
.opt = MATCH,
.mod = 0,
@@ -76,6 +80,7 @@ struct test_case cases[] = {
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(0),
.fund_probability = 100,
.leases_only = false,
},
.exp_our_funds = AMOUNT_SAT(0),
@@ -86,6 +91,7 @@ struct test_case cases[] = {
.their_funds = AMOUNT_SAT(5000),
.available_funds = AMOUNT_SAT(6000),
.channel_max = AMOUNT_SAT(11000),
.lease_request = AMOUNT_SAT(0),
.policy = {
.opt = MATCH,
.mod = 100,
@@ -96,6 +102,7 @@ struct test_case cases[] = {
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(0),
.fund_probability = 100,
.leases_only = false,
},
.exp_our_funds = AMOUNT_SAT(5000),
@@ -106,6 +113,7 @@ struct test_case cases[] = {
.their_funds = AMOUNT_SAT(2500),
.available_funds = AMOUNT_SAT(6000),
.channel_max = AMOUNT_SAT(11000),
.lease_request = AMOUNT_SAT(0),
.policy = {
.opt = MATCH,
.mod = 200,
@@ -116,6 +124,7 @@ struct test_case cases[] = {
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(0),
.fund_probability = 100,
.leases_only = false,
},
.exp_our_funds = AMOUNT_SAT(5000),
@@ -126,6 +135,7 @@ struct test_case cases[] = {
.their_funds = AMOUNT_SAT(2500),
.available_funds = AMOUNT_SAT(5000),
.channel_max = AMOUNT_SAT(11000),
.lease_request = AMOUNT_SAT(0),
.policy = {
.opt = AVAILABLE,
.mod = 0,
@@ -136,6 +146,7 @@ struct test_case cases[] = {
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(0),
.fund_probability = 100,
.leases_only = false,
},
.exp_our_funds = AMOUNT_SAT(0),
@@ -146,6 +157,7 @@ struct test_case cases[] = {
.their_funds = AMOUNT_SAT(2500),
.available_funds = AMOUNT_SAT(3000),
.channel_max = AMOUNT_SAT(11000),
.lease_request = AMOUNT_SAT(0),
.policy = {
.opt = AVAILABLE,
.mod = 50,
@@ -156,6 +168,7 @@ struct test_case cases[] = {
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(0),
.fund_probability = 100,
.leases_only = false,
},
.exp_our_funds = AMOUNT_SAT(1500),
@@ -166,6 +179,7 @@ struct test_case cases[] = {
.their_funds = AMOUNT_SAT(2500),
.available_funds = AMOUNT_SAT(5000),
.channel_max = AMOUNT_SAT(11000),
.lease_request = AMOUNT_SAT(0),
.policy = {
.opt = AVAILABLE,
.mod = 100,
@@ -176,6 +190,7 @@ struct test_case cases[] = {
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(0),
.fund_probability = 100,
.leases_only = false,
},
.exp_our_funds = AMOUNT_SAT(5000),
@@ -198,6 +213,7 @@ struct test_case cases[] = {
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(0),
.fund_probability = 100,
.leases_only = false,
},
.exp_our_funds = AMOUNT_SAT(900),
@@ -208,6 +224,7 @@ struct test_case cases[] = {
.their_funds = AMOUNT_SAT(5000),
.available_funds = AMOUNT_SAT(5000),
.channel_max = AMOUNT_SAT(5500),
.lease_request = AMOUNT_SAT(0),
.policy = {
.opt = FIXED,
.mod = 1002,
@@ -218,6 +235,7 @@ struct test_case cases[] = {
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(0),
.fund_probability = 100,
.leases_only = false,
},
.exp_our_funds = AMOUNT_SAT(500),
@@ -228,6 +246,7 @@ struct test_case cases[] = {
.their_funds = AMOUNT_SAT(5000),
.available_funds = AMOUNT_SAT(500),
.channel_max = AMOUNT_SAT(10000),
.lease_request = AMOUNT_SAT(0),
.policy = {
.opt = FIXED,
.mod = 1001,
@@ -238,6 +257,7 @@ struct test_case cases[] = {
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(0),
.fund_probability = 100,
.leases_only = false,
},
.exp_our_funds = AMOUNT_SAT(500),
@@ -248,6 +268,7 @@ struct test_case cases[] = {
.their_funds = AMOUNT_SAT(5000),
.available_funds = AMOUNT_SAT(1000),
.channel_max = AMOUNT_SAT(10000),
.lease_request = AMOUNT_SAT(0),
.policy = {
.opt = FIXED,
.mod = 999,
@@ -258,6 +279,7 @@ struct test_case cases[] = {
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(0),
.fund_probability = 100,
.leases_only = false,
},
.exp_our_funds = AMOUNT_SAT(0),
@@ -268,6 +290,7 @@ struct test_case cases[] = {
.their_funds = AMOUNT_SAT(5001),
.available_funds = AMOUNT_SAT(5000),
.channel_max = AMOUNT_SAT(10000),
.lease_request = AMOUNT_SAT(0),
.policy = {
.opt = FIXED,
.mod = 998,
@@ -278,6 +301,7 @@ struct test_case cases[] = {
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(0),
.fund_probability = 100,
.leases_only = false,
},
.exp_our_funds = AMOUNT_SAT(0),
@@ -288,6 +312,7 @@ struct test_case cases[] = {
.their_funds = AMOUNT_SAT(5000),
.available_funds = AMOUNT_SAT(1000),
.channel_max = AMOUNT_SAT(10000),
.lease_request = AMOUNT_SAT(0),
.policy = {
.opt = FIXED,
.mod = 997,
@@ -298,6 +323,7 @@ struct test_case cases[] = {
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(100),
.fund_probability = 100,
.leases_only = false,
},
.exp_our_funds = AMOUNT_SAT(900),
@@ -308,6 +334,7 @@ struct test_case cases[] = {
.their_funds = AMOUNT_SAT(5000),
.available_funds = AMOUNT_SAT(999),
.channel_max = AMOUNT_SAT(10000),
.lease_request = AMOUNT_SAT(0),
.policy = {
.opt = FIXED,
.mod = 996,
@@ -318,6 +345,7 @@ struct test_case cases[] = {
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(1000),
.fund_probability = 100,
.leases_only = false,
},
.exp_our_funds = AMOUNT_SAT(0),
@@ -328,6 +356,7 @@ struct test_case cases[] = {
.their_funds = AMOUNT_SAT(5000),
.available_funds = AMOUNT_SAT(5000),
.channel_max = AMOUNT_SAT(5000),
.lease_request = AMOUNT_SAT(0),
.policy = {
.opt = FIXED,
.mod = 995,
@@ -338,6 +367,7 @@ struct test_case cases[] = {
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(1000),
.fund_probability = 100,
.leases_only = false,
},
.exp_our_funds = AMOUNT_SAT(0),
@@ -348,6 +378,7 @@ struct test_case cases[] = {
.their_funds = AMOUNT_SAT(5000),
.available_funds = AMOUNT_SAT(5000),
.channel_max = AMOUNT_SAT(11000),
.lease_request = AMOUNT_SAT(0),
.policy = {
.opt = FIXED,
.mod = 988,
@@ -358,6 +389,51 @@ struct test_case cases[] = {
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(0),
.fund_probability = 100,
.leases_only = false,
},
.exp_our_funds = AMOUNT_SAT(0),
.expect_err = true,
},
/* By default, use lease request as ceiling */
{
.their_funds = AMOUNT_SAT(5000),
.available_funds = AMOUNT_SAT(100000),
.channel_max = AMOUNT_SAT(11000),
.lease_request = AMOUNT_SAT(980),
.policy = {
.opt = MATCH,
.mod = 100,
.min_their_funding = AMOUNT_SAT(0),
.max_their_funding = AMOUNT_SAT(10000),
.per_channel_max = AMOUNT_SAT(100000),
.per_channel_min = AMOUNT_SAT(0),
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(0),
.fund_probability = 100,
.leases_only = false,
},
.exp_our_funds = AMOUNT_SAT(980),
.expect_err = false,
},
/* Only fund lease requests */
{
.their_funds = AMOUNT_SAT(5000),
.available_funds = AMOUNT_SAT(100000),
.channel_max = AMOUNT_SAT(11000),
.lease_request = AMOUNT_SAT(0),
.policy = {
.opt = FIXED,
.mod = 985,
.min_their_funding = AMOUNT_SAT(0),
.max_their_funding = AMOUNT_SAT(10000),
.per_channel_max = AMOUNT_SAT(100000),
.per_channel_min = AMOUNT_SAT(0),
.fuzz_factor = 0,
.reserve_tank = AMOUNT_SAT(0),
.fund_probability = 100,
.leases_only = true,
},
.exp_our_funds = AMOUNT_SAT(0),
@@ -380,6 +456,7 @@ static void check_fuzzing(struct test_case fuzzcase)
fuzzcase.their_funds,
fuzzcase.available_funds,
fuzzcase.channel_max,
fuzzcase.lease_request,
&our_funds);
if (amount_sat_greater(our_funds, fuzz_max))
fuzz_max = our_funds;
@@ -412,6 +489,7 @@ int main(int argc, const char *argv[])
AMOUNT_SAT(50000),
AMOUNT_SAT(50000),
AMOUNT_SAT(100000),
AMOUNT_SAT(0),
&our_funds);
assert(amount_sat_eq(empty, our_funds));
assert(!err);
@@ -421,6 +499,7 @@ int main(int argc, const char *argv[])
cases[i].their_funds,
cases[i].available_funds,
cases[i].channel_max,
cases[i].lease_request,
&our_funds);
if (!amount_sat_eq(cases[i].exp_our_funds, our_funds)) {
fprintf(stderr, "FAIL policy: %s. expected %s, got %s\n",
@@ -454,6 +533,7 @@ int main(int argc, const char *argv[])
flipcase.their_funds,
flipcase.available_funds,
flipcase.channel_max,
flipcase.lease_request,
&our_funds);
if (!amount_sat_eq(our_funds, AMOUNT_SAT(0)))
flipcount++;