diff --git a/common/Makefile b/common/Makefile index c407214e0..b62e738c0 100644 --- a/common/Makefile +++ b/common/Makefile @@ -74,10 +74,8 @@ COMMON_SRC_NOGEN := \ common/utxo.c \ common/version.c \ common/wallet.c \ - common/wallet_tx.c \ common/wireaddr.c \ - common/wire_error.c \ - common/withdraw_tx.c + common/wire_error.c COMMON_SRC_GEN := common/status_wiregen.c common/peer_status_wiregen.c diff --git a/common/wallet_tx.c b/common/wallet_tx.c deleted file mode 100644 index da9a1a171..000000000 --- a/common/wallet_tx.c +++ /dev/null @@ -1,264 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void wtx_init(struct command *cmd, struct wallet_tx *wtx, struct amount_sat max) -{ - wtx->cmd = cmd; - wtx->amount = max; -} - -struct command_result *param_wtx(struct command *cmd, - const char *name, - const char *buffer, - const jsmntok_t *tok, - struct wallet_tx *wtx) -{ - struct amount_sat max = wtx->amount; - - if (json_tok_streq(buffer, tok, "all")) { - wtx->all_funds = true; - return NULL; - } - wtx->all_funds = false; - - if (!parse_amount_sat(&wtx->amount, - buffer + tok->start, tok->end - tok->start)) - return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "'%s' should be an amount in satoshis or all, not '%.*s'", - name, - tok->end - tok->start, - buffer + tok->start); - - if (amount_sat_greater(wtx->amount, max)) - return command_fail(wtx->cmd, FUND_MAX_EXCEEDED, - "Amount exceeded %s", - type_to_string(tmpctx, struct amount_sat, - &max)); - return NULL; -} - -struct command_result *param_utxos(struct command *cmd, - const char *name, - const char *buffer, - const jsmntok_t *tok, - const struct utxo ***utxos) -{ - size_t i; - const jsmntok_t *curr; - struct bitcoin_txid **txids = tal_arr(cmd, struct bitcoin_txid*, 0); - unsigned int **outnums = tal_arr(cmd, unsigned int*, 0); - - json_for_each_arr(i, curr, tok) { - jsmntok_t txid_tok, outnum_tok; - if (!split_tok(buffer, curr, ':', &txid_tok, &outnum_tok)) - return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "Could not decode the outpoint from \"%s\"" - " The utxos should be specified as" - " 'txid:output_index'.", - json_strdup(tmpctx, buffer, curr)); - - struct bitcoin_txid *txid = tal(txids, struct bitcoin_txid); - unsigned int *outnum = tal(txids, unsigned int); - if (!json_to_txid(buffer, (const jsmntok_t*)&txid_tok, txid)) { - return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "Could not get a txid out of \"%s\"", - json_strdup(tmpctx, buffer, &txid_tok)); - } - if (!json_to_number(buffer, (const jsmntok_t*)&outnum_tok, outnum)) - return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "Could not get a vout out of \"%s\"", - json_strdup(tmpctx, buffer, &outnum_tok)); - - tal_arr_expand(&txids, txid); - tal_arr_expand(&outnums, outnum); - } - - if (!tal_count(txids) || !tal_count(outnums)) - return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "Please specify an array of 'txid:output_index'," - " not \"%.*s\"", - tok->end - tok->start, - buffer + tok->start); - - *utxos = wallet_select_specific(cmd, cmd->ld->wallet, txids, outnums); - tal_free(txids); - tal_free(outnums); - - if (!*utxos) - return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "Could not decode all of the outpoints. The utxos" - " should be specified as an array of " - " 'txid:output_index'."); - if (tal_count(*utxos) == 0) - return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "No matching utxo was found from the wallet. " - "You can get a list of the wallet utxos with" - " the `listfunds` RPC call."); - return NULL; -} - -static struct command_result *check_amount(const struct wallet_tx *wtx, - struct amount_sat amount) -{ - if (tal_count(wtx->utxos) == 0) { - /* Since it's possible the lack of utxos is because we haven't finished - * syncing yet, report a sync timing error first */ - if (!topology_synced(wtx->cmd->ld->topology)) - return command_fail(wtx->cmd, FUNDING_STILL_SYNCING_BITCOIN, - "Still syncing with bitcoin network"); - - return command_fail(wtx->cmd, FUND_CANNOT_AFFORD, - "Cannot afford transaction"); - } - - if (amount_sat_less(amount, chainparams->dust_limit)) { - return command_fail(wtx->cmd, FUND_OUTPUT_IS_DUST, - "Output %s would be dust", - type_to_string(tmpctx, struct amount_sat, - &amount)); - } - return NULL; -} - -struct command_result *wtx_select_utxos(struct wallet_tx *tx, - u32 fee_rate_per_kw, - size_t out_len, - u32 maxheight) -{ - struct command_result *res; - struct amount_sat fee_estimate; - - if (tx->all_funds) { - struct amount_sat amount; - tx->utxos = wallet_select_all(tx, tx->cmd->ld->wallet, - fee_rate_per_kw, out_len, - maxheight, - &amount, - &fee_estimate); - res = check_amount(tx, amount); - if (res) - return res; - - /* tx->amount is max permissible */ - if (amount_sat_less_eq(amount, tx->amount)) { - tx->change = AMOUNT_SAT(0); - tx->change_key_index = 0; - tx->amount = amount; - return NULL; - } - - /* Too much? Try again, but ask for limit instead. */ - tx->all_funds = false; - tx->utxos = tal_free(tx->utxos); - } - - tx->utxos = wallet_select_coins(tx, tx->cmd->ld->wallet, - true, tx->amount, - fee_rate_per_kw, out_len, - maxheight, - &fee_estimate, &tx->change); - if (!tx->utxos) { - /* Try again, without change this time */ - tx->utxos = wallet_select_coins(tx, tx->cmd->ld->wallet, - false, tx->amount, - fee_rate_per_kw, out_len, - maxheight, - &fee_estimate, &tx->change); - - } - - res = check_amount(tx, tx->amount); - if (res) - return res; - - if (amount_sat_less(tx->change, chainparams->dust_limit)) { - tx->change = AMOUNT_SAT(0); - tx->change_key_index = 0; - } else { - tx->change_key_index = wallet_get_newindex(tx->cmd->ld); - } - return NULL; -} - -struct command_result *wtx_from_utxos(struct wallet_tx *tx, - u32 fee_rate_per_kw, - size_t out_len, - u32 maxheight, - const struct utxo **utxos) -{ - size_t weight; - struct amount_sat total_amount, fee_estimate; - - tx->change = AMOUNT_SAT(0); - tx->change_key_index = 0; - total_amount = AMOUNT_SAT(0); - - /* The transaction has `tal_count(tx.utxos)` inputs and one output */ - /* (version + in count + out count + locktime) (index + value + script length) */ - /* + segwit marker + flag */ - weight = 4 * (4 + 1 + 1 + 4) + 4 * (8 + 1 + out_len) + 1 + 1; - for (size_t i = 0; i < tal_count(utxos); i++) { - if (maxheight > 0 && - (!utxos[i]->blockheight || *utxos[i]->blockheight > maxheight)) { - tal_arr_remove(&utxos, i); - continue; - } - /* txid + index + sequence + script_len */ - weight += (32 + 4 + 4 + 1) * 4; - /* P2SH variants include push of <0 <20-byte-key-hash>> */ - if (utxos[i]->is_p2sh) - weight += 23 * 4; - /* Account for witness (1 byte count + sig + key) */ - weight += 1 + (1 + 73 + 1 + 33); - if (!amount_sat_add(&total_amount, total_amount, utxos[i]->amount)) - fatal("Overflow when computing input amount"); - } - tx->utxos = tal_steal(tx, utxos); - - if (!tx->all_funds && amount_sat_less(tx->amount, total_amount) - && !amount_sat_sub(&tx->change, total_amount, tx->amount)) - fatal("Overflow when computing change"); - - if (amount_sat_greater_eq(tx->change, chainparams->dust_limit)) { - /* Add the change output's weight */ - weight += (8 + 1 + out_len) * 4; - } - - fee_estimate = amount_tx_fee(fee_rate_per_kw, weight); - - if (tx->all_funds || amount_sat_eq(tx->change, AMOUNT_SAT(0))) { - tx->amount = total_amount; - if (!amount_sat_sub(&tx->amount, tx->amount, fee_estimate)) - return command_fail(tx->cmd, FUND_CANNOT_AFFORD, - "Cannot afford transaction with %s" - " sats of fees, make sure to use " - "confirmed utxos.", - type_to_string(tmpctx, struct amount_sat, - &fee_estimate)); - } else { - if (!amount_sat_sub(&tx->change, tx->change, fee_estimate)) { - /* Try again without a change output */ - weight -= (8 + 1 + out_len) * 4; - fee_estimate = amount_tx_fee(fee_rate_per_kw, weight); - if (!amount_sat_sub(&tx->change, tx->change, fee_estimate)) - return command_fail(tx->cmd, FUND_CANNOT_AFFORD, - "Cannot afford transaction with %s" - " sats of fees, make sure to use " - "confirmed utxos.", - type_to_string(tmpctx, struct amount_sat, - &fee_estimate)); - tx->change = AMOUNT_SAT(0); - } else { - tx->change_key_index = wallet_get_newindex(tx->cmd->ld); - } - } - - return check_amount(tx, tx->amount); -} diff --git a/common/wallet_tx.h b/common/wallet_tx.h deleted file mode 100644 index 1b8e95229..000000000 --- a/common/wallet_tx.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef LIGHTNING_COMMON_WALLET_TX_H -#define LIGHTNING_COMMON_WALLET_TX_H -#include "config.h" -#include -#include -#include -#include -#include - -/* A specification of funds in the wallet used for funding channels and - * withdrawal. - */ -struct wallet_tx { - struct command *cmd; - struct amount_sat amount, change; - u32 change_key_index; - const struct utxo **utxos; - - bool all_funds; /* In this case, amount is a maximum. */ -}; - -void wtx_init(struct command *cmd, struct wallet_tx *wtx, struct amount_sat max); - -struct command_result *param_wtx(struct command *cmd, - const char *name, - const char *buffer, - const jsmntok_t *tok, - struct wallet_tx *wtx); - -struct command_result *param_utxos(struct command *cmd, - const char *name, - const char *buffer, - const jsmntok_t *tok, - const struct utxo ***utxos); - -struct command_result *wtx_select_utxos(struct wallet_tx *tx, - u32 fee_rate_per_kw, - size_t out_len, - u32 maxheight); - -struct command_result *wtx_from_utxos(struct wallet_tx *tx, - u32 fee_rate_per_kw, - size_t out_len, - u32 maxheight, - const struct utxo **utxos); - -static inline u32 minconf_to_maxheight(u32 minconf, struct lightningd *ld) -{ - /* No confirmations is special, we need to disable the check in the - * selection */ - if (minconf == 0) - return 0; - - /* Avoid wrapping around and suddenly allowing any confirmed - * outputs. Since we can't have a coinbase output, and 0 is taken for - * the disable case, we can just clamp to 1. */ - if (minconf >= ld->topology->tip->height) - return 1; - return ld->topology->tip->height - minconf + 1; -} -#endif /* LIGHTNING_COMMON_WALLET_TX_H */ diff --git a/common/withdraw_tx.c b/common/withdraw_tx.c deleted file mode 100644 index b52aac517..000000000 --- a/common/withdraw_tx.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "withdraw_tx.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct bitcoin_tx *withdraw_tx(const tal_t *ctx, - const struct chainparams *chainparams, - const struct utxo **utxos, - struct bitcoin_tx_output **outputs, - const struct ext_key *bip32_base, - u32 nlocktime) -{ - struct bitcoin_tx *tx; - int output_count; - - tx = tx_spending_utxos(ctx, chainparams, utxos, bip32_base, - false, tal_count(outputs), nlocktime, - BITCOIN_TX_DEFAULT_SEQUENCE - 1); - - output_count = bitcoin_tx_add_multi_outputs(tx, outputs); - assert(output_count == tal_count(outputs)); - - permute_outputs(tx, NULL, (const void **)outputs); - permute_inputs(tx, (const void **)utxos); - - bitcoin_tx_finalize(tx); - assert(bitcoin_tx_check(tx)); - return tx; -} - diff --git a/common/withdraw_tx.h b/common/withdraw_tx.h deleted file mode 100644 index cf5d67af1..000000000 --- a/common/withdraw_tx.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef LIGHTNING_COMMON_WITHDRAW_TX_H -#define LIGHTNING_COMMON_WITHDRAW_TX_H -#include "config.h" -#include -#include -#include -#include -#include - -struct bitcoin_tx; -struct ext_key; -struct privkey; -struct pubkey; -struct bitcoin_address; -struct utxo; - -/** - * withdraw_tx - Create a p2pkh withdrawal transaction - * - * @ctx: context to tal from. - * @chainparams: (in) the params for the created transaction. - * @utxos: (in/out) tal_arr of UTXO pointers to spend (permuted to match) - * @outputs: (in) tal_arr of bitcoin_tx_output, scriptPubKeys with amount to send to. - * @bip32_base: (in) bip32 base for key derivation, or NULL. - * @nlocktime: (in) the value to set as the transaction's nLockTime. - */ -struct bitcoin_tx *withdraw_tx(const tal_t *ctx, - const struct chainparams *chainparams, - const struct utxo **utxos, - struct bitcoin_tx_output **outputs, - const struct ext_key *bip32_base, - u32 nlocktime); - -#endif /* LIGHTNING_COMMON_WITHDRAW_TX_H */ diff --git a/hsmd/Makefile b/hsmd/Makefile index 2b5c0b291..f3ad5ca72 100644 --- a/hsmd/Makefile +++ b/hsmd/Makefile @@ -39,8 +39,7 @@ HSMD_COMMON_OBJS := \ common/type_to_string.o \ common/utils.o \ common/utxo.o \ - common/version.o \ - common/withdraw_tx.o + common/version.o lightningd/lightning_hsmd: $(HSMD_OBJS) $(HSMD_COMMON_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index f4bd92a90..1bd52a4df 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/lightningd/Makefile b/lightningd/Makefile index b3190950a..2894fbedc 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -110,10 +110,8 @@ LIGHTNINGD_COMMON_OBJS := \ common/utxo.o \ common/version.o \ common/wallet.o \ - common/wallet_tx.o \ common/wire_error.o \ common/wireaddr.o \ - common/withdraw_tx.o include wallet/Makefile diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index fa5488eb3..82173e996 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/lightningd/channel_control.h b/lightningd/channel_control.h index cf234a5e7..016b2e6d1 100644 --- a/lightningd/channel_control.h +++ b/lightningd/channel_control.h @@ -8,6 +8,7 @@ struct channel; struct crypto_state; struct lightningd; struct per_peer_state; +struct peer; void peer_start_channeld(struct channel *channel, struct per_peer_state *pps, diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 8928e9463..bc8cb2efc 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -935,9 +935,6 @@ int main(int argc, char *argv[]) min_blockheight, max_blockheight); db_begin_transaction(ld->wallet->db); - /*~ Tell the wallet to start figuring out what to do for any reserved - * unspent outputs we may have crashed with. */ - wallet_clean_utxos(ld->wallet, ld->topology->bitcoind); /*~ Pull peers, channels and HTLCs from db. Needs to happen after the * topology is initialized since some decisions rely on being able to @@ -1045,7 +1042,6 @@ int main(int argc, char *argv[]) * unreserving UTXOs (see #1737) */ db_begin_transaction(ld->wallet->db); tal_free(ld->jsonrpc); - free_unreleased_txs(ld->wallet); db_commit_transaction(ld->wallet->db); /* Clean our our HTLC maps, since they use malloc. */ diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 0d96a9b8e..023f567e7 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/plugins/txprepare.c b/plugins/txprepare.c index bf587e113..7ce05cb48 100644 --- a/plugins/txprepare.c +++ b/plugins/txprepare.c @@ -521,7 +521,7 @@ static const struct plugin_command commands[] = { json_txsend }, { - "newwithdraw", + "withdraw", "bitcoin", "Send funds to {destination} address", "Send to {destination} {satoshi} (or 'all') at optional {feerate} using utxos from {minconf} or {utxos}.", diff --git a/tests/test_misc.py b/tests/test_misc.py index b910567b1..491dd6fea 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -522,7 +522,7 @@ def test_withdraw_misc(node_factory, bitcoind, chainparams): l1.rpc.withdraw(waddr, 'not an amount') with pytest.raises(RpcError): l1.rpc.withdraw(waddr, -amount) - with pytest.raises(RpcError, match=r'Cannot afford transaction'): + with pytest.raises(RpcError, match=r'Could not afford'): l1.rpc.withdraw(waddr, amount * 100) out = l1.rpc.withdraw(waddr, amount) @@ -638,7 +638,7 @@ def test_withdraw_misc(node_factory, bitcoind, chainparams): assert l1.db_query('SELECT COUNT(*) as c FROM outputs WHERE status=0')[0]['c'] == 0 # This should fail, can't even afford fee. - with pytest.raises(RpcError, match=r'Cannot afford transaction'): + with pytest.raises(RpcError, match=r'Could not afford'): l1.rpc.withdraw(waddr, 'all') bitcoind.generate_block(1) diff --git a/tests/test_wallet.py b/tests/test_wallet.py index 53e947970..ed7fc6400 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -12,7 +12,6 @@ from utils import ( import os import pytest import subprocess -import time import unittest @@ -42,7 +41,7 @@ def test_withdraw(node_factory, bitcoind): l1.rpc.withdraw(waddr, 'not an amount') with pytest.raises(RpcError): l1.rpc.withdraw(waddr, -amount) - with pytest.raises(RpcError, match=r'Cannot afford transaction'): + with pytest.raises(RpcError, match=r'Could not afford'): l1.rpc.withdraw(waddr, amount * 100) out = l1.rpc.withdraw(waddr, 2 * amount) @@ -67,15 +66,23 @@ def test_withdraw(node_factory, bitcoind): # lightningd uses P2SH-P2WPKH waddr = l2.rpc.newaddr('bech32')['bech32'] l1.rpc.withdraw(waddr, 2 * amount) + + # Now make sure an additional two of them were marked as reserved + assert l1.db_query('SELECT COUNT(*) as c FROM outputs WHERE status=2')[0]['c'] == 2 + assert l1.db_query('SELECT COUNT(*) as c FROM outputs WHERE status=1')[0]['c'] == 2 + + # They're turned into spent once the node sees them mined. bitcoind.generate_block(1) + sync_blockheight(l1.bitcoin, [l1, l2]) # Make sure l2 received the withdrawal. - wait_for(lambda: len(l2.rpc.listfunds()['outputs']) == 1) + assert len(l2.rpc.listfunds()['outputs']) == 1 outputs = l2.db_query('SELECT value FROM outputs WHERE status=0;') assert only_one(outputs)['value'] == 2 * amount # Now make sure an additional two of them were marked as spent assert l1.db_query('SELECT COUNT(*) as c FROM outputs WHERE status=2')[0]['c'] == 4 + assert l1.db_query('SELECT COUNT(*) as c FROM outputs WHERE status=1')[0]['c'] == 0 # Simple test for withdrawal to P2WPKH # Address from: https://bc-2.jp/tools/bech32demo/index.html @@ -88,6 +95,7 @@ def test_withdraw(node_factory, bitcoind): l1.rpc.withdraw('tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxxxxxx', 2 * amount) l1.rpc.withdraw(waddr, 2 * amount) bitcoind.generate_block(1) + sync_blockheight(l1.bitcoin, [l1]) # Now make sure additional two of them were marked as spent assert l1.db_query('SELECT COUNT(*) as c FROM outputs WHERE status=2')[0]['c'] == 6 @@ -102,6 +110,7 @@ def test_withdraw(node_factory, bitcoind): l1.rpc.withdraw('tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qxxxxxx', 2 * amount) l1.rpc.withdraw(waddr, 2 * amount) bitcoind.generate_block(1) + sync_blockheight(l1.bitcoin, [l1]) # Now make sure additional two of them were marked as spent assert l1.db_query('SELECT COUNT(*) as c FROM outputs WHERE status=2')[0]['c'] == 8 @@ -143,7 +152,7 @@ def test_withdraw(node_factory, bitcoind): assert l1.db_query('SELECT COUNT(*) as c FROM outputs WHERE status=0')[0]['c'] == 0 # This should fail, can't even afford fee. - with pytest.raises(RpcError, match=r'Cannot afford transaction'): + with pytest.raises(RpcError, match=r'Could not afford'): l1.rpc.withdraw(waddr, 'all') # Add some funds to withdraw @@ -225,7 +234,7 @@ def test_addfunds_from_block(node_factory, bitcoind): addr = l1.rpc.newaddr("bech32")['bech32'] l1.rpc.withdraw(addr, "all") bitcoind.generate_block(1) - time.sleep(1) + sync_blockheight(bitcoind, [l1]) # The address we detect must match what was paid to. output = only_one(l1.rpc.listfunds()['outputs']) diff --git a/wallet/reservation.c b/wallet/reservation.c index 4d2474434..aa20177bf 100644 --- a/wallet/reservation.c +++ b/wallet/reservation.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -314,6 +313,21 @@ static struct command_result *finish_psbt(struct command *cmd, return command_success(cmd, response); } +static inline u32 minconf_to_maxheight(u32 minconf, struct lightningd *ld) +{ + /* No confirmations is special, we need to disable the check in the + * selection */ + if (minconf == 0) + return 0; + + /* Avoid wrapping around and suddenly allowing any confirmed + * outputs. Since we can't have a coinbase output, and 0 is taken for + * the disable case, we can just clamp to 1. */ + if (minconf >= ld->topology->tip->height) + return 1; + return ld->topology->tip->height - minconf + 1; +} + static struct command_result *json_fundpsbt(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 427cda0ed..652da3ea6 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -908,7 +908,7 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) struct utxo u; struct pubkey pk; struct node_id id; - struct amount_sat fee_estimate, change_satoshis; + struct utxo *one_utxo; const struct utxo **utxos; CHECK(w); @@ -941,19 +941,23 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) "wallet_add_utxo with close_info"); /* Now select them */ - utxos = wallet_select_coins(w, w, true, AMOUNT_SAT(2), 0, 21, - 0 /* no confirmations required */, - &fee_estimate, &change_satoshis); - CHECK(utxos && tal_count(utxos) == 2); + utxos = tal_arr(w, const struct utxo *, 0); + while ((one_utxo = wallet_find_utxo(w, w, 0, NULL, 253, + 0 /* no confirmations required */, + utxos)) != NULL) { + tal_arr_expand(&utxos, one_utxo); + } + CHECK(tal_count(utxos) == 2); + + if (utxos[0]->close_info) + u = *utxos[0]; + else + u = *utxos[1]; - u = *utxos[1]; CHECK(u.close_info->channel_id == 42 && pubkey_eq(u.close_info->commitment_point, &pk) && node_id_eq(&u.close_info->peer_id, &id) && u.close_info->option_anchor_outputs == false); - /* Now un-reserve them for the tests below */ - tal_free(utxos); - /* Attempt to reserve the utxo */ CHECK_MSG(wallet_update_output_status(w, &u.txid, u.outnum, @@ -993,12 +997,19 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) "wallet_add_utxo with close_info no commitment_point"); /* Now select it */ - utxos = wallet_select_coins(w, w, true, AMOUNT_SAT(5), 0, 21, - 0 /* no confirmations required */, - &fee_estimate, &change_satoshis); - CHECK(utxos && tal_count(utxos) == 2); + utxos = tal_arr(w, const struct utxo *, 0); + while ((one_utxo = wallet_find_utxo(w, w, 0, NULL, 253, + 0 /* no confirmations required */, + utxos)) != NULL) { + tal_arr_expand(&utxos, one_utxo); + } + CHECK(tal_count(utxos) == 2); + + if (utxos[0]->close_info) + u = *utxos[0]; + else + u = *utxos[1]; - u = *utxos[1]; CHECK(u.close_info->channel_id == 42 && u.close_info->commitment_point == NULL && node_id_eq(&u.close_info->peer_id, &id) && diff --git a/wallet/wallet.c b/wallet/wallet.c index dec065ff3..85b74a64f 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -67,7 +67,6 @@ struct wallet *wallet_new(struct lightningd *ld, struct timers *timers, wallet->bip32_base = tal_steal(wallet, bip32_base); wallet->keyscan_gap = 50; list_head_init(&wallet->unstored_payments); - list_head_init(&wallet->unreleased_txs); wallet->db = db_setup(wallet, ld, wallet->bip32_base); db_begin_transaction(wallet->db); @@ -162,7 +161,7 @@ static bool wallet_add_utxo(struct wallet *w, struct utxo *utxo, static struct utxo *wallet_stmt2output(const tal_t *ctx, struct db_stmt *stmt) { struct utxo *utxo = tal(ctx, struct utxo); - u32 *blockheight, *spendheight, *reserved_til; + u32 *blockheight, *spendheight; db_column_txid(stmt, 0, &utxo->txid); utxo->outnum = db_column_int(stmt, 1); db_column_amount_sat(stmt, 2, &utxo->amount); @@ -192,7 +191,6 @@ static struct utxo *wallet_stmt2output(const tal_t *ctx, struct db_stmt *stmt) utxo->blockheight = NULL; utxo->spendheight = NULL; - utxo->reserved_til = NULL; if (!db_column_is_null(stmt, 10)) { blockheight = tal(utxo, u32); @@ -206,11 +204,9 @@ static struct utxo *wallet_stmt2output(const tal_t *ctx, struct db_stmt *stmt) utxo->spendheight = spendheight; } - if (!db_column_is_null(stmt, 13)) { - reserved_til = tal(utxo, u32); - *reserved_til = db_column_int(stmt, 13); - utxo->reserved_til = reserved_til; - } + /* This column can be null if 0.9.1 db or below. */ + utxo->reserved_til = tal(utxo, u32); + *utxo->reserved_til = db_column_int_or_default(stmt, 13, 0); return utxo; } @@ -453,8 +449,6 @@ bool wallet_reserve_utxo(struct wallet *w, struct utxo *utxo, u32 current_height if (utxo->status == output_state_reserved) assert(utxo->reserved_til); - else - assert(!utxo->reserved_til); switch (utxo->status) { case output_state_spent: @@ -489,8 +483,7 @@ void wallet_unreserve_utxo(struct wallet *w, struct utxo *utxo, u32 current_heig if (!utxo->reserved_til) utxo->reserved_til = tal_dup(utxo, u32, ¤t_height); assert(utxo->reserved_til); - } else - assert(!utxo->reserved_til); + } if (utxo->status != output_state_reserved) fatal("UTXO %s:%u is not reserved", @@ -645,175 +638,6 @@ bool wallet_add_onchaind_utxo(struct wallet *w, return true; } -static const struct utxo **wallet_select(const tal_t *ctx, struct wallet *w, - struct amount_sat sat, - const u32 feerate_per_kw, - size_t outscriptlen, - bool may_have_change, - u32 maxheight, - struct amount_sat *satoshi_in, - struct amount_sat *fee_estimate) -{ - size_t i = 0; - struct utxo **available; - u64 weight; - size_t num_outputs = may_have_change ? 2 : 1; - const struct utxo **utxos = tal_arr(ctx, const struct utxo *, 0); - tal_add_destructor2(utxos, destroy_utxos, w); - - /* We assume < 253 inputs, and margin is tiny if we're wrong */ - weight = bitcoin_tx_core_weight(1, num_outputs) - + bitcoin_tx_output_weight(outscriptlen); - - /* Change output will be P2WPKH */ - if (may_have_change) - weight += bitcoin_tx_output_weight(BITCOIN_SCRIPTPUBKEY_P2WPKH_LEN); - - *fee_estimate = AMOUNT_SAT(0); - *satoshi_in = AMOUNT_SAT(0); - - available = wallet_get_utxos(ctx, w, output_state_available); - - for (i = 0; i < tal_count(available); i++) { - struct amount_sat needed; - struct utxo *u = tal_steal(utxos, available[i]); - - /* If we require confirmations check that we have a - * confirmation height and that it is below the required - * maxheight (current_height - minconf) */ - if (maxheight != 0 && - (!u->blockheight || *u->blockheight > maxheight)) { - tal_free(u); - continue; - } - - tal_arr_expand(&utxos, u); - - if (!wallet_update_output_status( - w, &available[i]->txid, available[i]->outnum, - output_state_available, output_state_reserved)) - fatal("Unable to reserve output"); - - weight += bitcoin_tx_simple_input_weight(u->is_p2sh); - - if (!amount_sat_add(satoshi_in, *satoshi_in, u->amount)) - fatal("Overflow in available satoshis %zu/%zu %s + %s", - i, tal_count(available), - type_to_string(tmpctx, struct amount_sat, - satoshi_in), - type_to_string(tmpctx, struct amount_sat, - &u->amount)); - - *fee_estimate = amount_tx_fee(feerate_per_kw, weight); - if (!amount_sat_add(&needed, sat, *fee_estimate)) - fatal("Overflow in fee estimate %zu/%zu %s + %s", - i, tal_count(available), - type_to_string(tmpctx, struct amount_sat, &sat), - type_to_string(tmpctx, struct amount_sat, - fee_estimate)); - if (amount_sat_greater_eq(*satoshi_in, needed)) - break; - } - tal_free(available); - - return utxos; -} - -const struct utxo **wallet_select_coins(const tal_t *ctx, struct wallet *w, - bool with_change, - struct amount_sat sat, - const u32 feerate_per_kw, - size_t outscriptlen, - u32 maxheight, - struct amount_sat *fee_estimate, - struct amount_sat *change) -{ - struct amount_sat satoshi_in; - const struct utxo **utxo; - - utxo = wallet_select(ctx, w, sat, feerate_per_kw, - outscriptlen, with_change, maxheight, - &satoshi_in, fee_estimate); - - /* Couldn't afford it? */ - if (!amount_sat_sub(change, satoshi_in, sat) - || !amount_sat_sub(change, *change, *fee_estimate)) - return tal_free(utxo); - - if (!with_change) - *change = AMOUNT_SAT(0); - - return utxo; -} - -const struct utxo **wallet_select_specific(const tal_t *ctx, struct wallet *w, - struct bitcoin_txid **txids, - u32 **outnums) -{ - size_t i, j; - struct utxo **available; - const struct utxo **utxos = tal_arr(ctx, const struct utxo*, 0); - tal_add_destructor2(utxos, destroy_utxos, w); - - available = wallet_get_utxos(ctx, w, output_state_available); - for (i = 0; i < tal_count(txids); i++) { - for (j = 0; j < tal_count(available); j++) { - - if (bitcoin_txid_eq(&available[j]->txid, txids[i]) - && available[j]->outnum == *outnums[i]) { - struct utxo *u = tal_steal(utxos, available[j]); - tal_arr_expand(&utxos, u); - - if (!wallet_update_output_status( - w, &available[j]->txid, available[j]->outnum, - output_state_available, output_state_reserved)) - fatal("Unable to reserve output"); - } - } - } - tal_free(available); - - return utxos; -} - -const struct utxo **wallet_select_all(const tal_t *ctx, struct wallet *w, - const u32 feerate_per_kw, - size_t outscriptlen, - u32 maxheight, - struct amount_sat *value, - struct amount_sat *fee_estimate) -{ - struct amount_sat satoshi_in; - const struct utxo **utxo; - - /* Huge value, but won't overflow on addition */ - utxo = wallet_select(ctx, w, AMOUNT_SAT(1ULL << 56), feerate_per_kw, - outscriptlen, false, maxheight, - &satoshi_in, fee_estimate); - - /* Can't afford fees? */ - if (!amount_sat_sub(value, satoshi_in, *fee_estimate)) - return tal_free(utxo); - - return utxo; -} - -u8 *derive_redeem_scriptsig(const tal_t *ctx, struct wallet *w, u32 keyindex) -{ - struct ext_key ext; - struct pubkey key; - - if (bip32_key_from_parent(w->bip32_base, keyindex, - BIP32_FLAG_KEY_PUBLIC, &ext) != WALLY_OK) { - fatal("Unable to derive pubkey"); - } - - if (!pubkey_from_der(ext.pub_key, PUBKEY_CMPR_LEN, &key)) - fatal("Unble to derive pubkey from DER"); - - return bitcoin_scriptsig_p2sh_p2wpkh(ctx, &key); -} - bool wallet_can_spend(struct wallet *w, const u8 *script, u32 *index, bool *output_is_p2sh) { @@ -3933,85 +3757,6 @@ const struct forwarding *wallet_forwarded_payments_get(struct wallet *w, return results; } -struct unreleased_tx *find_unreleased_tx(struct wallet *w, - const struct bitcoin_txid *txid) -{ - struct unreleased_tx *utx; - - list_for_each(&w->unreleased_txs, utx, list) { - if (bitcoin_txid_eq(txid, &utx->txid)) - return utx; - } - return NULL; -} - -static void destroy_unreleased_tx(struct unreleased_tx *utx) -{ - list_del(&utx->list); -} - -void remove_unreleased_tx(struct unreleased_tx *utx) -{ - tal_del_destructor(utx, destroy_unreleased_tx); - list_del(&utx->list); -} - -void add_unreleased_tx(struct wallet *w, struct unreleased_tx *utx) -{ - list_add_tail(&w->unreleased_txs, &utx->list); - tal_add_destructor(utx, destroy_unreleased_tx); -} - -/* These will touch the db, so need to be explicitly freed. */ -void free_unreleased_txs(struct wallet *w) -{ - struct unreleased_tx *utx; - - while ((utx = list_top(&w->unreleased_txs, struct unreleased_tx, list))) - tal_free(utx); -} - -static void process_utxo_result(struct bitcoind *bitcoind, - const struct bitcoin_tx_output *txout, - void *_utxos) -{ - struct utxo **utxos = _utxos; - enum output_status newstate = - txout == NULL ? output_state_spent : output_state_available; - - /* Don't unreserve ones which are on timers */ - if (!utxos[0]->reserved_til || newstate == output_state_spent) { - log_unusual(bitcoind->ld->wallet->log, - "wallet: reserved output %s/%u reset to %s", - type_to_string(tmpctx, struct bitcoin_txid, &utxos[0]->txid), - utxos[0]->outnum, - newstate == output_state_spent ? "spent" : "available"); - wallet_update_output_status(bitcoind->ld->wallet, - &utxos[0]->txid, utxos[0]->outnum, - utxos[0]->status, newstate); - } - - /* If we have more, resolve them too. */ - tal_arr_remove(&utxos, 0); - if (tal_count(utxos) != 0) { - bitcoind_getutxout(bitcoind, &utxos[0]->txid, utxos[0]->outnum, - process_utxo_result, utxos); - } else - tal_free(utxos); -} - -void wallet_clean_utxos(struct wallet *w, struct bitcoind *bitcoind) -{ - struct utxo **utxos = wallet_get_utxos(NULL, w, output_state_reserved); - - if (tal_count(utxos) != 0) { - bitcoind_getutxout(bitcoind, &utxos[0]->txid, utxos[0]->outnum, - process_utxo_result, - notleak_with_children(utxos)); - } else - tal_free(utxos); -} - struct wallet_transaction *wallet_transactions_get(struct wallet *w, const tal_t *ctx) { struct db_stmt *stmt; diff --git a/wallet/wallet.h b/wallet/wallet.h index 9c9566f8c..73b2347e2 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -48,26 +48,10 @@ struct wallet { * the blockchain. This is currently all P2WSH outputs */ struct outpointfilter *utxoset_outpoints; - /* Unreleased txs, waiting for txdiscard/txsend */ - struct list_head unreleased_txs; - /* How many keys should we look ahead at most? */ u64 keyscan_gap; }; -/* A transaction we've txprepared, but haven't signed and released yet */ -struct unreleased_tx { - /* In wallet->unreleased_txs */ - struct list_node list; - /* All the utxos. */ - struct wallet_tx *wtx; - /* Outputs(scriptpubkey and satoshi) this pays to. */ - struct bitcoin_tx_output **outputs; - /* The tx itself (unsigned initially) */ - struct bitcoin_tx *tx; - struct bitcoin_txid txid; -}; - /* Possible states for tracked outputs in the database. Not sure yet * whether we really want to have reservations reflected in the * database, it would simplify queries at the cost of some IO ops */ @@ -440,30 +424,6 @@ struct utxo *wallet_utxo_get(const tal_t *ctx, struct wallet *w, const struct bitcoin_txid *txid, u32 outnum); -const struct utxo **wallet_select_coins(const tal_t *ctx, struct wallet *w, - bool with_change, - struct amount_sat value, - const u32 feerate_per_kw, - size_t outscriptlen, - u32 maxheight, - struct amount_sat *fee_estimate, - struct amount_sat *change_satoshi); - -const struct utxo **wallet_select_all(const tal_t *ctx, struct wallet *w, - const u32 feerate_per_kw, - size_t outscriptlen, - u32 maxheight, - struct amount_sat *sat, - struct amount_sat *fee_estimate); - -/* derive_redeem_scriptsig - Compute the scriptSig for a P2SH-P2WPKH - * - * @ctx - allocation context - * @w - wallet - * @keyindex - index of the internal BIP32 key - */ -u8 *derive_redeem_scriptsig(const tal_t *ctx, struct wallet *w, u32 keyindex); - /** * wallet_select_specific - Select utxos given an array of txids and an array of outputs index * diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c index 2b2db663c..c1c69c59b 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -15,8 +15,6 @@ #include #include #include -#include -#include #include #include #include @@ -35,283 +33,6 @@ #include #include -struct tx_broadcast { - struct command *cmd; - const struct utxo **utxos; - const struct wally_tx *wtx; - struct amount_sat *expected_change; -}; - -static struct tx_broadcast *unreleased_tx_to_broadcast(const tal_t *ctx, - struct command *cmd, - struct unreleased_tx *utx) -{ - struct tx_broadcast *txb = tal(ctx, struct tx_broadcast); - struct amount_sat *change = tal(txb, struct amount_sat); - - txb->cmd = cmd; - txb->utxos = utx->wtx->utxos; - txb->wtx = utx->tx->wtx; - *change = utx->wtx->change; - txb->expected_change = change; - return txb; -} - -/** - * wallet_withdrawal_broadcast - The tx has been broadcast (or it failed) - * - * This is the final step in the withdrawal. We either successfully - * broadcast the withdrawal transaction or it failed somehow. So we - * report success or a broadcast failure. Upon success we also mark - * the used outputs as spent, and add the change output to our pool of - * available outputs. - */ -static void wallet_withdrawal_broadcast(struct bitcoind *bitcoind UNUSED, - bool success, const char *msg, - struct tx_broadcast *txb) -{ - struct command *cmd = txb->cmd; - struct lightningd *ld = cmd->ld; - - /* FIXME: This won't be necessary once we use ccan/json_out! */ - /* Massage output into shape so it doesn't kill the JSON serialization */ - char *output = tal_strjoin(cmd, tal_strsplit(cmd, msg, "\n", STR_NO_EMPTY), " ", STR_NO_TRAIL); - if (success) { - struct bitcoin_txid txid; - struct amount_sat change = AMOUNT_SAT(0); - - /* Mark used outputs as spent */ - wallet_confirm_utxos(ld->wallet, txb->utxos); - - /* Extract the change output and add it to the DB */ - wallet_extract_owned_outputs(ld->wallet, txb->wtx, NULL, &change); - - /* Note normally, change_satoshi == withdraw->wtx->change, but - * not if we're actually making a payment to ourselves! */ - if (txb->expected_change) - assert(amount_sat_greater_eq(change, *txb->expected_change)); - - struct json_stream *response = json_stream_success(cmd); - wally_txid(txb->wtx, &txid); - json_add_hex_talarr(response, "tx", - linearize_wtx(tmpctx, txb->wtx)); - json_add_txid(response, "txid", &txid); - was_pending(command_success(cmd, response)); - } else { - was_pending(command_fail(cmd, LIGHTNINGD, - "Error broadcasting transaction: %s. Unsent tx discarded %s", - output, - type_to_string(tmpctx, struct wally_tx, txb->wtx))); - } -} - -/* Signs the tx, broadcasts it: broadcast calls wallet_withdrawal_broadcast */ -static struct command_result *broadcast_and_wait(struct command *cmd, - struct unreleased_tx *utx) -{ - struct wally_psbt *signed_psbt; - struct wally_tx *signed_wtx; - struct bitcoin_txid signed_txid; - - /* FIXME: hsm will sign almost anything, but it should really - * fail cleanly (not abort!) and let us report the error here. */ - u8 *msg = towire_hsmd_sign_withdrawal(cmd, utx->wtx->utxos, utx->tx->psbt); - - if (!wire_sync_write(cmd->ld->hsm_fd, take(msg))) - fatal("Could not write sign_withdrawal to HSM: %s", - strerror(errno)); - - msg = wire_sync_read(cmd, cmd->ld->hsm_fd); - - if (!fromwire_hsmd_sign_withdrawal_reply(utx, msg, &signed_psbt)) - fatal("HSM gave bad sign_withdrawal_reply %s", - tal_hex(tmpctx, msg)); - - signed_wtx = psbt_finalize(signed_psbt, true); - - if (!signed_wtx) { - /* Have the utx persist past this command */ - tal_steal(cmd->ld->wallet, utx); - add_unreleased_tx(cmd->ld->wallet, utx); - return command_fail(cmd, LIGHTNINGD, - "PSBT is not finalized %s", - type_to_string(tmpctx, - struct wally_psbt, - signed_psbt)); - } - - /* Sanity check */ - wally_txid(signed_wtx, &signed_txid); - if (!bitcoin_txid_eq(&signed_txid, &utx->txid)) - fatal("HSM changed txid: unsigned %s, signed %s", - tal_hex(tmpctx, linearize_tx(tmpctx, utx->tx)), - tal_hex(tmpctx, linearize_wtx(tmpctx, signed_wtx))); - - /* Replace unsigned tx by signed tx. */ - wally_tx_free(utx->tx->wtx); - utx->tx->wtx = tal_steal(utx->tx, signed_wtx); - tal_free(utx->tx->psbt); - utx->tx->psbt = tal_steal(utx->tx, signed_psbt); - - /* Now broadcast the transaction */ - bitcoind_sendrawtx(cmd->ld->topology->bitcoind, - tal_hex(tmpctx, linearize_tx(tmpctx, utx->tx)), - wallet_withdrawal_broadcast, - unreleased_tx_to_broadcast(cmd, cmd, utx)); - - return command_still_pending(cmd); -} - -/* Parsing code for withdraw. - * - * Returns NULL on success, and fills in wtx, output and - * maybe changekey (owned by cmd). Otherwise, cmd has failed, so don't - * access it! (It's been freed). */ -static struct command_result *json_prepare_tx(struct command *cmd, - const char *buffer, - const jsmntok_t *params, - struct unreleased_tx **utx) -{ - u32 *feerate_per_kw = NULL; - struct command_result *result; - u32 *minconf, maxheight; - struct pubkey *changekey; - struct bitcoin_tx_output **outputs; - const u8 *destination = NULL; - size_t out_len; - const struct utxo **chosen_utxos = NULL; - u32 locktime; - - *utx = tal(cmd, struct unreleased_tx); - (*utx)->wtx = tal(*utx, struct wallet_tx); - wtx_init(cmd, (*utx)->wtx, AMOUNT_SAT(-1ULL)); - - /* *withdraw* command still use 'destination' and 'satoshi' as parameters. */ - if (!param(cmd, buffer, params, - p_req("destination", param_bitcoin_address, - &destination), - p_req("satoshi", param_wtx, (*utx)->wtx), - p_opt("feerate", param_feerate, &feerate_per_kw), - p_opt_def("minconf", param_number, &minconf, 1), - p_opt("utxos", param_utxos, &chosen_utxos), - NULL)) - return command_param_failed(); - - /* Setting the locktime to the next block to be mined has multiple - * benefits: - * - anti fee-snipping (even if not yet likely) - * - less distinguishable transactions (with this we create - * general-purpose transactions which looks like bitcoind: - * native segwit, nlocktime set to tip, and sequence set to - * 0xFFFFFFFE by default. Other wallets are likely to implement - * this too). - */ - locktime = cmd->ld->topology->tip->height; - /* Eventually fuzz it too. */ - if (pseudorand(10) == 0) - locktime -= (u32)pseudorand(100); - - if (!feerate_per_kw) { - /* We mainly use `txprepare` for opening transactions, and FEERATE_OPENING - * is kind of the new FEERATE_NORMAL so it fits well `withdraw` too. */ - result = param_feerate_estimate(cmd, &feerate_per_kw, - FEERATE_OPENING); - if (result) - return result; - } - - maxheight = minconf_to_maxheight(*minconf, cmd->ld); - - outputs = tal_arr(tmpctx, struct bitcoin_tx_output *, 1); - outputs[0] = new_tx_output(outputs, (*utx)->wtx->amount, - destination); - out_len = tal_count(outputs[0]->script); - - if (chosen_utxos) - result = wtx_from_utxos((*utx)->wtx, *feerate_per_kw, - out_len, maxheight, - chosen_utxos); - else - result = wtx_select_utxos((*utx)->wtx, *feerate_per_kw, - out_len, maxheight); - - if (result) - return result; - - /* Because of the max limit of AMOUNT_SAT(-1ULL), - * `(*utx)->wtx->all_funds` won't change in `wtx_select_utxos()` */ - if ((*utx)->wtx->all_funds) - outputs[0]->amount = (*utx)->wtx->amount; - - /* Add the change as the last output */ - if (!amount_sat_eq((*utx)->wtx->change, AMOUNT_SAT(0))) { - struct bitcoin_tx_output *change_output; - - changekey = tal(tmpctx, struct pubkey); - if (!bip32_pubkey(cmd->ld->wallet->bip32_base, changekey, - (*utx)->wtx->change_key_index)) - return command_fail(cmd, LIGHTNINGD, "Keys generation failure"); - - change_output = new_tx_output(outputs, (*utx)->wtx->change, - scriptpubkey_p2wpkh(tmpctx, changekey)); - tal_arr_expand(&outputs, change_output); - } - - (*utx)->outputs = tal_steal(*utx, outputs); - (*utx)->tx = withdraw_tx(*utx, chainparams, - (*utx)->wtx->utxos, - (*utx)->outputs, - cmd->ld->wallet->bip32_base, - /* FIXME: Should probably be - * struct abs_locktime. - */ - locktime); - - bitcoin_txid((*utx)->tx, &(*utx)->txid); - return NULL; -} - -/** - * json_withdraw - Entrypoint for the withdrawal flow - * - * A user has requested a withdrawal over the JSON-RPC, parse the - * request, select coins and a change key. Then send the request to - * the HSM to generate the signatures. - */ -static struct command_result *json_withdraw(struct command *cmd, - const char *buffer, - const jsmntok_t *obj UNNEEDED, - const jsmntok_t *params) -{ - struct unreleased_tx *utx; - struct command_result *res; - - res = json_prepare_tx(cmd, buffer, params, &utx); - if (res) - return res; - - /* Store the transaction in the DB and annotate it as a withdrawal */ - wallet_transaction_add(cmd->ld->wallet, utx->tx->wtx, 0, 0); - wallet_transaction_annotate(cmd->ld->wallet, &utx->txid, - TX_WALLET_WITHDRAWAL, 0); - - return broadcast_and_wait(cmd, utx); -} - -static const struct json_command withdraw_command = { - "withdraw", - "bitcoin", - json_withdraw, - "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. Only use outputs that have at least " - "{minconf} confirmations." -}; -AUTODATA(json_command, &withdraw_command); - /* May return NULL if encoding error occurs. */ static char * encode_pubkey_to_addr(const tal_t *ctx,