#include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* May return NULL if encoding error occurs. */ static char * encode_pubkey_to_addr(const tal_t *ctx, const struct pubkey *pubkey, enum addrtype addrtype, /* Output: redeemscript to use to redeem outputs * paying to the address. * May be NULL if redeemscript is do not care. */ u8 **out_redeemscript) { char *out; const char *hrp; struct ripemd160 h160; u8 *redeemscript; bool ok; switch (addrtype) { case ADDR_BECH32: hrp = chainparams->onchain_hrp; /* out buffer is 73 + strlen(human readable part), * see common/bech32.h*/ out = tal_arr(ctx, char, 73 + strlen(hrp)); pubkey_to_hash160(pubkey, &h160); /* I am uncertain why this is so for direct SegWit * outputs, but this is how listaddrs worked prior to * this code being refactored. */ redeemscript = tal_dup_arr(ctx, u8, (u8 *) &h160, sizeof(h160), 0); ok = segwit_addr_encode(out, hrp, 0, h160.u.u8, sizeof(h160)); goto done; case ADDR_P2TR: { u8 *p2tr_spk = scriptpubkey_p2tr(ctx, pubkey); u8 *x_key = p2tr_spk + 2; hrp = chainparams->onchain_hrp; redeemscript = NULL; /* out buffer is 73 + strlen(human readable part), * see common/bech32.h*/ out = tal_arr(ctx, char, 73 + strlen(hrp)); ok = segwit_addr_encode(out, hrp, /* witver */ 1, x_key, 32); goto done; } case ADDR_ALL: abort(); } abort(); done: if (!ok) out = tal_free(out); if (out_redeemscript) *out_redeemscript = redeemscript; else tal_free(redeemscript); return out; } static struct command_result *param_newaddr(struct command *cmd, const char *name, const char *buffer, const jsmntok_t *tok, enum addrtype **addrtype) { *addrtype = tal(cmd, enum addrtype); if (json_tok_streq(buffer, tok, "bech32")) **addrtype = ADDR_BECH32; else if (!chainparams->is_elements && json_tok_streq(buffer, tok, "p2tr")) **addrtype = ADDR_P2TR; else if (json_tok_streq(buffer, tok, "all")) **addrtype = ADDR_ALL; else return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "'%s' should be 'p2tr', 'bech32', or 'all', not '%.*s'", name, tok->end - tok->start, buffer + tok->start); return NULL; } bool WARN_UNUSED_RESULT newaddr_inner(struct command *cmd, struct pubkey *pubkey, enum addrtype addrtype) { s64 keyidx; u8 *b32script; u8 *p2tr_script; keyidx = wallet_get_newindex(cmd->ld, addrtype); if (keyidx < 0) { // return command_fail(cmd, LIGHTNINGD, "Keys exhausted "); return false; } bip32_pubkey(cmd->ld, pubkey, keyidx); b32script = scriptpubkey_p2wpkh(tmpctx, pubkey); p2tr_script = scriptpubkey_p2tr(tmpctx, pubkey); if (addrtype & ADDR_BECH32) txfilter_add_scriptpubkey(cmd->ld->owned_txfilter, b32script); if (addrtype & ADDR_P2TR) txfilter_add_scriptpubkey(cmd->ld->owned_txfilter, p2tr_script); return true; } static struct command_result *json_newaddr(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, const jsmntok_t *params) { struct json_stream *response; struct pubkey pubkey; enum addrtype *addrtype; char *bech32, *p2tr; if (!param(cmd, buffer, params, p_opt_def("addresstype", param_newaddr, &addrtype, ADDR_BECH32), NULL)) return command_param_failed(); if (!newaddr_inner(cmd, &pubkey, *addrtype)) { return command_fail(cmd, LIGHTNINGD, "Keys exhausted "); }; bech32 = encode_pubkey_to_addr(cmd, &pubkey, ADDR_BECH32, NULL); p2tr = encode_pubkey_to_addr(cmd, &pubkey, ADDR_P2TR, NULL); if (!bech32 || !p2tr) { return command_fail(cmd, LIGHTNINGD, "p2wpkh address encoding failure."); } response = json_stream_success(cmd); if (*addrtype & ADDR_BECH32) json_add_string(response, "bech32", bech32); if (*addrtype & ADDR_P2TR) json_add_string(response, "p2tr", p2tr); return command_success(cmd, response); } static const struct json_command newaddr_command = { "newaddr", json_newaddr, }; AUTODATA(json_command, &newaddr_command); static void json_add_address_details(struct json_stream *response, const u64 keyidx, const char *out_p2wpkh, const char *out_p2tr) { json_object_start(response, NULL); json_add_u64(response, "keyidx", keyidx); if (!streq(out_p2wpkh, "")) { json_add_string(response, "bech32", out_p2wpkh); } if (!streq(out_p2tr,"")) { json_add_string(response, "p2tr", out_p2tr); } json_object_end(response); } static struct command_result *json_listaddresses(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, const jsmntok_t *params) { struct json_stream *response; struct pubkey pubkey; const u8 *scriptpubkey; u64 *liststart; u32 *listlimit; char *addr = NULL; if (!param(cmd, buffer, params, p_opt("address", param_bitcoin_address, &scriptpubkey), p_opt_def("start", param_u64, &liststart, 1), p_opt("limit", param_u32, &listlimit), NULL)) return command_param_failed(); addr = encode_scriptpubkey_to_addr(tmpctx, chainparams, scriptpubkey); if (*liststart == 0) { return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Starting keyidx is 1; Cannot {start} with 0"); } struct issued_address_type *listaddrtypes = wallet_list_addresses(tmpctx, cmd->ld->wallet, *liststart, listlimit); response = json_stream_success(cmd); json_array_start(response, "addresses"); for (size_t i = 0; i < tal_count(listaddrtypes); i++) { if (listaddrtypes[i].keyidx == BIP32_INITIAL_HARDENED_CHILD){ break; } bip32_pubkey(cmd->ld, &pubkey, listaddrtypes[i].keyidx); char *out_p2wpkh = ""; char *out_p2tr = ""; if (listaddrtypes[i].addrtype == ADDR_BECH32 || listaddrtypes[i].addrtype == ADDR_ALL) { u8 *redeemscript_p2wpkh; out_p2wpkh = encode_pubkey_to_addr(cmd, &pubkey, ADDR_BECH32, &redeemscript_p2wpkh); if (!out_p2wpkh) { abort(); } } if (listaddrtypes[i].addrtype == ADDR_P2TR || listaddrtypes[i].addrtype == ADDR_ALL) { out_p2tr = encode_pubkey_to_addr(cmd, &pubkey, ADDR_P2TR, /* out_redeemscript */ NULL); if (!out_p2tr) { abort(); } } if (!addr || streq(addr, out_p2wpkh) || streq(addr, out_p2tr)) { json_add_address_details(response, listaddrtypes[i].keyidx, out_p2wpkh, out_p2tr); if (addr) { break; } } } json_array_end(response); return command_success(cmd, response); } static const struct json_command listaddresses_command = { "listaddresses", json_listaddresses }; AUTODATA(json_command, &listaddresses_command); static struct command_result *json_listaddrs(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, const jsmntok_t *params) { struct json_stream *response; struct pubkey pubkey; u64 *bip32_max_index; if (!param(cmd, buffer, params, p_opt("bip32_max_index", param_u64, &bip32_max_index), NULL)) return command_param_failed(); if (!bip32_max_index) { bip32_max_index = tal(cmd, u64); *bip32_max_index = db_get_intvar(cmd->ld->wallet->db, "bip32_max_index", 0); } response = json_stream_success(cmd); json_array_start(response, "addresses"); for (s64 keyidx = 0; keyidx <= *bip32_max_index; keyidx++) { if (keyidx == BIP32_INITIAL_HARDENED_CHILD){ break; } bip32_pubkey(cmd->ld, &pubkey, keyidx); // bech32 : p2wpkh u8 *redeemscript_p2wpkh; char *out_p2wpkh = encode_pubkey_to_addr(cmd, &pubkey, ADDR_BECH32, &redeemscript_p2wpkh); if (!out_p2wpkh) { abort(); } // p2tr char *out_p2tr = encode_pubkey_to_addr(cmd, &pubkey, ADDR_P2TR, /* out_redeemscript */ NULL); if (!out_p2tr) { abort(); } // outputs json_object_start(response, NULL); json_add_u64(response, "keyidx", keyidx); json_add_pubkey(response, "pubkey", &pubkey); json_add_string(response, "bech32", out_p2wpkh); json_add_hex_talarr(response, "bech32_redeemscript", redeemscript_p2wpkh); json_add_string(response, "p2tr", out_p2tr); json_object_end(response); } json_array_end(response); return command_success(cmd, response); } static const struct json_command listaddrs_command = { "dev-listaddrs", json_listaddrs, .dev_only = true, }; AUTODATA(json_command, &listaddrs_command); static void json_add_utxo(struct json_stream *response, const char *fieldname, struct wallet *wallet, const struct utxo *utxo) { const char *out; bool reserved; u32 current_height = get_block_height(wallet->ld->topology); json_object_start(response, fieldname); json_add_txid(response, "txid", &utxo->outpoint.txid); json_add_num(response, "output", utxo->outpoint.n); json_add_amount_sat_msat(response, "amount_msat", utxo->amount); if (utxo->is_p2sh) { struct pubkey key; bip32_pubkey(wallet->ld, &key, utxo->keyindex); json_add_hex_talarr(response, "redeemscript", bitcoin_redeem_p2sh_p2wpkh(tmpctx, &key)); } json_add_hex_talarr(response, "scriptpubkey", utxo->scriptPubkey); out = encode_scriptpubkey_to_addr(tmpctx, chainparams, utxo->scriptPubkey); if (!out) log_broken(wallet->log, "Could not encode utxo %s%s!", fmt_bitcoin_outpoint(tmpctx, &utxo->outpoint), utxo->close_info ? " (has close_info)" : ""); else json_add_string(response, "address", out); if (utxo->spendheight) json_add_string(response, "status", "spent"); else if (utxo->blockheight) { json_add_string(response, "status", utxo_is_immature(utxo, current_height) ? "immature" : "confirmed"); json_add_num(response, "blockheight", *utxo->blockheight); } else json_add_string(response, "status", "unconfirmed"); reserved = utxo_is_reserved(utxo, current_height); json_add_bool(response, "reserved", reserved); if (reserved) json_add_num(response, "reserved_to_block", utxo->reserved_til); if (utxo->close_info && utxo->close_info->csv > 1) { json_add_num(response, "csv_lock", utxo->close_info->csv); if (utxo->blockheight) json_add_u32(response, "spendable_at", *utxo->blockheight + utxo->close_info->csv); } json_object_end(response); } static void json_add_utxos(struct json_stream *response, struct wallet *wallet, struct utxo **utxos) { for (size_t i = 0; i < tal_count(utxos); i++) json_add_utxo(response, NULL, wallet, utxos[i]); } static struct command_result *json_listfunds(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, const jsmntok_t *params) { struct json_stream *response; struct peer *p; struct peer_node_id_map_iter it; struct utxo **utxos; bool *spent; if (!param(cmd, buffer, params, p_opt_def("spent", param_bool, &spent, false), NULL)) return command_param_failed(); response = json_stream_success(cmd); if (*spent) utxos = wallet_get_all_utxos(cmd, cmd->ld->wallet); else utxos = wallet_get_unspent_utxos(cmd, cmd->ld->wallet); json_array_start(response, "outputs"); json_add_utxos(response, cmd->ld->wallet, utxos); json_array_end(response); /* Add funds that are allocated to channels */ json_array_start(response, "channels"); for (p = peer_node_id_map_first(cmd->ld->peers, &it); p; p = peer_node_id_map_next(cmd->ld->peers, &it)) { struct channel *c; list_for_each(&p->channels, c, list) { /* We don't print out uncommitted channels */ if (channel_state_uncommitted(c->state)) continue; json_object_start(response, NULL); json_add_node_id(response, "peer_id", &p->id); json_add_bool(response, "connected", channel_is_connected(c)); json_add_string(response, "state", channel_state_name(c)); json_add_channel_id(response, "channel_id", &c->cid); if (c->scid) json_add_short_channel_id(response, "short_channel_id", *c->scid); json_add_amount_msat(response, "our_amount_msat", c->our_msat); json_add_amount_sat_msat(response, "amount_msat", c->funding_sats); json_add_txid(response, "funding_txid", &c->funding.txid); json_add_num(response, "funding_output", c->funding.n); json_object_end(response); } } json_array_end(response); return command_success(cmd, response); } static const struct json_command listfunds_command = { "listfunds", json_listfunds, }; AUTODATA(json_command, &listfunds_command); struct txo_rescan { struct command *cmd; struct utxo **utxos; struct json_stream *response; }; static void process_utxo_result(struct bitcoind *bitcoind, const struct bitcoin_tx_output *txout, struct txo_rescan *rescan) { struct json_stream *response = rescan->response; struct utxo *u = rescan->utxos[0]; enum output_status newstate = txout == NULL ? OUTPUT_STATE_SPENT : OUTPUT_STATE_AVAILABLE; json_object_start(rescan->response, NULL); json_add_txid(response, "txid", &u->outpoint.txid); json_add_num(response, "output", u->outpoint.n); json_add_num(response, "oldstate", u->status); json_add_num(response, "newstate", newstate); json_object_end(rescan->response); wallet_update_output_status(bitcoind->ld->wallet, &u->outpoint, u->status, newstate); /* Remove the utxo we just resolved */ rescan->utxos[0] = rescan->utxos[tal_count(rescan->utxos) - 1]; tal_resize(&rescan->utxos, tal_count(rescan->utxos) - 1); if (tal_count(rescan->utxos) == 0) { /* Complete the response */ json_array_end(rescan->response); was_pending(command_success(rescan->cmd, rescan->response)); } else { bitcoind_getutxout(bitcoind, bitcoind, &rescan->utxos[0]->outpoint, process_utxo_result, rescan); } } static struct command_result *json_dev_rescan_outputs(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, const jsmntok_t *params) { struct txo_rescan *rescan = tal(cmd, struct txo_rescan); if (!param(cmd, buffer, params, NULL)) return command_param_failed(); rescan->response = json_stream_success(cmd); rescan->cmd = cmd; /* Open the outputs structure so we can incrementally add results */ json_array_start(rescan->response, "outputs"); rescan->utxos = wallet_get_all_utxos(rescan, cmd->ld->wallet); if (tal_count(rescan->utxos) == 0) { json_array_end(rescan->response); return command_success(cmd, rescan->response); } bitcoind_getutxout(rescan, cmd->ld->topology->bitcoind, &rescan->utxos[0]->outpoint, process_utxo_result, rescan); return command_still_pending(cmd); } static const struct json_command dev_rescan_output_command = { "dev-rescan-outputs", json_dev_rescan_outputs, .dev_only = true, }; AUTODATA(json_command, &dev_rescan_output_command); struct { enum wallet_tx_type t; const char *name; } wallet_tx_type_display_names[] = { {TX_THEIRS, "theirs"}, {TX_WALLET_DEPOSIT, "deposit"}, {TX_WALLET_WITHDRAWAL, "withdraw"}, {TX_CHANNEL_FUNDING, "channel_funding"}, {TX_CHANNEL_CLOSE, "channel_mutual_close"}, {TX_CHANNEL_UNILATERAL, "channel_unilateral_close"}, {TX_CHANNEL_SWEEP, "channel_sweep"}, {TX_CHANNEL_HTLC_SUCCESS, "channel_htlc_success"}, {TX_CHANNEL_HTLC_TIMEOUT, "channel_htlc_timeout"}, {TX_CHANNEL_PENALTY, "channel_penalty"}, {TX_CHANNEL_CHEAT, "channel_unilateral_cheat"}, }; static void json_transaction_details(struct json_stream *response, const struct wallet_transaction *tx) { struct wally_tx *wtx = tx->tx->wtx; json_object_start(response, NULL); json_add_txid(response, "hash", &tx->id); json_add_hex_talarr(response, "rawtx", tx->rawtx); json_add_num(response, "blockheight", tx->blockheight); json_add_num(response, "txindex", tx->txindex); json_add_u32(response, "locktime", wtx->locktime); json_add_u32(response, "version", wtx->version); json_array_start(response, "inputs"); for (size_t i = 0; i < wtx->num_inputs; i++) { struct bitcoin_txid prevtxid; struct wally_tx_input *in = &wtx->inputs[i]; bitcoin_tx_input_get_txid(tx->tx, i, &prevtxid); json_object_start(response, NULL); json_add_txid(response, "txid", &prevtxid); json_add_u32(response, "index", in->index); json_add_u32(response, "sequence", in->sequence); json_object_end(response); } json_array_end(response); json_array_start(response, "outputs"); for (size_t i = 0; i < wtx->num_outputs; i++) { struct wally_tx_output *out = &wtx->outputs[i]; struct amount_asset amt = bitcoin_tx_output_get_amount(tx->tx, i); struct amount_sat sat; /* TODO We should eventually handle non-bitcoin assets as well. */ if (amount_asset_is_main(&amt)) sat = amount_asset_to_sat(&amt); else sat = AMOUNT_SAT(0); json_object_start(response, NULL); json_add_u32(response, "index", i); json_add_amount_sat_msat(response, "amount_msat", sat); json_add_hex(response, "scriptPubKey", out->script, out->script_len); json_object_end(response); } json_array_end(response); json_object_end(response); } static struct command_result *json_listtransactions(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, const jsmntok_t *params) { struct json_stream *response; struct wallet_transaction *txs; if (!param(cmd, buffer, params, NULL)) return command_param_failed(); txs = wallet_transactions_get(cmd, cmd->ld->wallet); response = json_stream_success(cmd); json_array_start(response, "transactions"); for (size_t i = 0; i < tal_count(txs); i++) json_transaction_details(response, &txs[i]); json_array_end(response); return command_success(cmd, response); } static const struct json_command listtransactions_command = { "listtransactions", json_listtransactions, }; AUTODATA(json_command, &listtransactions_command); static bool in_only_inputs(const u32 *only_inputs, u32 this) { for (size_t i = 0; i < tal_count(only_inputs); i++) if (only_inputs[i] == this) return true; return false; } static struct command_result *match_psbt_inputs_to_utxos(struct command *cmd, struct wally_psbt *psbt, const u32 *only_inputs, struct utxo ***utxos) { *utxos = tal_arr(cmd, struct utxo *, 0); for (size_t i = 0; i < psbt->num_inputs; i++) { struct utxo *utxo; struct bitcoin_outpoint outpoint; if (only_inputs && !in_only_inputs(only_inputs, i)) continue; wally_psbt_input_get_outpoint(&psbt->inputs[i], &outpoint); utxo = wallet_utxo_get(*utxos, cmd->ld->wallet, &outpoint); if (!utxo) { if (only_inputs) return command_fail(cmd, LIGHTNINGD, "Aborting PSBT signing. UTXO %s is unknown (and specified by signonly)", fmt_bitcoin_outpoint(tmpctx, &outpoint)); continue; } /* Oops we haven't reserved this utxo yet! */ if (!utxo_is_reserved(utxo, get_block_height(cmd->ld->topology))) return command_fail(cmd, LIGHTNINGD, "Aborting PSBT signing. UTXO %s is not reserved", fmt_bitcoin_outpoint(tmpctx, &utxo->outpoint)); /* If the psbt doesn't have the UTXO info yet, add it. * We only add the witness_utxo for this */ if (!psbt->inputs[i].utxo && !psbt->inputs[i].witness_utxo) { u8 *scriptPubKey; if (utxo->is_p2sh) { struct pubkey key; u8 *redeemscript; int wally_err; bip32_pubkey(cmd->ld, &key, utxo->keyindex); redeemscript = bitcoin_redeem_p2sh_p2wpkh(tmpctx, &key); scriptPubKey = scriptpubkey_p2sh(tmpctx, redeemscript); tal_wally_start(); wally_err = wally_psbt_input_set_redeem_script(&psbt->inputs[i], redeemscript, tal_bytelen(redeemscript)); assert(wally_err == WALLY_OK); tal_wally_end(psbt); } else scriptPubKey = utxo->scriptPubkey; psbt_input_set_wit_utxo(psbt, i, scriptPubKey, utxo->amount); } tal_arr_expand(utxos, utxo); } return NULL; } static void match_psbt_outputs_to_wallet(struct wally_psbt *psbt, struct wallet *w) { tal_wally_start(); for (size_t outndx = 0; outndx < psbt->num_outputs; ++outndx) { struct ext_key ext; const u8 *script = psbt->outputs[outndx].script; const size_t script_len = psbt->outputs[outndx].script_len; u32 index; if (!wallet_can_spend(w, script, &index)) continue; if (bip32_key_from_parent( w->ld->bip32_base, index, BIP32_FLAG_KEY_PUBLIC, &ext) != WALLY_OK) { abort(); } psbt_output_set_keypath(index, &ext, is_p2tr(script, script_len, NULL), &psbt->outputs[outndx]); } tal_wally_end(psbt); } static struct command_result *param_input_numbers(struct command *cmd, const char *name, const char *buffer, const jsmntok_t *tok, u32 **input_nums) { struct command_result *res; const jsmntok_t *arr, *t; size_t i; res = param_array(cmd, name, buffer, tok, &arr); if (res) return res; *input_nums = tal_arr(cmd, u32, arr->size); json_for_each_arr(i, t, arr) { u32 *num; res = param_number(cmd, name, buffer, t, &num); if (res) return res; (*input_nums)[i] = *num; tal_free(num); } return NULL; } static struct command_result *json_signpsbt(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, const jsmntok_t *params) { struct command_result *res; struct json_stream *response; struct wally_psbt *psbt, *signed_psbt; struct utxo **utxos; u32 *input_nums; u32 psbt_version; if (!param_check(cmd, buffer, params, p_req("psbt", param_psbt, &psbt), p_opt("signonly", param_input_numbers, &input_nums), NULL)) return command_param_failed(); /* We internally deal with v2 only but we want to return V2 if given */ psbt_version = psbt->version; if (!psbt_set_version(psbt, 2)) { return command_fail(cmd, LIGHTNINGD, "Could not set PSBT version: %s", fmt_wally_psbt(tmpctx, psbt)); } /* Sanity check! */ for (size_t i = 0; i < tal_count(input_nums); i++) { if (input_nums[i] >= psbt->num_inputs) return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "signonly[%zu]: %u out of range", i, input_nums[i]); } /* We have to find/locate the utxos that are ours on this PSBT, * so that the HSM knows how/what to sign for (it's possible some of * our utxos require more complicated data to sign for e.g. * closeinfo outputs */ res = match_psbt_inputs_to_utxos(cmd, psbt, input_nums, &utxos); if (res) return res; if (tal_count(utxos) == 0) return command_fail(cmd, LIGHTNINGD, "No wallet inputs to sign"); if (command_check_only(cmd)) return command_check_done(cmd); /* Update the keypaths on any outputs that are in our wallet (change addresses). */ match_psbt_outputs_to_wallet(psbt, cmd->ld->wallet); /* 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, cast_const2(const struct utxo **, utxos), 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(cmd, msg, &signed_psbt)) return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "HSM gave bad sign_withdrawal_reply %s", tal_hex(tmpctx, msg)); /* Some signers (VLS) prune the input.utxo data as it's used * because it is too large to store in the signer. We can * restore this metadata by combining the signed psbt back * into a clone of the original psbt. */ struct wally_psbt *combined_psbt; combined_psbt = combine_psbt(cmd, psbt, signed_psbt); if (!combined_psbt) { return command_fail(cmd, LIGHTNINGD, "Unable to combine signed psbt: %s", fmt_wally_psbt(tmpctx, signed_psbt)); } if (!psbt_set_version(combined_psbt, psbt_version)) { return command_fail(cmd, LIGHTNINGD, "Signed PSBT unable to have version set: %s", fmt_wally_psbt(tmpctx, combined_psbt)); } response = json_stream_success(cmd); json_add_psbt(response, "signed_psbt", combined_psbt); return command_success(cmd, response); } static const struct json_command signpsbt_command = { "signpsbt", json_signpsbt, false }; AUTODATA(json_command, &signpsbt_command); static struct command_result *json_setpsbtversion(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, const jsmntok_t *params) { struct json_stream *response; unsigned int *version; struct wally_psbt *psbt; if (!param_check(cmd, buffer, params, p_req("psbt", param_psbt, &psbt), p_req("version", param_number, &version), NULL)) return command_param_failed(); if (!psbt_set_version(psbt, *version)) { return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Could not set PSBT version"); } if (command_check_only(cmd)) return command_check_done(cmd); response = json_stream_success(cmd); json_add_psbt(response, "psbt", psbt); return command_success(cmd, response); } static const struct json_command setpsbtversion_command = { "setpsbtversion", json_setpsbtversion, false }; AUTODATA(json_command, &setpsbtversion_command); struct sending_psbt { struct command *cmd; struct utxo **utxos; struct wally_tx *wtx; /* Hold onto b/c has data about * which are to external addresses */ struct wally_psbt *psbt; u32 reserve_blocks; }; static void maybe_notify_new_external_send(struct lightningd *ld, struct bitcoin_txid *txid, u32 outnum, struct wally_psbt *psbt) { struct chain_coin_mvt *mvt; struct bitcoin_outpoint outpoint; struct amount_sat amount; u32 index; const u8 *script; /* If it's not going to an external address, ignore */ if (!psbt_output_to_external(&psbt->outputs[outnum])) return; /* If it's going to our wallet, ignore */ script = wally_psbt_output_get_script(tmpctx, &psbt->outputs[outnum]); if (wallet_can_spend(ld->wallet, script, &index)) return; outpoint.txid = *txid; outpoint.n = outnum; amount = psbt_output_get_amount(psbt, outnum); mvt = new_coin_external_deposit(NULL, &outpoint, 0, amount, DEPOSIT); mvt->originating_acct = WALLET; notify_chain_mvt(ld, mvt); tal_free(mvt); } static void sendpsbt_done(struct bitcoind *bitcoind UNUSED, bool success, const char *msg, struct sending_psbt *sending) { struct lightningd *ld = sending->cmd->ld; struct json_stream *response; struct bitcoin_txid txid; struct amount_sat change; if (!success) { /* Unreserve the inputs again. */ for (size_t i = 0; i < tal_count(sending->utxos); i++) { wallet_unreserve_utxo(ld->wallet, sending->utxos[i], get_block_height(ld->topology), sending->reserve_blocks); } was_pending(command_fail(sending->cmd, LIGHTNINGD, "Error broadcasting transaction: %s." " Unsent tx discarded %s", msg, fmt_wally_tx(tmpctx, sending->wtx))); return; } /* Internal-only after, set to v2 */ if (!psbt_set_version(sending->psbt, 2)) { abort(); // Send succeeded but later calls may fail } wallet_transaction_add(ld->wallet, sending->wtx, 0, 0); /* Extract the change output and add it to the DB */ wallet_extract_owned_outputs(ld->wallet, sending->wtx, false, NULL, &change); wally_txid(sending->wtx, &txid); for (size_t i = 0; i < sending->psbt->num_outputs; i++) maybe_notify_new_external_send(ld, &txid, i, sending->psbt); response = json_stream_success(sending->cmd); json_add_hex_talarr(response, "tx", linearize_wtx(tmpctx, sending->wtx)); json_add_txid(response, "txid", &txid); was_pending(command_success(sending->cmd, response)); } static struct command_result *json_sendpsbt(struct command *cmd, const char *buffer, const jsmntok_t *obj, const jsmntok_t *params) { struct command_result *res; struct sending_psbt *sending; struct wally_psbt *psbt; struct lightningd *ld = cmd->ld; u32 *reserve_blocks; if (!param_check(cmd, buffer, params, p_req("psbt", param_psbt, &psbt), p_opt_def("reserve", param_number, &reserve_blocks, 12 * 6), NULL)) return command_param_failed(); sending = tal(cmd, struct sending_psbt); sending->cmd = cmd; sending->reserve_blocks = *reserve_blocks; psbt_finalize(psbt); sending->wtx = psbt_final_tx(sending, psbt); /* psbt contains info about which outputs are to external, * and thus need a coin_move issued for them. We only * notify if the transaction broadcasts */ sending->psbt = tal_steal(sending, psbt); if (!sending->wtx) return command_fail(cmd, LIGHTNINGD, "PSBT not finalizeable %s", fmt_wally_psbt(tmpctx, psbt)); /* We have to find/locate the utxos that are ours on this PSBT, * so that we know who to mark as used. */ res = match_psbt_inputs_to_utxos(cmd, psbt, NULL, &sending->utxos); if (res) return res; if (command_check_only(cmd)) return command_check_done(cmd); for (size_t i = 0; i < tal_count(sending->utxos); i++) { if (!wallet_reserve_utxo(ld->wallet, sending->utxos[i], get_block_height(ld->topology), sending->reserve_blocks)) fatal("UTXO not reservable?"); } /* Now broadcast the transaction */ bitcoind_sendrawtx(sending, cmd->ld->topology->bitcoind, cmd->id, tal_hex(tmpctx, linearize_wtx(tmpctx, sending->wtx)), false, sendpsbt_done, sending); return command_still_pending(cmd); } static const struct json_command sendpsbt_command = { "sendpsbt", json_sendpsbt, false }; AUTODATA(json_command, &sendpsbt_command);