Skip to content

Commit

Permalink
queryrates: make it dev-only
Browse files Browse the repository at this point in the history
Since we now use 'compact_lease' to gate an open (if the rates have
changed, we fail), we no longer need to rely on query rates for figuring
things out, so we make it dev-only.

Changelog-Changed: JSON-API: queryrates is now developer only
  • Loading branch information
niftynei committed Jul 9, 2021
1 parent f2857a2 commit 030d954
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 112 deletions.
4 changes: 2 additions & 2 deletions contrib/pyln-client/pyln/client/lightning.py
Original file line number Diff line number Diff line change
Expand Up @@ -1019,7 +1019,7 @@ def pay(self, bolt11, msatoshi=None, label=None, riskfactor=None,
}
return self.call("pay", payload)

def queryrates(self, node_id, channel_amount, request_amt, commitment_feerate=None, funding_feerate=None):
def dev_queryrates(self, node_id, channel_amount, request_amt, commitment_feerate=None, funding_feerate=None):
"""Ask a peer how much they'd charge for a given liquidity amount """
payload = {
"id": node_id,
Expand All @@ -1028,7 +1028,7 @@ def queryrates(self, node_id, channel_amount, request_amt, commitment_feerate=No
"commitment_feerate": commitment_feerate,
"funding_feerate": funding_feerate,
}
return self.call("queryrates", payload)
return self.call("dev-queryrates", payload)

def openchannel_init(self, node_id, channel_amount, psbt, feerate=None, funding_feerate=None, announce=True, close_to=None, request_amt=None, *args, **kwargs):
"""Initiate an openchannel with a peer """
Expand Down
2 changes: 1 addition & 1 deletion contrib/startup_regtest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ start_nodes() {

# Start the lightning nodes
test -f "/tmp/l$i-$network/lightningd-$network.pid" || \
"$LIGHTNINGD" "--lightning-dir=/tmp/l$i-$network" --daemon
"$LIGHTNINGD" "--lightning-dir=/tmp/l$i-$network" &
# shellcheck disable=SC2139 disable=SC2086
alias l$i-cli="$LCLI --lightning-dir=/tmp/l$i-$network"
# shellcheck disable=SC2139 disable=SC2086
Expand Down
207 changes: 105 additions & 102 deletions lightningd/dual_open_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -2490,106 +2490,6 @@ static struct command_result *init_set_feerate(struct command *cmd,
return NULL;
}

static struct command_result *json_queryrates(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
struct node_id *id;
struct peer *peer;
struct channel *channel;
u32 *feerate_per_kw_funding;
u32 *feerate_per_kw;
struct amount_sat *amount, *request_amt;
struct wally_psbt *psbt;
struct open_attempt *oa;
u8 *msg;
struct command_result *res;

if (!param(cmd, buffer, params,
p_req("id", param_node_id, &id),
p_req("amount", param_sat, &amount),
p_req("request_amt", param_sat, &request_amt),
p_opt("commitment_feerate", param_feerate, &feerate_per_kw),
p_opt("funding_feerate", param_feerate, &feerate_per_kw_funding),
NULL))
return command_param_failed();

res = init_set_feerate(cmd, &feerate_per_kw, &feerate_per_kw_funding);
if (res)
return res;

peer = peer_by_id(cmd->ld, id);
if (!peer) {
return command_fail(cmd, FUNDING_UNKNOWN_PEER, "Unknown peer");
}

/* We can't query rates for a peer we have a channel with */
channel = peer_active_channel(peer);
if (channel)
return command_fail(cmd, LIGHTNINGD, "Peer in state %s,"
" can't query peer's rates if already"
" have a channel",
channel_state_name(channel));

channel = peer_unsaved_channel(peer);
if (!channel || !channel->owner)
return command_fail(cmd, FUNDING_PEER_NOT_CONNECTED,
"Peer not connected");
if (channel->open_attempt
|| !list_empty(&channel->inflights))
return command_fail(cmd, FUNDING_STATE_INVALID,
"Channel funding in-progress. %s",
channel_state_name(channel));

if (!feature_negotiated(cmd->ld->our_features,
peer->their_features,
OPT_DUAL_FUND)) {
return command_fail(cmd, FUNDING_V2_NOT_SUPPORTED,
"v2 openchannel not supported "
"by peer, can't query rates");
}

/* BOLT #2:
* - if both nodes advertised `option_support_large_channel`:
* - MAY set `funding_satoshis` greater than or equal to 2^24 satoshi.
* - otherwise:
* - MUST set `funding_satoshis` to less than 2^24 satoshi.
*/
if (!feature_negotiated(cmd->ld->our_features,
peer->their_features, OPT_LARGE_CHANNELS)
&& amount_sat_greater(*amount, chainparams->max_funding))
return command_fail(cmd, FUND_MAX_EXCEEDED,
"Amount exceeded %s",
type_to_string(tmpctx, struct amount_sat,
&chainparams->max_funding));

/* Get a new open_attempt going, keeps us from re-initing
* while looking */
channel->opener = LOCAL;
channel->open_attempt = oa = new_channel_open_attempt(channel);
channel->channel_flags = OUR_CHANNEL_FLAGS;
oa->funding = *amount;
oa->cmd = cmd;
/* empty psbt to start */
psbt = create_psbt(tmpctx, 0, 0, 0);

msg = towire_dualopend_opener_init(NULL,
psbt, *amount,
oa->our_upfront_shutdown_script,
*feerate_per_kw,
*feerate_per_kw_funding,
channel->channel_flags,
*request_amt,
get_block_height(cmd->ld->topology),
true,
NULL);

subd_send_msg(channel->owner, take(msg));
return command_still_pending(cmd);

}

static struct command_result *json_openchannel_init(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
Expand Down Expand Up @@ -3120,14 +3020,118 @@ static unsigned int dual_opend_msg(struct subd *dualopend,
return 0;
}

#if DEVELOPER
static struct command_result *json_queryrates(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
struct node_id *id;
struct peer *peer;
struct channel *channel;
u32 *feerate_per_kw_funding;
u32 *feerate_per_kw;
struct amount_sat *amount, *request_amt;
struct wally_psbt *psbt;
struct open_attempt *oa;
u8 *msg;
struct command_result *res;

if (!param(cmd, buffer, params,
p_req("id", param_node_id, &id),
p_req("amount", param_sat, &amount),
p_req("request_amt", param_sat, &request_amt),
p_opt("commitment_feerate", param_feerate, &feerate_per_kw),
p_opt("funding_feerate", param_feerate, &feerate_per_kw_funding),
NULL))
return command_param_failed();

res = init_set_feerate(cmd, &feerate_per_kw, &feerate_per_kw_funding);
if (res)
return res;

peer = peer_by_id(cmd->ld, id);
if (!peer) {
return command_fail(cmd, FUNDING_UNKNOWN_PEER, "Unknown peer");
}

/* We can't query rates for a peer we have a channel with */
channel = peer_active_channel(peer);
if (channel)
return command_fail(cmd, LIGHTNINGD, "Peer in state %s,"
" can't query peer's rates if already"
" have a channel",
channel_state_name(channel));

channel = peer_unsaved_channel(peer);
if (!channel || !channel->owner)
return command_fail(cmd, FUNDING_PEER_NOT_CONNECTED,
"Peer not connected");
if (channel->open_attempt
|| !list_empty(&channel->inflights))
return command_fail(cmd, FUNDING_STATE_INVALID,
"Channel funding in-progress. %s",
channel_state_name(channel));

if (!feature_negotiated(cmd->ld->our_features,
peer->their_features,
OPT_DUAL_FUND)) {
return command_fail(cmd, FUNDING_V2_NOT_SUPPORTED,
"v2 openchannel not supported "
"by peer, can't query rates");
}

/* BOLT #2:
* - if both nodes advertised `option_support_large_channel`:
* - MAY set `funding_satoshis` greater than or equal to 2^24 satoshi.
* - otherwise:
* - MUST set `funding_satoshis` to less than 2^24 satoshi.
*/
if (!feature_negotiated(cmd->ld->our_features,
peer->their_features, OPT_LARGE_CHANNELS)
&& amount_sat_greater(*amount, chainparams->max_funding))
return command_fail(cmd, FUND_MAX_EXCEEDED,
"Amount exceeded %s",
type_to_string(tmpctx, struct amount_sat,
&chainparams->max_funding));

/* Get a new open_attempt going, keeps us from re-initing
* while looking */
channel->opener = LOCAL;
channel->open_attempt = oa = new_channel_open_attempt(channel);
channel->channel_flags = OUR_CHANNEL_FLAGS;
oa->funding = *amount;
oa->cmd = cmd;
/* empty psbt to start */
psbt = create_psbt(tmpctx, 0, 0, 0);

msg = towire_dualopend_opener_init(NULL,
psbt, *amount,
oa->our_upfront_shutdown_script,
*feerate_per_kw,
*feerate_per_kw_funding,
channel->channel_flags,
*request_amt,
get_block_height(cmd->ld->topology),
true,
NULL);

subd_send_msg(channel->owner, take(msg));
return command_still_pending(cmd);

}

static const struct json_command queryrates_command = {
"queryrates",
"dev-queryrates",
"channels",
json_queryrates,
"Ask a peer what their contribution and liquidity rates are"
" for the given {amount} and {requested_amt}"
};

AUTODATA(json_command, &queryrates_command);
#endif /* DEVELOPER */

static const struct json_command openchannel_init_command = {
"openchannel_init",
"channels",
Expand Down Expand Up @@ -3166,7 +3170,6 @@ static const struct json_command openchannel_abort_command = {
"Abort {channel_id}'s open. Usable while `commitment_signed=false`."
};

AUTODATA(json_command, &queryrates_command);
AUTODATA(json_command, &openchannel_init_command);
AUTODATA(json_command, &openchannel_update_command);
AUTODATA(json_command, &openchannel_signed_command);
Expand Down
14 changes: 9 additions & 5 deletions tests/test_closing.py
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,7 @@ def calc_lease_fee(amt, feerate, rates):
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
@pytest.mark.openchannel('v2')
@pytest.mark.slow_test
@pytest.mark.developer("requres 'dev-queryrates'")
def test_channel_lease_falls_behind(node_factory, bitcoind):
'''
If our peer falls too far behind/doesn't send us an update for
Expand All @@ -745,7 +746,7 @@ def test_channel_lease_falls_behind(node_factory, bitcoind):
l2.fundwallet(20000000)

l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
rates = l1.rpc.queryrates(l2.info['id'], amount, amount)
rates = l1.rpc.dev_queryrates(l2.info['id'], amount, amount)
l1.daemon.wait_for_log('disconnect')
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
# l1 leases a channel from l2
Expand All @@ -768,6 +769,7 @@ def test_channel_lease_falls_behind(node_factory, bitcoind):

@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
@pytest.mark.openchannel('v2')
@pytest.mark.developer("requres 'dev-queryrates'")
@pytest.mark.slow_test
def test_channel_lease_post_expiry(node_factory, bitcoind):

Expand Down Expand Up @@ -868,7 +870,7 @@ def test_channel_lease_unilat_closes(node_factory, bitcoind):
l3.fundwallet(20000000)

l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
rates = l1.rpc.queryrates(l2.info['id'], amount, amount)
rates = l1.rpc.dev_queryrates(l2.info['id'], amount, amount)
l1.daemon.wait_for_log('disconnect')
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
# l1 leases a channel from l2
Expand All @@ -878,7 +880,7 @@ def test_channel_lease_unilat_closes(node_factory, bitcoind):

# l2 leases a channel from l3
l2.rpc.connect(l3.info['id'], 'localhost', l3.port)
rates = l2.rpc.queryrates(l3.info['id'], amount, amount)
rates = l2.rpc.dev_queryrates(l3.info['id'], amount, amount)
l3.daemon.wait_for_log('disconnect')
l2.rpc.connect(l3.info['id'], 'localhost', l3.port)
l2.rpc.fundchannel(l3.info['id'], amount, request_amt=amount,
Expand Down Expand Up @@ -949,6 +951,7 @@ def test_channel_lease_unilat_closes(node_factory, bitcoind):
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
@pytest.mark.openchannel('v2')
@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "Makes use of the sqlite3 db")
@pytest.mark.developer("requres 'dev-queryrates'")
def test_channel_lease_lessor_cheat(node_factory, bitcoind, chainparams):
'''
Check that lessee can recover funds if lessor cheats
Expand All @@ -966,7 +969,7 @@ def test_channel_lease_lessor_cheat(node_factory, bitcoind, chainparams):
l2.fundwallet(20000000)

l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
rates = l1.rpc.queryrates(l2.info['id'], amount, amount)
rates = l1.rpc.dev_queryrates(l2.info['id'], amount, amount)
l1.daemon.wait_for_log('disconnect')
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
# l1 leases a channel from l2
Expand Down Expand Up @@ -1021,6 +1024,7 @@ def test_channel_lease_lessor_cheat(node_factory, bitcoind, chainparams):
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
@pytest.mark.openchannel('v2')
@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "Makes use of the sqlite3 db")
@pytest.mark.developer("requres 'dev-queryrates'")
def test_channel_lease_lessee_cheat(node_factory, bitcoind, chainparams):
'''
Check that lessor can recover funds if lessee cheats
Expand All @@ -1038,7 +1042,7 @@ def test_channel_lease_lessee_cheat(node_factory, bitcoind, chainparams):
l2.fundwallet(20000000)

l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
rates = l1.rpc.queryrates(l2.info['id'], amount, amount)
rates = l1.rpc.dev_queryrates(l2.info['id'], amount, amount)
l1.daemon.wait_for_log('disconnect')
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
# l1 leases a channel from l2
Expand Down
5 changes: 3 additions & 2 deletions tests/test_opening.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def find_next_feerate(node, peer):

@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
@pytest.mark.openchannel('v2')
@pytest.mark.developer("requres 'dev-queryrates'")
def test_queryrates(node_factory, bitcoind):
l1, l2 = node_factory.get_nodes(2)

Expand All @@ -27,7 +28,7 @@ def test_queryrates(node_factory, bitcoind):

l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
with pytest.raises(RpcError, match=r'not advertising liquidity'):
l1.rpc.queryrates(l2.info['id'], amount, amount * 10)
l1.rpc.dev_queryrates(l2.info['id'], amount, amount * 10)

l2.rpc.call('funderupdate', {'policy': 'match',
'policy_mod': 100,
Expand All @@ -40,7 +41,7 @@ def test_queryrates(node_factory, bitcoind):
'channel_fee_max_proportional_thousandths': 101})

l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
result = l1.rpc.queryrates(l2.info['id'], amount, amount)
result = l1.rpc.dev_queryrates(l2.info['id'], amount, amount)
assert result['our_funding_msat'] == Millisatoshi(amount * 1000)
assert result['their_funding_msat'] == Millisatoshi(amount * 1000)
assert result['funding_weight'] == 1000
Expand Down

0 comments on commit 030d954

Please sign in to comment.