openingd: ensure that initial channel can cover fees and reserve.

This is probably covered by our "channel capacity" heuristic which
requires the channel be significant, but best to be explicit and sure.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2018-03-18 15:11:32 +10:30 committed by Christian Decker
parent 441a5b8835
commit 21fbae6df8
6 changed files with 70 additions and 8 deletions

View file

@ -98,6 +98,7 @@ struct bitcoin_tx *initial_channel_tx(const tal_t *ctx,
dust_limit_satoshis(channel, side), dust_limit_satoshis(channel, side),
channel->view[side].owed_msat[side], channel->view[side].owed_msat[side],
channel->view[side].owed_msat[!side], channel->view[side].owed_msat[!side],
channel_reserve_msat(channel, side),
0 ^ channel->commitment_number_obscurer, 0 ^ channel->commitment_number_obscurer,
side); side);
} }

View file

@ -164,7 +164,8 @@ struct channel *new_initial_channel(const tal_t *ctx,
* @per_commitment_point: Per-commitment point to determine keys * @per_commitment_point: Per-commitment point to determine keys
* @side: which side to get the commitment transaction for * @side: which side to get the commitment transaction for
* *
* Returns the unsigned initial commitment transaction for @side. * Returns the unsigned initial commitment transaction for @side, or NULL
* if the channel size was insufficient to cover fees or reserves.
*/ */
struct bitcoin_tx *initial_channel_tx(const tal_t *ctx, struct bitcoin_tx *initial_channel_tx(const tal_t *ctx,
const u8 **wscript, const u8 **wscript,

View file

@ -4,7 +4,9 @@
#include <common/initial_commit_tx.h> #include <common/initial_commit_tx.h>
#include <common/keyset.h> #include <common/keyset.h>
#include <common/permute_tx.h> #include <common/permute_tx.h>
#include <common/status.h>
#include <common/utils.h> #include <common/utils.h>
#include <inttypes.h>
/* BOLT #3: /* BOLT #3:
* *
@ -29,7 +31,7 @@ u64 commit_number_obscurer(const struct pubkey *opener_payment_basepoint,
return be64_to_cpu(obscurer); return be64_to_cpu(obscurer);
} }
void try_subtract_fee(enum side funder, enum side side, bool try_subtract_fee(enum side funder, enum side side,
u64 base_fee_msat, u64 *self_msat, u64 *other_msat) u64 base_fee_msat, u64 *self_msat, u64 *other_msat)
{ {
u64 *funder_msat; u64 *funder_msat;
@ -39,10 +41,13 @@ void try_subtract_fee(enum side funder, enum side side,
else else
funder_msat = other_msat; funder_msat = other_msat;
if (*funder_msat >= base_fee_msat) if (*funder_msat >= base_fee_msat) {
*funder_msat -= base_fee_msat; *funder_msat -= base_fee_msat;
else return true;
} else {
*funder_msat = 0; *funder_msat = 0;
return false;
}
} }
u8 *to_self_wscript(const tal_t *ctx, u8 *to_self_wscript(const tal_t *ctx,
@ -65,6 +70,7 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx,
u64 dust_limit_satoshis, u64 dust_limit_satoshis,
u64 self_pay_msat, u64 self_pay_msat,
u64 other_pay_msat, u64 other_pay_msat,
u64 self_reserve_msat,
u64 obscured_commitment_number, u64 obscured_commitment_number,
enum side side) enum side side)
{ {
@ -93,8 +99,41 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx,
* 3. Subtract this base fee from the funder (either `to_local` or * 3. Subtract this base fee from the funder (either `to_local` or
* `to_remote`), with a floor of zero (see [Fee Payment](#fee-payment)). * `to_remote`), with a floor of zero (see [Fee Payment](#fee-payment)).
*/ */
try_subtract_fee(funder, side, base_fee_msat, if (!try_subtract_fee(funder, side, base_fee_msat,
&self_pay_msat, &other_pay_msat); &self_pay_msat, &other_pay_msat)) {
/* BOLT #2:
*
* The receiving node MUST fail the channel if:
*...
* - the funder's amount for the initial commitment
* transaction is not sufficient for full [fee
* payment](03-transactions.md#fee-payment).
*/
status_unusual("Funder cannot afford fee"
" on initial commitment transaction");
return NULL;
}
/* BOLT #2:
*
* The receiving node MUST fail the channel if:
*...
* - both `to_local` and `to_remote` amounts for the initial
* commitment transaction are less than or equal to
* `channel_reserve_satoshis`.
*/
if (self_pay_msat <= self_reserve_msat
&& other_pay_msat <= self_reserve_msat) {
status_unusual("Neither self amount %"PRIu64
" nor other amount %"PRIu64
" exceed reserve %"PRIu64
" on initial commitment transaction",
self_pay_msat / 1000,
other_pay_msat / 1000,
self_reserve_msat / 1000);
return NULL;
}
/* Worst-case sizing: both to-local and to-remote outputs. */ /* Worst-case sizing: both to-local and to-remote outputs. */
tx = bitcoin_tx(ctx, 1, untrimmed + 2); tx = bitcoin_tx(ctx, 1, untrimmed + 2);

View file

@ -76,11 +76,12 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx,
u64 dust_limit_satoshis, u64 dust_limit_satoshis,
u64 self_pay_msat, u64 self_pay_msat,
u64 other_pay_msat, u64 other_pay_msat,
u64 self_reserve_msat,
u64 obscured_commitment_number, u64 obscured_commitment_number,
enum side side); enum side side);
/* try_subtract_fee - take away this fee from the funder, or all if insufficient. */ /* try_subtract_fee - take away this fee from the funder (and return true), or all if insufficient (and return false). */
void try_subtract_fee(enum side funder, enum side side, bool try_subtract_fee(enum side funder, enum side side,
u64 base_fee_msat, u64 *self_msat, u64 *other_msat); u64 base_fee_msat, u64 *self_msat, u64 *other_msat);
/* Generate the witness script for the to-self output: /* Generate the witness script for the to-self output:

View file

@ -19,6 +19,13 @@ static bool print_superverbose;
/* Turn this on to brute-force fee values */ /* Turn this on to brute-force fee values */
/*#define DEBUG */ /*#define DEBUG */
/* AUTOGENERATED MOCKS START */
/* Generated stub for status_fmt */
void status_fmt(enum log_level level UNNEEDED, const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "status_fmt called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */
/* bitcoind loves its backwards txids! */ /* bitcoind loves its backwards txids! */
static struct bitcoin_txid txid_from_hex(const char *hex) static struct bitcoin_txid txid_from_hex(const char *hex)
{ {

View file

@ -422,6 +422,9 @@ static u8 *funder_channel(struct state *state,
*/ */
tx = initial_channel_tx(state, &wscript, state->channel, tx = initial_channel_tx(state, &wscript, state->channel,
&state->next_per_commit[REMOTE], REMOTE); &state->next_per_commit[REMOTE], REMOTE);
if (!tx)
negotiation_failed(state,
"Could not meet their fees and reserve");
sign_tx_input(tx, 0, NULL, wscript, sign_tx_input(tx, 0, NULL, wscript,
&state->our_secrets.funding_privkey, &state->our_secrets.funding_privkey,
@ -480,6 +483,9 @@ static u8 *funder_channel(struct state *state,
*/ */
tx = initial_channel_tx(state, &wscript, state->channel, tx = initial_channel_tx(state, &wscript, state->channel,
&state->next_per_commit[LOCAL], LOCAL); &state->next_per_commit[LOCAL], LOCAL);
if (!tx)
negotiation_failed(state,
"Could not meet our fees and reserve");
if (!check_tx_sig(tx, 0, NULL, wscript, &their_funding_pubkey, &sig)) { if (!check_tx_sig(tx, 0, NULL, wscript, &their_funding_pubkey, &sig)) {
peer_failed(&state->cs, state->gossip_index, peer_failed(&state->cs, state->gossip_index,
@ -706,6 +712,9 @@ static u8 *fundee_channel(struct state *state,
*/ */
their_commit = initial_channel_tx(state, &wscript, state->channel, their_commit = initial_channel_tx(state, &wscript, state->channel,
&state->next_per_commit[LOCAL], LOCAL); &state->next_per_commit[LOCAL], LOCAL);
if (!their_commit)
negotiation_failed(state,
"Could not meet our fees and reserve");
if (!check_tx_sig(their_commit, 0, NULL, wscript, &their_funding_pubkey, if (!check_tx_sig(their_commit, 0, NULL, wscript, &their_funding_pubkey,
&theirsig)) { &theirsig)) {
@ -740,6 +749,10 @@ static u8 *fundee_channel(struct state *state,
*/ */
our_commit = initial_channel_tx(state, &wscript, state->channel, our_commit = initial_channel_tx(state, &wscript, state->channel,
&state->next_per_commit[REMOTE], REMOTE); &state->next_per_commit[REMOTE], REMOTE);
if (!our_commit)
negotiation_failed(state,
"Could not meet their fees and reserve");
sign_tx_input(our_commit, 0, NULL, wscript, sign_tx_input(our_commit, 0, NULL, wscript,
&state->our_secrets.funding_privkey, &state->our_secrets.funding_privkey,
our_funding_pubkey, &sig); our_funding_pubkey, &sig);