mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-03 10:46:58 +01:00
build_utxos: fix weight calculation, and make more accurate.
Accuracy improvements: 1. We assumed the output was a p2wpkh, but it can be user-supplied now. 2. We assumed we always had change; remove this for wallet_select_all. Calculation out-by-one fixes: 1. We need to add 1 byte (4 sipa) for the input count. 2. We need to add 1 byte (4 sipa) for the output count. 3. We need to add 1 byte (4 sipa) for the output script length for each output. 4. We need to add 1 byte (4 sipa) for the input script length for each input. 5. We need to add 1 byte (4 sipa) for the PUSH optcode for each P2SH input. The results are now a slight overestimate (due to guessing 73 bytes for signature, whereas they're 71 or 72 in practice). Fixes: #458 Reported-by: Jonas Nick @jonasnick Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
bbac67f108
commit
3543530172
6 changed files with 44 additions and 10 deletions
|
@ -11,12 +11,14 @@
|
|||
const struct utxo **build_utxos(const tal_t *ctx,
|
||||
struct lightningd *ld, u64 satoshi_out,
|
||||
u32 feerate_per_kw, u64 dust_limit,
|
||||
size_t outputscriptlen,
|
||||
u64 *change_satoshis, u32 *change_keyindex)
|
||||
{
|
||||
u64 fee_estimate = 0;
|
||||
u64 bip32_max_index = db_get_intvar(ld->wallet->db, "bip32_max_index", 0);
|
||||
const struct utxo **utxos =
|
||||
wallet_select_coins(ctx, ld->wallet, satoshi_out, feerate_per_kw,
|
||||
outputscriptlen,
|
||||
&fee_estimate, change_satoshis);
|
||||
|
||||
/* Oops, didn't have enough coins available */
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
const struct utxo **build_utxos(const tal_t *ctx,
|
||||
struct lightningd *ld, u64 satoshi_out,
|
||||
u32 feerate_per_kw, u64 dust_limit,
|
||||
size_t outputscriptlen,
|
||||
u64 *change_satoshis, u32 *change_keyindex);
|
||||
|
||||
#endif /* LIGHTNING_LIGHTNINGD_BUILD_UTXOS_H */
|
||||
|
|
|
@ -2631,7 +2631,8 @@ static void json_fund_channel(struct command *cmd,
|
|||
/* FIXME: dustlimit */
|
||||
fc->utxomap = build_utxos(fc, cmd->ld, fc->funding_satoshi,
|
||||
get_feerate(cmd->ld->topology, FEERATE_NORMAL),
|
||||
600, &fc->change, &fc->change_keyindex);
|
||||
600, BITCOIN_SCRIPTPUBKEY_P2WSH_LEN,
|
||||
&fc->change, &fc->change_keyindex);
|
||||
if (!fc->utxomap) {
|
||||
command_fail(cmd, "Cannot afford funding transaction");
|
||||
return;
|
||||
|
|
|
@ -134,22 +134,35 @@ void wallet_confirm_utxos(struct wallet *w, const struct utxo **utxos)
|
|||
static const struct utxo **wallet_select(const tal_t *ctx, struct wallet *w,
|
||||
const u64 value,
|
||||
const u32 feerate_per_kw,
|
||||
size_t outscriptlen,
|
||||
bool may_have_change,
|
||||
u64 *satoshi_in,
|
||||
u64 *fee_estimate)
|
||||
{
|
||||
size_t i = 0;
|
||||
struct utxo **available;
|
||||
u64 weight;
|
||||
const struct utxo **utxos = tal_arr(ctx, const struct utxo *, 0);
|
||||
/* We assume two outputs for the weight. */
|
||||
u64 weight = (4 + (8 + 22) * 2 + 4) * 4;
|
||||
tal_add_destructor2(utxos, destroy_utxos, w);
|
||||
|
||||
/* version, input count, output count, locktime */
|
||||
weight = (4 + 1 + 1 + 4) * 4;
|
||||
|
||||
/* The main output: amount, len, scriptpubkey */
|
||||
weight += (8 + 1 + outscriptlen) * 4;
|
||||
|
||||
/* Change output will be P2WPKH */
|
||||
if (may_have_change)
|
||||
weight += (8 + 1 + BITCOIN_SCRIPTPUBKEY_P2WPKH_LEN) * 4;
|
||||
|
||||
*fee_estimate = 0;
|
||||
*satoshi_in = 0;
|
||||
|
||||
available = wallet_get_utxos(ctx, w, output_state_available);
|
||||
|
||||
for (i = 0; i < tal_count(available); i++) {
|
||||
size_t input_weight;
|
||||
|
||||
tal_resize(&utxos, i + 1);
|
||||
utxos[i] = tal_steal(utxos, available[i]);
|
||||
|
||||
|
@ -158,12 +171,21 @@ static const struct utxo **wallet_select(const tal_t *ctx, struct wallet *w,
|
|||
output_state_available, output_state_reserved))
|
||||
fatal("Unable to reserve output");
|
||||
|
||||
weight += (32 + 4 + 4) * 4;
|
||||
if (utxos[i]->is_p2sh)
|
||||
weight += 22 * 4;
|
||||
/* Input weight: txid + index + sequence */
|
||||
input_weight = (32 + 4 + 4) * 4;
|
||||
|
||||
/* We always encode the length of the script, even if empty */
|
||||
input_weight += 1 * 4;
|
||||
|
||||
/* P2SH variants include push of <0 <20-byte-key-hash>> */
|
||||
if (utxos[i]->is_p2sh)
|
||||
input_weight += 23 * 4;
|
||||
|
||||
/* Account for witness (1 byte count + sig + key) */
|
||||
input_weight += 1 + (1 + 73 + 1 + 33);
|
||||
|
||||
weight += input_weight;
|
||||
|
||||
/* Account for witness (1 byte count + sig + key */
|
||||
weight += 1 + (1 + 73 + 1 + 33);
|
||||
*fee_estimate = weight * feerate_per_kw / 1000;
|
||||
*satoshi_in += utxos[i]->amount;
|
||||
if (*satoshi_in >= *fee_estimate + value)
|
||||
|
@ -177,12 +199,14 @@ static const struct utxo **wallet_select(const tal_t *ctx, struct wallet *w,
|
|||
const struct utxo **wallet_select_coins(const tal_t *ctx, struct wallet *w,
|
||||
const u64 value,
|
||||
const u32 feerate_per_kw,
|
||||
size_t outscriptlen,
|
||||
u64 *fee_estimate, u64 *changesatoshi)
|
||||
{
|
||||
u64 satoshi_in;
|
||||
const struct utxo **utxo;
|
||||
|
||||
utxo = wallet_select(ctx, w, value, feerate_per_kw,
|
||||
outscriptlen, true,
|
||||
&satoshi_in, fee_estimate);
|
||||
|
||||
/* Couldn't afford it? */
|
||||
|
@ -194,15 +218,17 @@ const struct utxo **wallet_select_coins(const tal_t *ctx, struct wallet *w,
|
|||
}
|
||||
|
||||
const struct utxo **wallet_select_all(const tal_t *ctx, struct wallet *w,
|
||||
const u32 feerate_per_kw,
|
||||
u64 *value,
|
||||
u64 *fee_estimate)
|
||||
const u32 feerate_per_kw,
|
||||
size_t outscriptlen,
|
||||
u64 *value,
|
||||
u64 *fee_estimate)
|
||||
{
|
||||
u64 satoshi_in;
|
||||
const struct utxo **utxo;
|
||||
|
||||
/* Huge value, but won't overflow on addition */
|
||||
utxo = wallet_select(ctx, w, (1ULL << 56), feerate_per_kw,
|
||||
outscriptlen, false,
|
||||
&satoshi_in, fee_estimate);
|
||||
|
||||
/* Can't afford fees? */
|
||||
|
|
|
@ -134,11 +134,13 @@ struct utxo **wallet_get_utxos(const tal_t *ctx, struct wallet *w,
|
|||
const struct utxo **wallet_select_coins(const tal_t *ctx, struct wallet *w,
|
||||
const u64 value,
|
||||
const u32 feerate_per_kw,
|
||||
size_t outscriptlen,
|
||||
u64 *fee_estimate,
|
||||
u64 *change_satoshi);
|
||||
|
||||
const struct utxo **wallet_select_all(const tal_t *ctx, struct wallet *w,
|
||||
const u32 feerate_per_kw,
|
||||
size_t outscriptlen,
|
||||
u64 *value,
|
||||
u64 *fee_estimate);
|
||||
|
||||
|
|
|
@ -246,6 +246,7 @@ static void json_withdraw(struct command *cmd,
|
|||
if (withdraw_all) {
|
||||
withdraw->utxos = wallet_select_all(cmd, cmd->ld->wallet,
|
||||
feerate_per_kw,
|
||||
tal_len(withdraw->destination),
|
||||
&withdraw->amount,
|
||||
&fee_estimate);
|
||||
/* FIXME Pull dust amount from the daemon config */
|
||||
|
@ -259,6 +260,7 @@ static void json_withdraw(struct command *cmd,
|
|||
withdraw->utxos = wallet_select_coins(cmd, cmd->ld->wallet,
|
||||
withdraw->amount,
|
||||
feerate_per_kw,
|
||||
tal_len(withdraw->destination),
|
||||
&fee_estimate,
|
||||
&withdraw->changesatoshi);
|
||||
if (!withdraw->utxos) {
|
||||
|
|
Loading…
Add table
Reference in a new issue