mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 07:04:22 +01:00
fundchannel / withdraw: allow explicit feerate setting.
These are the two cases where we'll refuse without a fee estimate. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
e2d4b7cc8d
commit
14dc1c37ab
@@ -22,6 +22,7 @@ This release named by ZmnSCPxj.
|
||||
- JSON API: `ping` command to send a ping to a connected peer.
|
||||
- JSON API: `feerates` command to inject fee estimates manually, and retrieve
|
||||
current estimates.
|
||||
- JSON API: `withdraw` and `fundchannel` can be given manual feerate.
|
||||
- Config: `--conf` option to set config file.
|
||||
- Documentation: Added CHANGELOG.md
|
||||
- pylightning: RpcError now has `method` and `payload` fields.
|
||||
|
||||
@@ -331,13 +331,15 @@ class LightningRpc(UnixDomainSocketRpc):
|
||||
}
|
||||
return self.call("listpeers", payload)
|
||||
|
||||
def fundchannel(self, node_id, satoshi):
|
||||
def fundchannel(self, node_id, satoshi, feerate=None, feeratestyle=None):
|
||||
"""
|
||||
Fund channel with {id} using {satoshi} satoshis"
|
||||
"""
|
||||
payload = {
|
||||
"id": node_id,
|
||||
"satoshi": satoshi
|
||||
"satoshi": satoshi,
|
||||
"feerate": feerate,
|
||||
"feeratestyle": feeratestyle
|
||||
}
|
||||
return self.call("fundchannel", payload)
|
||||
|
||||
@@ -404,14 +406,16 @@ class LightningRpc(UnixDomainSocketRpc):
|
||||
"""
|
||||
return self.call("dev-memleak")
|
||||
|
||||
def withdraw(self, destination, satoshi):
|
||||
def withdraw(self, destination, satoshi, feerate=None, feeratestyle=None):
|
||||
"""
|
||||
Send to {destination} address {satoshi} (or "all")
|
||||
amount via Bitcoin transaction
|
||||
"""
|
||||
payload = {
|
||||
"destination": destination,
|
||||
"satoshi": satoshi
|
||||
"satoshi": satoshi,
|
||||
"feerate": feerate,
|
||||
"feeratestyle": feeratestyle
|
||||
}
|
||||
return self.call("withdraw", payload)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ lightning-fundchannel - Command for establishing a lightning channel.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
*fundchannel* 'id' 'satoshi'
|
||||
*fundchannel* 'id' 'satoshi' ['feerate' 'feeratestyle']
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -27,6 +27,11 @@ The string 'all' can be used to specify all available funds (or 16777215 satoshi
|
||||
The value cannot be less than the dust limit, currently set to 546, nor more
|
||||
than 16777215 satoshi.
|
||||
|
||||
'feerate' is an optional feerate to use, overriding lightningd's
|
||||
internal estimate. If specified, 'feeratestyle' must be either
|
||||
'"perkw"' for if 'feerate' is in satoshi-per-kilosipa (weight),
|
||||
or '"perkb"' for if 'feerate' is in bitcoind-style satoshi-per-kilobyte.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
On success, the 'tx' and 'txid' of the transaction is returned, as well as the
|
||||
|
||||
@@ -9,7 +9,7 @@ internal wallet.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
*withdraw* 'destination' 'satoshi'
|
||||
*withdraw* 'destination' 'satoshi' ['feerate' 'feeratestyle']
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -24,6 +24,10 @@ wallet (expressed, as name suggests, in satoshi).
|
||||
The string 'all' can be used to specify withdrawal of all
|
||||
available funds.
|
||||
|
||||
'feerate' is an optional feerate to use, overriding lightningd's
|
||||
internal estimate. If specified, 'feeratestyle' must be either
|
||||
'"perkw"' for if 'feerate' is in satoshi-per-kilosipa (weight),
|
||||
or '"perkb"' for if 'feerate' is in bitcoind-style satoshi-per-kilobyte.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
|
||||
@@ -447,6 +447,36 @@ u32 feerate_to_style(u32 feerate_perkw, enum feerate_style style)
|
||||
abort();
|
||||
}
|
||||
|
||||
/* If we have both feerate and style, use that, otherwise use inbuilt if avail.
|
||||
* Return false if we failed command, otherwise fills in feerate_perkw. */
|
||||
bool json_feerate_and_style(struct command *cmd,
|
||||
const u32 *feerate, enum feerate_style *style,
|
||||
u32 fallback_feerate_per_kw,
|
||||
u32 *feerate_per_kw)
|
||||
{
|
||||
if (feerate) {
|
||||
if (!style) {
|
||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"'feerate' requires 'feeratestyle'");
|
||||
return false;
|
||||
}
|
||||
*feerate_per_kw = feerate_from_style(*feerate, *style);
|
||||
return true;
|
||||
} else {
|
||||
if (style) {
|
||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"'feeratestyle' requires 'feerate'");
|
||||
return false;
|
||||
}
|
||||
*feerate_per_kw = fallback_feerate_per_kw;
|
||||
if (!*feerate_per_kw) {
|
||||
command_fail(cmd, LIGHTNINGD, "Cannot estimate fees");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static void json_feerates(struct command *cmd,
|
||||
const char *buffer, const jsmntok_t *params)
|
||||
{
|
||||
|
||||
@@ -150,6 +150,14 @@ u32 unilateral_feerate(struct chain_topology *topo);
|
||||
u32 feerate_from_style(u32 feerate, enum feerate_style style);
|
||||
u32 feerate_to_style(u32 feerate_perkw, enum feerate_style style);
|
||||
|
||||
/* If we have both feerate and style, use that, otherwise use fallback
|
||||
* if nonzero. Return false if we failed command, otherwise fills in
|
||||
* feerate_per_kw. */
|
||||
bool json_feerate_and_style(struct command *cmd,
|
||||
const u32 *feerate, enum feerate_style *style,
|
||||
u32 fallback_feerate_per_kw,
|
||||
u32 *feerate_per_kw);
|
||||
|
||||
/* Broadcast a single tx, and rebroadcast as reqd (copies tx).
|
||||
* If failed is non-NULL, call that and don't rebroadcast. */
|
||||
void broadcast_tx(struct chain_topology *topo,
|
||||
|
||||
@@ -764,7 +764,9 @@ static void json_fund_channel(struct command *cmd,
|
||||
struct pubkey *id;
|
||||
struct peer *peer;
|
||||
struct channel *channel;
|
||||
u32 feerate_per_kw = opening_feerate(cmd->ld->topology);
|
||||
unsigned int *feerate;
|
||||
enum feerate_style *style;
|
||||
u32 feerate_per_kw;
|
||||
u8 *msg;
|
||||
|
||||
fc->cmd = cmd;
|
||||
@@ -773,16 +775,18 @@ static void json_fund_channel(struct command *cmd,
|
||||
if (!param(fc->cmd, buffer, params,
|
||||
p_req("id", json_tok_pubkey, &id),
|
||||
p_req("satoshi", json_tok_tok, &sattok),
|
||||
p_opt("feerate", json_tok_number, &feerate),
|
||||
p_opt("feeratestyle", json_tok_feerate_style, &style),
|
||||
NULL))
|
||||
return;
|
||||
|
||||
if (!json_tok_wtx(&fc->wtx, buffer, sattok, MAX_FUNDING_SATOSHI))
|
||||
return;
|
||||
|
||||
if (!feerate_per_kw) {
|
||||
command_fail(cmd, LIGHTNINGD, "Cannot estimate fees");
|
||||
if (!json_feerate_and_style(cmd, feerate, style,
|
||||
opening_feerate(cmd->ld->topology),
|
||||
&feerate_per_kw))
|
||||
return;
|
||||
}
|
||||
|
||||
peer = peer_by_id(cmd->ld, id);
|
||||
if (!peer) {
|
||||
@@ -839,6 +843,6 @@ static void json_fund_channel(struct command *cmd,
|
||||
static const struct json_command fund_channel_command = {
|
||||
"fundchannel",
|
||||
json_fund_channel,
|
||||
"Fund channel with {id} using {satoshi} (or 'all') satoshis"
|
||||
"Fund channel with {id} using {satoshi} (or 'all') satoshis, at optional {feerate}"
|
||||
};
|
||||
AUTODATA(json_command, &fund_channel_command);
|
||||
|
||||
@@ -1124,7 +1124,20 @@ def test_no_fee_estimate(node_factory, bitcoind, executor):
|
||||
with pytest.raises(RpcError, match=r'Cannot estimate fees'):
|
||||
l1.rpc.withdraw(l2.rpc.newaddr()['address'], 'all')
|
||||
|
||||
# Can with manual feerate.
|
||||
l1.rpc.withdraw(l2.rpc.newaddr()['address'], 10000, 1500, 'perkb')
|
||||
l1.rpc.fundchannel(l2.info['id'], 10**6, 2000, 'perkw')
|
||||
|
||||
# Make sure we clean up cahnnel for later attempt.
|
||||
l1.daemon.wait_for_log('sendrawtx exit 0')
|
||||
l1.rpc.dev_fail(l2.info['id'])
|
||||
l1.daemon.wait_for_log('sendrawtx exit 0')
|
||||
bitcoind.generate_block(6)
|
||||
wait_for(lambda: only_one(l1.rpc.getpeer(l2.info['id'])['channels'])['state'] == 'ONCHAIN')
|
||||
wait_for(lambda: only_one(l2.rpc.getpeer(l1.info['id'])['channels'])['state'] == 'ONCHAIN')
|
||||
|
||||
# But can accept incoming connections.
|
||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
||||
l2.fund_channel(l1, 10**6)
|
||||
|
||||
# Can do HTLCs.
|
||||
|
||||
@@ -89,10 +89,10 @@ static void json_withdraw(struct command *cmd,
|
||||
{
|
||||
const jsmntok_t *desttok, *sattok;
|
||||
struct withdrawal *withdraw = tal(cmd, struct withdrawal);
|
||||
|
||||
u32 feerate_per_kw = try_get_feerate(cmd->ld->topology, FEERATE_NORMAL);
|
||||
u32 feerate_per_kw;
|
||||
unsigned int *feerate;
|
||||
enum feerate_style *style;
|
||||
struct bitcoin_tx *tx;
|
||||
|
||||
enum address_parse_result addr_parse;
|
||||
|
||||
withdraw->cmd = cmd;
|
||||
@@ -101,16 +101,19 @@ static void json_withdraw(struct command *cmd,
|
||||
if (!param(cmd, buffer, params,
|
||||
p_req("destination", json_tok_tok, &desttok),
|
||||
p_req("satoshi", json_tok_tok, &sattok),
|
||||
p_opt("feerate", json_tok_number, &feerate),
|
||||
p_opt("feeratestyle", json_tok_feerate_style, &style),
|
||||
NULL))
|
||||
return;
|
||||
|
||||
if (!json_tok_wtx(&withdraw->wtx, buffer, sattok, -1ULL))
|
||||
return;
|
||||
|
||||
if (!feerate_per_kw) {
|
||||
command_fail(cmd, LIGHTNINGD, "Cannot estimate fees");
|
||||
if (!json_feerate_and_style(cmd, feerate, style,
|
||||
try_get_feerate(cmd->ld->topology,
|
||||
FEERATE_NORMAL),
|
||||
&feerate_per_kw))
|
||||
return;
|
||||
}
|
||||
|
||||
/* Parse address. */
|
||||
addr_parse = json_tok_address_scriptpubkey(cmd,
|
||||
@@ -163,7 +166,7 @@ static void json_withdraw(struct command *cmd,
|
||||
static const struct json_command withdraw_command = {
|
||||
"withdraw",
|
||||
json_withdraw,
|
||||
"Send to {destination} address {satoshi} (or 'all') amount via Bitcoin transaction",
|
||||
"Send to {destination} address {satoshi} (or 'all') amount via Bitcoin transaction, at optional {feerate}",
|
||||
false, "Send funds from the internal wallet to the specified address. Either specify a number of satoshis to send or 'all' to sweep all funds in the internal wallet to the address."
|
||||
};
|
||||
AUTODATA(json_command, &withdraw_command);
|
||||
|
||||
Reference in New Issue
Block a user