mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 01:43:36 +01:00
Support p2tr deposit addresses
Changelog-Added: JSON-RPC: newaddr: p2tr option to create taproot addresses. Changelog-Changed: Wallet: we now use taproot change addresses.
This commit is contained in:
parent
55cad79d82
commit
4b70736d13
10
.msggen.json
10
.msggen.json
@ -273,7 +273,8 @@
|
||||
"NewaddrAddresstype": {
|
||||
"all": 2,
|
||||
"bech32": 0,
|
||||
"p2sh-segwit": 1
|
||||
"p2sh-segwit": 1,
|
||||
"p2tr": 3
|
||||
},
|
||||
"PayStatus": {
|
||||
"complete": 0,
|
||||
@ -1263,7 +1264,8 @@
|
||||
},
|
||||
"NewaddrResponse": {
|
||||
"NewAddr.bech32": 1,
|
||||
"NewAddr.p2sh-segwit": 2
|
||||
"NewAddr.p2sh-segwit": 2,
|
||||
"NewAddr.p2tr": 3
|
||||
},
|
||||
"PayRequest": {
|
||||
"Pay.amount_msat": 13,
|
||||
@ -4643,6 +4645,10 @@
|
||||
"added": "pre-v0.10.1",
|
||||
"deprecated": "v23.02"
|
||||
},
|
||||
"NewAddr.p2tr": {
|
||||
"added": "v23.08",
|
||||
"deprecated": false
|
||||
},
|
||||
"Pay": {
|
||||
"added": "pre-v0.10.1",
|
||||
"deprecated": null
|
||||
|
@ -972,7 +972,7 @@ struct amount_sat change_fee(u32 feerate_perkw, size_t total_weight)
|
||||
struct amount_sat fee;
|
||||
|
||||
/* Must be able to pay for its own additional weight */
|
||||
outweight = bitcoin_tx_output_weight(BITCOIN_SCRIPTPUBKEY_P2WPKH_LEN);
|
||||
outweight = bitcoin_tx_output_weight(chainparams->is_elements ? BITCOIN_SCRIPTPUBKEY_P2WPKH_LEN : BITCOIN_SCRIPTPUBKEY_P2TR_LEN);
|
||||
|
||||
/* Rounding can cause off by one errors, so we do this */
|
||||
if (!amount_sat_sub(&fee,
|
||||
|
@ -330,11 +330,13 @@ size_t bitcoin_tx_2of2_input_witness_weight(void);
|
||||
struct amount_sat change_fee(u32 feerate_perkw, size_t total_weight);
|
||||
|
||||
/**
|
||||
* change_amount - Is it worth making a P2WPKH change output at this feerate?
|
||||
* change_amount - Is it worth making a change output at this feerate?
|
||||
* @excess: input amount we have above the tx fee and other outputs.
|
||||
* @feerate_perkw: feerate.
|
||||
* @total_weight: current weight of tx.
|
||||
*
|
||||
* Change script is P2TR for Bitcoin, P2WPKH for Elements
|
||||
*
|
||||
* If it's not worth (or possible) to make change, returns AMOUNT_SAT(0).
|
||||
* Otherwise returns the amount of the change output to add (@excess minus
|
||||
* the change_fee()).
|
||||
|
@ -349,9 +349,9 @@ struct bitcoin_tx **channel_txs(const tal_t *ctx,
|
||||
|
||||
/* Set the remote/local pubkeys on the commitment tx psbt */
|
||||
psbt_input_add_pubkey(txs[0]->psbt, 0,
|
||||
&channel->funding_pubkey[side]);
|
||||
&channel->funding_pubkey[side], false /* is_taproot */);
|
||||
psbt_input_add_pubkey(txs[0]->psbt, 0,
|
||||
&channel->funding_pubkey[!side]);
|
||||
&channel->funding_pubkey[!side], false /* is_taproot */);
|
||||
|
||||
add_htlcs(&txs, *htlcmap, channel, &keyset, side);
|
||||
|
||||
|
@ -81,7 +81,7 @@ penalty_tx_create(const tal_t *ctx,
|
||||
bitcoin_tx_add_output(tx, final_scriptpubkey, NULL, to_them_sats);
|
||||
assert((final_index == NULL) == (final_ext_key == NULL));
|
||||
if (final_index)
|
||||
psbt_add_keypath_to_last_output(tx, *final_index, final_ext_key);
|
||||
psbt_add_keypath_to_last_output(tx, *final_index, final_ext_key, is_p2tr(final_scriptpubkey, NULL));
|
||||
|
||||
/* Worst-case sig is 73 bytes */
|
||||
weight = bitcoin_tx_weight(tx) + 1 + 3 + 73 + 0 + tal_count(wscript);
|
||||
|
BIN
cln-grpc/proto/node.proto
generated
BIN
cln-grpc/proto/node.proto
generated
Binary file not shown.
BIN
cln-grpc/src/convert.rs
generated
BIN
cln-grpc/src/convert.rs
generated
Binary file not shown.
BIN
cln-rpc/src/model.rs
generated
BIN
cln-rpc/src/model.rs
generated
Binary file not shown.
@ -52,7 +52,7 @@ struct bitcoin_tx *create_close_tx(const tal_t *ctx,
|
||||
assert((local_wallet_index == NULL) == (local_wallet_ext_key == NULL));
|
||||
if (local_wallet_index)
|
||||
psbt_add_keypath_to_last_output(
|
||||
tx, *local_wallet_index, local_wallet_ext_key);
|
||||
tx, *local_wallet_index, local_wallet_ext_key, is_p2tr(script, NULL));
|
||||
num_outputs++;
|
||||
}
|
||||
|
||||
|
@ -139,9 +139,9 @@ struct bitcoin_tx *initial_channel_tx(const tal_t *ctx,
|
||||
|
||||
if (init_tx) {
|
||||
psbt_input_add_pubkey(init_tx->psbt, 0,
|
||||
&channel->funding_pubkey[side]);
|
||||
&channel->funding_pubkey[side], false /* is_taproot */);
|
||||
psbt_input_add_pubkey(init_tx->psbt, 0,
|
||||
&channel->funding_pubkey[!side]);
|
||||
&channel->funding_pubkey[!side], false /* is_taproot */);
|
||||
}
|
||||
|
||||
return init_tx;
|
||||
|
@ -3,9 +3,8 @@
|
||||
#include <common/psbt_keypath.h>
|
||||
#include <common/utils.h>
|
||||
#include <wally_bip32.h>
|
||||
#include <wally_psbt.h>
|
||||
|
||||
void psbt_set_keypath(u32 index, const struct ext_key *ext, struct wally_map *map_in) {
|
||||
void psbt_output_set_keypath(u32 index, const struct ext_key *ext, bool is_taproot, struct wally_psbt_output *output) {
|
||||
u8 fingerprint[BIP32_KEY_FINGERPRINT_LEN];
|
||||
if (bip32_key_get_fingerprint(
|
||||
(struct ext_key *) ext, fingerprint, sizeof(fingerprint)) != WALLY_OK)
|
||||
@ -14,20 +13,30 @@ void psbt_set_keypath(u32 index, const struct ext_key *ext, struct wally_map *ma
|
||||
u32 path[1];
|
||||
path[0] = index;
|
||||
|
||||
if (wally_map_keypath_add(map_in,
|
||||
ext->pub_key, sizeof(ext->pub_key),
|
||||
fingerprint, sizeof(fingerprint),
|
||||
path, 1) != WALLY_OK)
|
||||
abort();
|
||||
if (is_taproot) {
|
||||
if (wally_psbt_output_taproot_keypath_add(output,
|
||||
ext->pub_key + 1, sizeof(ext->pub_key) - 1,
|
||||
NULL, 0,
|
||||
fingerprint, sizeof(fingerprint),
|
||||
path, 1) != WALLY_OK)
|
||||
abort();
|
||||
} else {
|
||||
if (wally_psbt_output_keypath_add(output,
|
||||
ext->pub_key, sizeof(ext->pub_key),
|
||||
fingerprint, sizeof(fingerprint),
|
||||
path, 1) != WALLY_OK)
|
||||
abort();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void psbt_add_keypath_to_last_output(struct bitcoin_tx *tx,
|
||||
u32 key_index,
|
||||
const struct ext_key *ext) {
|
||||
const struct ext_key *ext,
|
||||
bool is_taproot) {
|
||||
size_t outndx = tx->psbt->num_outputs - 1;
|
||||
struct wally_map *map_in = &tx->psbt->outputs[outndx].keypaths;
|
||||
|
||||
tal_wally_start();
|
||||
psbt_set_keypath(key_index, ext, map_in);
|
||||
psbt_output_set_keypath(key_index, ext, is_taproot, &tx->psbt->outputs[outndx]);
|
||||
tal_wally_end(tx->psbt);
|
||||
}
|
||||
|
@ -3,20 +3,23 @@
|
||||
|
||||
#include "config.h"
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <wally_psbt.h>
|
||||
|
||||
struct bitcoin_tx;
|
||||
struct ext_key;
|
||||
struct wally_map;
|
||||
|
||||
/* psbt_set_keypath - Set the keypath of a PSBT output.
|
||||
/* psbt_output_set_keypath - Set the keypath of a PSBT output.
|
||||
*
|
||||
* @index - child index of the wallet key
|
||||
* @ext - extended public key of the immediate parent of the wallet key
|
||||
* @map_in - wally keypaths map
|
||||
* @is_taproot - PSBT output has taproot script
|
||||
* @output - PSBT output to set
|
||||
*/
|
||||
void psbt_set_keypath(u32 index,
|
||||
void psbt_output_set_keypath(u32 index,
|
||||
const struct ext_key *ext,
|
||||
struct wally_map *map_in);
|
||||
bool is_taproot,
|
||||
struct wally_psbt_output *output);
|
||||
|
||||
/* psbt_add_keypath_to_last_output - augment the last output with the
|
||||
* given wallet keypath
|
||||
@ -24,9 +27,11 @@ void psbt_set_keypath(u32 index,
|
||||
* @tx - transaction to modify
|
||||
* @index - child index of the wallet key
|
||||
* @ext - extended public key of the immediate parent of the wallet key
|
||||
* @is_taproot - if the output is taproot
|
||||
*/
|
||||
void psbt_add_keypath_to_last_output(struct bitcoin_tx *tx,
|
||||
u32 index,
|
||||
const struct ext_key *ext);
|
||||
const struct ext_key *ext,
|
||||
bool is_taproot);
|
||||
|
||||
#endif /* LIGHTNING_COMMON_PSBT_KEYPATH_H */
|
||||
|
@ -75,6 +75,9 @@ static const u8 *linearize_input(const tal_t *ctx,
|
||||
wally_psbt_input_set_final_scriptsig(&psbt->inputs[0], NULL, 0);
|
||||
wally_psbt_input_set_witness_script(&psbt->inputs[0], NULL, 0);
|
||||
wally_psbt_input_set_redeem_script(&psbt->inputs[0], NULL, 0);
|
||||
wally_psbt_input_set_taproot_signature(&psbt->inputs[0], NULL, 0);
|
||||
psbt->inputs[0].taproot_leaf_hashes.num_items = 0;
|
||||
psbt->inputs[0].taproot_leaf_paths.num_items = 0;
|
||||
psbt->inputs[0].keypaths.num_items = 0;
|
||||
psbt->inputs[0].signatures.num_items = 0;
|
||||
|
||||
@ -104,6 +107,8 @@ static const u8 *linearize_output(const tal_t *ctx,
|
||||
|
||||
/* We don't care if the keypaths change */
|
||||
psbt->outputs[0].keypaths.num_items = 0;
|
||||
psbt->outputs[0].taproot_leaf_hashes.num_items = 0;
|
||||
psbt->outputs[0].taproot_leaf_paths.num_items = 0;
|
||||
/* And you can add scripts, no problem */
|
||||
wally_psbt_output_set_witness_script(&psbt->outputs[0], NULL, 0);
|
||||
wally_psbt_output_set_redeem_script(&psbt->outputs[0], NULL, 0);
|
||||
|
File diff suppressed because one or more lines are too long
@ -613,6 +613,7 @@ def waitsendpay2py(m):
|
||||
|
||||
def newaddr2py(m):
|
||||
return remove_default({
|
||||
"p2tr": m.p2tr, # PrimitiveField in generate_composite
|
||||
"bech32": m.bech32, # PrimitiveField in generate_composite
|
||||
"p2sh_segwit": m.p2sh_segwit, # PrimitiveField in generate_composite
|
||||
})
|
||||
|
@ -17,8 +17,8 @@ The funding transaction needs to be confirmed before funds can be used.
|
||||
*addresstype* specifies the type of address wanted; currently *bech32*
|
||||
(e.g. `tb1qu9j4lg5f9rgjyfhvfd905vw46eg39czmktxqgg` on bitcoin testnet
|
||||
or `bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej` on
|
||||
bitcoin mainnet). The special value *all* generates all known address types
|
||||
for the same underlying key.
|
||||
bitcoin mainnet), or *p2tr* taproot addresses. The special value *all*
|
||||
generates all known address types for the same underlying key.
|
||||
|
||||
If no *addresstype* is specified the address generated is a *bech32* address.
|
||||
|
||||
@ -30,6 +30,7 @@ RETURN VALUE
|
||||
[comment]: # (GENERATE-FROM-SCHEMA-START)
|
||||
On success, an object is returned, containing:
|
||||
|
||||
- **p2tr** (string, optional): The taproot address *(added v23.08)*
|
||||
- **bech32** (string, optional): The bech32 (native segwit) address
|
||||
- **p2sh-segwit** (string, optional): The p2sh-wrapped address **deprecated, removal in v23.11**
|
||||
|
||||
@ -56,4 +57,4 @@ RESOURCES
|
||||
|
||||
Main web site: <https://github.com/ElementsProject/lightning>
|
||||
|
||||
[comment]: # ( SHA256STAMP:90d550bc2290dd2ab6ee67e377679fe45230a14ba6f4608fda8e51bb6670cc07)
|
||||
[comment]: # ( SHA256STAMP:f93771e450afe0fc20b2ff9763ba7654d4caf17c35cf45186f2cb9146a67503f)
|
||||
|
@ -8,6 +8,7 @@
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"bech32",
|
||||
"p2tr",
|
||||
"all"
|
||||
]
|
||||
}
|
||||
|
@ -4,6 +4,11 @@
|
||||
"additionalProperties": false,
|
||||
"required": [],
|
||||
"properties": {
|
||||
"p2tr": {
|
||||
"added": "v23.08",
|
||||
"type": "string",
|
||||
"description": "The taproot address"
|
||||
},
|
||||
"bech32": {
|
||||
"type": "string",
|
||||
"description": "The bech32 (native segwit) address"
|
||||
|
@ -489,7 +489,7 @@ static void sign_our_inputs(struct utxo **utxos, struct wally_psbt *psbt)
|
||||
* requires the HSM to find the pubkey, and we
|
||||
* skip doing that until now as a bit of a reduction
|
||||
* of complexity in the calling code */
|
||||
psbt_input_add_pubkey(psbt, j, &pubkey);
|
||||
psbt_input_add_pubkey(psbt, j, &pubkey, utxo->scriptPubkey && is_p2tr(utxo->scriptPubkey, NULL));
|
||||
|
||||
/* It's actually a P2WSH in this case. */
|
||||
if (utxo->close_info && utxo->close_info->option_anchors) {
|
||||
@ -507,6 +507,8 @@ static void sign_our_inputs(struct utxo **utxos, struct wally_psbt *psbt)
|
||||
sizeof(privkey.secret.data),
|
||||
EC_FLAG_GRIND_R) != WALLY_OK) {
|
||||
tal_wally_end(psbt);
|
||||
/* Converting to v0 for log consumption */
|
||||
psbt_set_version(psbt, 0);
|
||||
hsmd_status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
||||
"Received wally_err attempting to "
|
||||
"sign utxo with key %s. PSBT: %s",
|
||||
|
@ -290,7 +290,7 @@ static struct bitcoin_tx *spend_anchor(const tal_t *ctx,
|
||||
psbt_input_set_wit_utxo(psbt, 1,
|
||||
scriptpubkey_p2wsh(tmpctx, adet->anchor_wscript),
|
||||
AMOUNT_SAT(330));
|
||||
psbt_input_add_pubkey(psbt, 1, &channel->local_funding_pubkey);
|
||||
psbt_input_add_pubkey(psbt, 1, &channel->local_funding_pubkey, false);
|
||||
|
||||
if (!amount_sat_add(&change, utxos[0]->amount, AMOUNT_SAT(330))
|
||||
|| !amount_sat_sub(&change, change, fee)) {
|
||||
|
@ -398,6 +398,10 @@ struct channel *new_channel(struct peer *peer, u64 dbid,
|
||||
struct channel *channel = tal(peer->ld, struct channel);
|
||||
struct amount_msat htlc_min, htlc_max;
|
||||
|
||||
bool anysegwit = !chainparams->is_elements && feature_negotiated(peer->ld->our_features,
|
||||
peer->their_features,
|
||||
OPT_SHUTDOWN_ANYSEGWIT);
|
||||
|
||||
assert(dbid != 0);
|
||||
channel->peer = peer;
|
||||
channel->dbid = dbid;
|
||||
@ -477,13 +481,18 @@ struct channel *new_channel(struct peer *peer, u64 dbid,
|
||||
channel->shutdown_wrong_funding
|
||||
= tal_steal(channel, shutdown_wrong_funding);
|
||||
channel->closing_feerate_range = NULL;
|
||||
if (local_shutdown_scriptpubkey)
|
||||
if (local_shutdown_scriptpubkey) {
|
||||
channel->shutdown_scriptpubkey[LOCAL]
|
||||
= tal_steal(channel, local_shutdown_scriptpubkey);
|
||||
else
|
||||
} else if (anysegwit) {
|
||||
channel->shutdown_scriptpubkey[LOCAL]
|
||||
= p2tr_for_keyidx(channel, channel->peer->ld,
|
||||
channel->final_key_idx);
|
||||
} else {
|
||||
channel->shutdown_scriptpubkey[LOCAL]
|
||||
= p2wpkh_for_keyidx(channel, channel->peer->ld,
|
||||
channel->final_key_idx);
|
||||
channel->final_key_idx);
|
||||
}
|
||||
channel->last_was_revoke = last_was_revoke;
|
||||
channel->last_sent_commit = tal_steal(channel, last_sent_commit);
|
||||
channel->first_blocknum = first_blocknum;
|
||||
@ -534,9 +543,17 @@ struct channel *new_channel(struct peer *peer, u64 dbid,
|
||||
channel->state_change_cause = reason;
|
||||
|
||||
/* Make sure we see any spends using this key */
|
||||
txfilter_add_scriptpubkey(peer->ld->owned_txfilter,
|
||||
take(p2wpkh_for_keyidx(NULL, peer->ld,
|
||||
channel->final_key_idx)));
|
||||
if (!local_shutdown_scriptpubkey) {
|
||||
if (anysegwit) {
|
||||
txfilter_add_scriptpubkey(peer->ld->owned_txfilter,
|
||||
take(p2tr_for_keyidx(NULL, peer->ld,
|
||||
channel->final_key_idx)));
|
||||
} else {
|
||||
txfilter_add_scriptpubkey(peer->ld->owned_txfilter,
|
||||
take(p2wpkh_for_keyidx(NULL, peer->ld,
|
||||
channel->final_key_idx)));
|
||||
}
|
||||
}
|
||||
/* scid is NULL when opening a new channel so we don't
|
||||
* need to set error in that case as well */
|
||||
if (is_stub_scid(scid))
|
||||
|
@ -674,6 +674,11 @@ static struct command_result *json_close(struct command *cmd,
|
||||
index_val = (u32) channel->final_key_idx;
|
||||
final_index = &index_val;
|
||||
|
||||
/* Don't send a scriptpubkey peer won't accept */
|
||||
anysegwit = !chainparams->is_elements && feature_negotiated(cmd->ld->our_features,
|
||||
channel->peer->their_features,
|
||||
OPT_SHUTDOWN_ANYSEGWIT);
|
||||
|
||||
/* If we've set a local shutdown script for this peer, and it's not the
|
||||
* default upfront script, try to close to a different channel.
|
||||
* Error is an operator error */
|
||||
@ -682,8 +687,13 @@ static struct command_result *json_close(struct command *cmd,
|
||||
tal_count(close_to_script),
|
||||
channel->shutdown_scriptpubkey[LOCAL],
|
||||
tal_count(channel->shutdown_scriptpubkey[LOCAL]))) {
|
||||
u8 *default_close_to = p2wpkh_for_keyidx(tmpctx, cmd->ld,
|
||||
channel->final_key_idx);
|
||||
u8 *default_close_to = NULL;
|
||||
if (anysegwit)
|
||||
default_close_to = p2tr_for_keyidx(tmpctx, cmd->ld,
|
||||
channel->final_key_idx);
|
||||
else
|
||||
default_close_to = p2wpkh_for_keyidx(tmpctx, cmd->ld,
|
||||
channel->final_key_idx);
|
||||
if (!memeq(default_close_to, tal_count(default_close_to),
|
||||
channel->shutdown_scriptpubkey[LOCAL],
|
||||
tal_count(channel->shutdown_scriptpubkey[LOCAL]))) {
|
||||
@ -722,10 +732,6 @@ static struct command_result *json_close(struct command *cmd,
|
||||
} else
|
||||
close_script_set = false;
|
||||
|
||||
/* Don't send a scriptpubkey peer won't accept */
|
||||
anysegwit = feature_negotiated(cmd->ld->our_features,
|
||||
channel->peer->their_features,
|
||||
OPT_SHUTDOWN_ANYSEGWIT);
|
||||
if (!valid_shutdown_scriptpubkey(channel->shutdown_scriptpubkey[LOCAL],
|
||||
anysegwit, false)) {
|
||||
/* Explicit check for future segwits. */
|
||||
|
@ -1287,7 +1287,7 @@ wallet_commit_channel(struct lightningd *ld,
|
||||
= tal_steal(channel, our_upfront_shutdown_script);
|
||||
else
|
||||
channel->shutdown_scriptpubkey[LOCAL]
|
||||
= p2wpkh_for_keyidx(channel, channel->peer->ld,
|
||||
= p2tr_for_keyidx(channel, channel->peer->ld,
|
||||
channel->final_key_idx);
|
||||
|
||||
/* Can't have gotten their alias for this channel yet. */
|
||||
|
@ -691,9 +691,10 @@ static struct bitcoin_tx *onchaind_tx_unsigned(const tal_t *ctx,
|
||||
bitcoin_tx_add_input(tx, &info->out, info->to_self_delay,
|
||||
NULL, info->out_sats, NULL, info->wscript);
|
||||
|
||||
/* FIXME should this be p2tr now? */
|
||||
bitcoin_tx_add_output(
|
||||
tx, scriptpubkey_p2wpkh(tmpctx, &final_key), NULL, info->out_sats);
|
||||
psbt_add_keypath_to_last_output(tx, channel->final_key_idx, &final_wallet_ext_key);
|
||||
psbt_add_keypath_to_last_output(tx, channel->final_key_idx, &final_wallet_ext_key, false /* is_taproot */);
|
||||
|
||||
/* Worst-case sig is 73 bytes */
|
||||
weight = bitcoin_tx_weight(tx) + 1 + 3 + 73 + 0 + tal_count(info->wscript);
|
||||
|
@ -217,6 +217,15 @@ u8 *p2wpkh_for_keyidx(const tal_t *ctx, struct lightningd *ld, u64 keyidx)
|
||||
return scriptpubkey_p2wpkh(ctx, &shutdownkey);
|
||||
}
|
||||
|
||||
u8 *p2tr_for_keyidx(const tal_t *ctx, struct lightningd *ld, u64 keyidx)
|
||||
{
|
||||
struct pubkey shutdownkey;
|
||||
|
||||
bip32_pubkey(ld, &shutdownkey, keyidx);
|
||||
|
||||
return scriptpubkey_p2tr(ctx, &shutdownkey);
|
||||
}
|
||||
|
||||
static void sign_last_tx(struct channel *channel,
|
||||
struct bitcoin_tx *last_tx,
|
||||
struct bitcoin_signature *last_sig)
|
||||
|
@ -100,6 +100,7 @@ void channel_errmsg(struct channel *channel,
|
||||
const u8 *err_for_them);
|
||||
|
||||
u8 *p2wpkh_for_keyidx(const tal_t *ctx, struct lightningd *ld, u64 keyidx);
|
||||
u8 *p2tr_for_keyidx(const tal_t *ctx, struct lightningd *ld, u64 keyidx);
|
||||
|
||||
/* We've loaded peers from database, set them going. */
|
||||
void setup_peers(struct lightningd *ld);
|
||||
|
@ -969,8 +969,8 @@ static char *check_balances(const tal_t *ctx,
|
||||
|
||||
static bool is_segwit_output(struct wally_tx_output *output)
|
||||
{
|
||||
const u8 *wit_prog = wally_tx_output_get_script(tmpctx, output);
|
||||
return is_p2wsh(wit_prog, NULL) || is_p2wpkh(wit_prog, NULL);
|
||||
const u8 *script = wally_tx_output_get_script(tmpctx, output);
|
||||
return is_known_segwit_scripttype(script);
|
||||
}
|
||||
|
||||
static void set_remote_upfront_shutdown(struct state *state,
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "config.h"
|
||||
#include <bitcoin/chainparams.h>
|
||||
#include <bitcoin/psbt.h>
|
||||
#include <bitcoin/script.h>
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/json_out/json_out.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
@ -511,7 +512,7 @@ mw_get_change_addr(struct multiwithdraw_command *mw)
|
||||
req = jsonrpc_request_start(mw->cmd->plugin, mw->cmd,
|
||||
"newaddr",
|
||||
&mw_after_newaddr, &mw_forward_error, mw);
|
||||
json_add_string(req->js, "addresstype", "bech32");
|
||||
json_add_string(req->js, "addresstype", chainparams->is_elements ? "bech32" : "p2tr");
|
||||
return send_outreq(mw->cmd->plugin, req);
|
||||
}
|
||||
|
||||
@ -524,7 +525,7 @@ mw_after_newaddr(struct command *cmd,
|
||||
const jsmntok_t *bech32tok;
|
||||
const u8 *script;
|
||||
|
||||
bech32tok = json_get_member(buf, result, "bech32");
|
||||
bech32tok = json_get_member(buf, result, chainparams->is_elements ? "bech32" : "p2tr");
|
||||
if (!bech32tok
|
||||
|| json_to_address_scriptpubkey(mw, chainparams, buf, bech32tok,
|
||||
&script) != ADDRESS_PARSE_SUCCESS)
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "config.h"
|
||||
#include <bitcoin/psbt.h>
|
||||
#include <bitcoin/script.h>
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <common/addr.h>
|
||||
#include <common/json_param.h>
|
||||
@ -573,7 +574,8 @@ static struct command_result *newaddr_sweep_done(struct command *cmd,
|
||||
struct listfunds_info *info)
|
||||
{
|
||||
struct out_req *req;
|
||||
const jsmntok_t *addr = json_get_member(buf, result, "bech32");
|
||||
const jsmntok_t *addr = json_get_member(buf, result, chainparams->is_elements ? "bech32" : "p2tr");
|
||||
assert(addr);
|
||||
|
||||
info->txp = tal(info, struct txprepare);
|
||||
info->txp->is_upgrade = true;
|
||||
@ -627,6 +629,7 @@ static struct command_result *json_upgradewallet(struct command *cmd,
|
||||
newaddr_sweep_done,
|
||||
forward_error,
|
||||
info);
|
||||
json_add_string(req->js, "addresstype", "all");
|
||||
return send_outreq(cmd->plugin, req);
|
||||
}
|
||||
|
||||
|
@ -395,13 +395,13 @@ def test_bookkeeping_missed_chans_leases(node_factory, bitcoind):
|
||||
|
||||
# l1 events
|
||||
exp_events = [('channel_open', open_amt * 1000 + lease_fee, 0),
|
||||
('onchain_fee', 1224000, 0),
|
||||
('onchain_fee', 1320000, 0),
|
||||
('lease_fee', 0, lease_fee),
|
||||
('journal_entry', 0, invoice_msat)]
|
||||
_check_events(l1, channel_id, exp_events)
|
||||
|
||||
exp_events = [('channel_open', open_amt * 1000, 0),
|
||||
('onchain_fee', 796000, 0),
|
||||
('onchain_fee', 892000, 0),
|
||||
('lease_fee', lease_fee, 0),
|
||||
('journal_entry', invoice_msat, 0)]
|
||||
_check_events(l2, channel_id, exp_events)
|
||||
@ -461,7 +461,7 @@ def test_bookkeeping_missed_chans_pushed(node_factory, bitcoind):
|
||||
|
||||
# l1 events
|
||||
exp_events = [('channel_open', open_amt * 1000, 0),
|
||||
('onchain_fee', 4567000, 0),
|
||||
('onchain_fee', 4927000, 0),
|
||||
('pushed', 0, push_amt),
|
||||
('journal_entry', 0, invoice_msat)]
|
||||
_check_events(l1, channel_id, exp_events)
|
||||
@ -534,7 +534,7 @@ def test_bookkeeping_missed_chans_pay_after(node_factory, bitcoind):
|
||||
|
||||
# l1 events
|
||||
exp_events = [('channel_open', open_amt * 1000, 0),
|
||||
('onchain_fee', 4567000, 0),
|
||||
('onchain_fee', 4927000, 0),
|
||||
('invoice', 0, invoice_msat)]
|
||||
_check_events(l1, channel_id, exp_events)
|
||||
|
||||
|
@ -1338,7 +1338,7 @@ def test_penalty_htlc_tx_fulfill(node_factory, bitcoind, chainparams, anchors):
|
||||
]}
|
||||
] + [
|
||||
{'blockheight': 108, 'accounts': [
|
||||
{'balance_msat': '995433000msat', 'account_id': 'wallet'},
|
||||
{'balance_msat': '995073000msat', 'account_id': 'wallet'},
|
||||
{'balance_msat': '500000000msat', 'account_id': first_channel_id(l1, l2)},
|
||||
{'balance_msat': '499994999msat', 'account_id': channel_id}]}
|
||||
] * 2 # duplicated; we stop and restart l2 twice (both at block 108)
|
||||
@ -3203,7 +3203,7 @@ def test_shutdown(node_factory):
|
||||
|
||||
|
||||
@pytest.mark.developer("needs to set upfront_shutdown_script")
|
||||
def test_option_upfront_shutdown_script(node_factory, bitcoind, executor):
|
||||
def test_option_upfront_shutdown_script(node_factory, bitcoind, executor, chainparams):
|
||||
l1 = node_factory.get_node(start=False, allow_warning=True)
|
||||
# Insist on upfront script we're not going to match.
|
||||
# '0014' + l1.rpc.call('dev-listaddrs', [10])['addresses'][-1]['bech32_redeemscript']
|
||||
@ -3256,8 +3256,11 @@ def test_option_upfront_shutdown_script(node_factory, bitcoind, executor):
|
||||
|
||||
# Now, if we specify upfront and it's OK, all good.
|
||||
l1.stop()
|
||||
# We need to prepend the segwit version (0) and push opcode (14).
|
||||
l1.daemon.env["DEV_OPENINGD_UPFRONT_SHUTDOWN_SCRIPT"] = '0014' + addr['bech32_redeemscript']
|
||||
if not chainparams['elements']:
|
||||
l1.daemon.env["DEV_OPENINGD_UPFRONT_SHUTDOWN_SCRIPT"] = bitcoind.rpc.getaddressinfo(addr['p2tr'])['scriptPubKey']
|
||||
else:
|
||||
# We need to prepend the segwit version (0) and push opcode (14).
|
||||
l1.daemon.env["DEV_OPENINGD_UPFRONT_SHUTDOWN_SCRIPT"] = '0014' + addr['bech32_redeemscript']
|
||||
l1.start()
|
||||
|
||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
||||
@ -3573,8 +3576,8 @@ def test_close_feerate_range(node_factory, bitcoind, chainparams):
|
||||
l1.rpc.close(l2.info['id'], feerange=['253perkw', 'normal'])
|
||||
|
||||
if not chainparams['elements']:
|
||||
l1_range = [139, 4140]
|
||||
l2_range = [1035, 1000000]
|
||||
l1_range = [151, 4500]
|
||||
l2_range = [1125, 1000000]
|
||||
else:
|
||||
# That fee output is a little chunky.
|
||||
l1_range = [221, 6577]
|
||||
|
@ -636,7 +636,7 @@ def test_withdraw_misc(node_factory, bitcoind, chainparams):
|
||||
{'type': 'chain_mvt', 'credit_msat': 2000000000, 'debit_msat': 0, 'tags': ['deposit']},
|
||||
{'type': 'chain_mvt', 'credit_msat': 2000000000, 'debit_msat': 0, 'tags': ['deposit']},
|
||||
{'type': 'chain_mvt', 'credit_msat': 2000000000, 'debit_msat': 0, 'tags': ['deposit']},
|
||||
{'type': 'chain_mvt', 'credit_msat': 11957603000, 'debit_msat': 0, 'tags': ['deposit']},
|
||||
{'type': 'chain_mvt', 'credit_msat': 11956163000, 'debit_msat': 0, 'tags': ['deposit']},
|
||||
]
|
||||
|
||||
check_coin_moves(l1, 'external', external_moves, chainparams)
|
||||
|
@ -316,7 +316,10 @@ def test_txprepare(node_factory, bitcoind, chainparams):
|
||||
assert o['scriptPubKey']['type'] == 'witness_v0_keyhash'
|
||||
assert scriptpubkey_addr(o['scriptPubKey']) == addr
|
||||
else:
|
||||
assert o['scriptPubKey']['type'] in ['witness_v0_keyhash', 'fee']
|
||||
if chainparams['elements']:
|
||||
o['scriptPubKey']['type'] in ['witness_v0_keyhash', 'fee']
|
||||
else:
|
||||
assert o['scriptPubKey']['type'] in ['witness_v1_taproot', 'fee']
|
||||
|
||||
# Now prepare one with no change.
|
||||
prep2 = l1.rpc.txprepare([{addr: 'all'}])
|
||||
@ -438,7 +441,10 @@ def test_txprepare(node_factory, bitcoind, chainparams):
|
||||
assert decode['vout'][outnum2]['scriptPubKey']['type'] == 'witness_v0_keyhash'
|
||||
assert scriptpubkey_addr(decode['vout'][outnum2]['scriptPubKey']) == addr
|
||||
|
||||
assert decode['vout'][changenum]['scriptPubKey']['type'] == 'witness_v0_keyhash'
|
||||
if chainparams['elements']:
|
||||
assert decode['vout'][changenum]['scriptPubKey']['type'] == 'witness_v0_keyhash'
|
||||
else:
|
||||
assert decode['vout'][changenum]['scriptPubKey']['type'] == 'witness_v1_taproot'
|
||||
|
||||
|
||||
def test_reserveinputs(node_factory, bitcoind, chainparams):
|
||||
@ -1237,45 +1243,39 @@ def test_hsmtool_secret_decryption(node_factory):
|
||||
def test_hsmtool_dump_descriptors(node_factory, bitcoind):
|
||||
l1 = node_factory.get_node()
|
||||
l1.fundwallet(10**6)
|
||||
|
||||
# Get a tpub descriptor of lightningd's wallet
|
||||
hsm_path = os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, "hsm_secret")
|
||||
cmd_line = ["tools/hsmtool", "dumponchaindescriptors", hsm_path, "testnet"]
|
||||
out = subprocess.check_output(cmd_line).decode("utf8").split("\n")
|
||||
descriptor = [l for l in out if l.startswith("wpkh(tpub")][0]
|
||||
descriptors = subprocess.check_output(cmd_line).decode("utf8").split("\n")
|
||||
|
||||
# If we switch wallet, we can't generate address: do so now.
|
||||
mine_to_addr = bitcoind.rpc.getnewaddress()
|
||||
# Deprecated or empty line
|
||||
descriptors = [desc for desc in descriptors if not (desc.startswith("sh(wpkh(") or desc == '')]
|
||||
|
||||
# Import the descriptor to bitcoind
|
||||
try:
|
||||
bitcoind.rpc.importmulti([{
|
||||
"desc": descriptor,
|
||||
# No need to rescan, we'll transact afterward
|
||||
"timestamp": "now",
|
||||
# The default
|
||||
"range": [0, 99]
|
||||
}])
|
||||
except JSONRPCError:
|
||||
# Oh look, a new API!
|
||||
# Need watch-only wallet, since descriptor has no privkeys.
|
||||
bitcoind.rpc.createwallet("lightningd-ro", True)
|
||||
withdraw_addr = None
|
||||
index_offset = 2 # index starts handing out addrs at 2
|
||||
|
||||
# FIXME: No way to access non-default wallet in python-bitcoinlib
|
||||
bitcoind.rpc.unloadwallet("lightningd-tests", True)
|
||||
bitcoind.rpc.importdescriptors([{
|
||||
"desc": descriptor,
|
||||
# No need to rescan, we'll transact afterward
|
||||
"timestamp": "now",
|
||||
# The default
|
||||
"range": [0, 99]
|
||||
}])
|
||||
# Generate twenty addresses for all known descriptors
|
||||
cln_addrs = [l1.rpc.newaddr('all') for _ in range(20)]
|
||||
for descriptor in descriptors:
|
||||
for i, cln_addr in enumerate(cln_addrs):
|
||||
computed_addr = bitcoind.rpc.deriveaddresses(descriptor, [i + index_offset, i + index_offset])[0]
|
||||
if descriptor.startswith("wpkh"):
|
||||
assert cln_addr["bech32"] == computed_addr
|
||||
withdraw_addr = cln_addr["bech32"]
|
||||
elif descriptor.startswith("tr"):
|
||||
assert cln_addr["p2tr"] == computed_addr
|
||||
withdraw_addr = cln_addr["p2tr"]
|
||||
else:
|
||||
raise Exception('Unexpected descriptor!')
|
||||
|
||||
# Funds sent to lightningd can be retrieved by bitcoind
|
||||
addr = l1.rpc.newaddr()["bech32"]
|
||||
txid = l1.rpc.withdraw(addr, 10**3)["txid"]
|
||||
bitcoind.generate_block(1, txid, mine_to_addr)
|
||||
assert len(bitcoind.rpc.listunspent(1, 1, [addr])) == 1
|
||||
# For last address per type:
|
||||
# Funds sent to lightningd can be retrieved by bitcoind
|
||||
txid = l1.rpc.withdraw(withdraw_addr, 10**3)["txid"]
|
||||
bitcoind.generate_block(1, txid, bitcoind.rpc.getnewaddress())
|
||||
l1.daemon.wait_for_log('Owning output .* txid {} CONFIRMED'.format(txid))
|
||||
actual_index = len(cln_addrs) - 1 + index_offset
|
||||
res = bitcoind.rpc.scantxoutset("start", [{"desc": descriptor, "range": [actual_index, actual_index]}])
|
||||
assert res["total_amount"] == Decimal('0.00001000')
|
||||
|
||||
|
||||
def test_hsmtool_generatehsm(node_factory):
|
||||
@ -1545,6 +1545,44 @@ def test_withdraw_bech32m(node_factory, bitcoind):
|
||||
assert set([output['scriptPubKey']['address'] for output in outputs]).issuperset([addr.lower() for addr in addrs])
|
||||
|
||||
|
||||
@unittest.skipIf(TEST_NETWORK != 'regtest', "Elements-based schnorr is not yet supported")
|
||||
def test_p2tr_deposit_withdrawal(node_factory, bitcoind):
|
||||
|
||||
# Don't get any funds from previous runs.
|
||||
l1 = node_factory.get_node(random_hsm=True)
|
||||
|
||||
# Can fetch p2tr addresses through 'all' or specifically
|
||||
deposit_addrs = [l1.rpc.newaddr('all')] * 3
|
||||
withdrawal_addr = l1.rpc.newaddr('p2tr')
|
||||
|
||||
# Add some funds to withdraw
|
||||
for addr_type in ['p2tr', 'bech32']:
|
||||
for i in range(3):
|
||||
l1.bitcoin.rpc.sendtoaddress(deposit_addrs[i][addr_type], 1)
|
||||
|
||||
bitcoind.generate_block(1)
|
||||
|
||||
wait_for(lambda: len(l1.rpc.listfunds()['outputs']) == 6)
|
||||
for i in range(3):
|
||||
assert l1.rpc.listfunds()['outputs'][i]['address'] == deposit_addrs[i]['p2tr']
|
||||
assert l1.rpc.listfunds()['outputs'][i + 3]['address'] == deposit_addrs[i]['bech32']
|
||||
l1.rpc.withdraw(withdrawal_addr['p2tr'], 100000000 * 5)
|
||||
wait_for(lambda: len(bitcoind.rpc.getrawmempool()) == 1)
|
||||
raw_tx = bitcoind.rpc.getrawtransaction(bitcoind.rpc.getrawmempool()[0], 1)
|
||||
assert len(raw_tx['vin']) == 6
|
||||
assert len(raw_tx['vout']) == 2
|
||||
# Change goes to p2tr
|
||||
for output in raw_tx['vout']:
|
||||
assert output["scriptPubKey"]["type"] == "witness_v1_taproot"
|
||||
bitcoind.generate_block(1)
|
||||
wait_for(lambda: len(l1.rpc.listtransactions()['transactions']) == 7)
|
||||
|
||||
# Only self-send + change is left
|
||||
wait_for(lambda: len(l1.rpc.listfunds()['outputs']) == 2)
|
||||
|
||||
# make sure tap derivation is embedded in PSBT output
|
||||
|
||||
|
||||
@unittest.skipIf(TEST_NETWORK != 'regtest', "Address is network specific")
|
||||
def test_upgradewallet(node_factory, bitcoind):
|
||||
# Make sure bitcoind doesn't think it's going backwards
|
||||
|
@ -98,7 +98,8 @@ def check_balance_snaps(n, expected_bals):
|
||||
snaps = n.rpc.listsnapshots()['balance_snapshots']
|
||||
for snap, exp in zip(snaps, expected_bals):
|
||||
assert snap['blockheight'] == exp['blockheight']
|
||||
assert _dictify(snap) == _dictify(exp)
|
||||
if _dictify(snap) != _dictify(exp):
|
||||
raise Exception('Unexpected balance snap: {} vs {}'.format(_dictify(snap), _dictify(exp)))
|
||||
|
||||
|
||||
def check_coin_moves(n, account_id, expected_moves, chainparams):
|
||||
@ -409,7 +410,8 @@ def basic_fee(feerate, anchor_expected):
|
||||
|
||||
def closing_fee(feerate, num_outputs):
|
||||
assert num_outputs == 1 or num_outputs == 2
|
||||
weight = 428 + 124 * num_outputs
|
||||
# Assumes p2tr outputs
|
||||
weight = 428 + (8 + 1 + 1 + 1 + 32) * 4 * num_outputs
|
||||
return (weight * feerate) // 1000
|
||||
|
||||
|
||||
|
@ -558,7 +558,7 @@ static int dumponchaindescriptors(const char *hsm_secret_path, const char *old_p
|
||||
if (bip32_key_to_base58(&master_extkey, BIP32_FLAG_KEY_PUBLIC, &enc_xpub) != WALLY_OK)
|
||||
errx(ERROR_LIBWALLY, "Can't encode xpub");
|
||||
|
||||
/* Now we format the descriptor strings (we only ever create P2WPKH and
|
||||
/* Now we format the descriptor strings (we only ever create P2TR, P2WPKH, and
|
||||
* P2SH-P2WPKH outputs). */
|
||||
|
||||
descriptor = tal_fmt(NULL, "wpkh(%s/0/0/*)", enc_xpub);
|
||||
@ -573,6 +573,12 @@ static int dumponchaindescriptors(const char *hsm_secret_path, const char *old_p
|
||||
printf("%s#%s\n", descriptor, checksum.csum);
|
||||
tal_free(descriptor);
|
||||
|
||||
descriptor = tal_fmt(NULL, "tr(%s/0/0/*)", enc_xpub);
|
||||
if (!descriptor_checksum(descriptor, strlen(descriptor), &checksum))
|
||||
errx(ERROR_LIBWALLY, "Can't derive descriptor checksum for tr");
|
||||
printf("%s#%s\n", descriptor, checksum.csum);
|
||||
tal_free(descriptor);
|
||||
|
||||
wally_free_string(enc_xpub);
|
||||
|
||||
return 0;
|
||||
|
@ -1365,9 +1365,9 @@ migrate_inflight_last_tx_to_psbt(struct lightningd *ld, struct db *db)
|
||||
&remote_funding_pubkey, &last_sig))
|
||||
abort();
|
||||
psbt_input_add_pubkey(last_tx->psbt, 0,
|
||||
&local_funding_pubkey);
|
||||
&local_funding_pubkey, false /* is_taproot */);
|
||||
psbt_input_add_pubkey(last_tx->psbt, 0,
|
||||
&remote_funding_pubkey);
|
||||
&remote_funding_pubkey, false /* is_taproot */);
|
||||
|
||||
update_stmt = db_prepare_v2(db,
|
||||
SQL("UPDATE channel_funding_inflights"
|
||||
@ -1461,9 +1461,9 @@ void migrate_last_tx_to_psbt(struct lightningd *ld, struct db *db)
|
||||
&remote_funding_pubkey, &last_sig))
|
||||
abort();
|
||||
psbt_input_add_pubkey(last_tx->psbt, 0,
|
||||
&local_funding_pubkey);
|
||||
&local_funding_pubkey, false /* is_taproot */);
|
||||
psbt_input_add_pubkey(last_tx->psbt, 0,
|
||||
&remote_funding_pubkey);
|
||||
&remote_funding_pubkey, false /* is_taproot */);
|
||||
|
||||
update_stmt = db_prepare_v2(db, SQL("UPDATE channels"
|
||||
" SET last_tx = ?"
|
||||
|
@ -381,15 +381,24 @@ static struct command_result *finish_psbt(struct command *cmd,
|
||||
"Failed to generate change address."
|
||||
" Keys exhausted.");
|
||||
|
||||
bip32_pubkey(cmd->ld, &pubkey, keyidx);
|
||||
b32script = scriptpubkey_p2wpkh(tmpctx, &pubkey);
|
||||
if (chainparams->is_elements) {
|
||||
bip32_pubkey(cmd->ld, &pubkey, keyidx);
|
||||
b32script = scriptpubkey_p2wpkh(tmpctx, &pubkey);
|
||||
} else {
|
||||
b32script = p2tr_for_keyidx(tmpctx, cmd->ld, keyidx);
|
||||
}
|
||||
if (!b32script) {
|
||||
return command_fail(cmd, LIGHTNINGD,
|
||||
"Failed to generate change address."
|
||||
" Keys generation failure");
|
||||
}
|
||||
txfilter_add_scriptpubkey(cmd->ld->owned_txfilter, b32script);
|
||||
|
||||
change_outnum = psbt->num_outputs;
|
||||
psbt_append_output(psbt, b32script, change);
|
||||
/* Add additional weight of output */
|
||||
weight += bitcoin_tx_output_weight(
|
||||
BITCOIN_SCRIPTPUBKEY_P2WPKH_LEN);
|
||||
chainparams->is_elements ? BITCOIN_SCRIPTPUBKEY_P2WPKH_LEN : BITCOIN_SCRIPTPUBKEY_P2TR_LEN);
|
||||
} else {
|
||||
change_outnum = -1;
|
||||
}
|
||||
|
@ -734,6 +734,8 @@ bool wallet_can_spend(struct wallet *w, const u8 *script,
|
||||
*output_is_p2sh = true;
|
||||
else if (is_p2wpkh(script, NULL))
|
||||
*output_is_p2sh = false;
|
||||
else if (is_p2tr(script, NULL))
|
||||
*output_is_p2sh = false;
|
||||
else
|
||||
return false;
|
||||
|
||||
@ -761,6 +763,18 @@ bool wallet_can_spend(struct wallet *w, const u8 *script,
|
||||
return true;
|
||||
}
|
||||
tal_free(s);
|
||||
/* Try taproot output now */
|
||||
s = scriptpubkey_p2tr_derkey(w, ext.pub_key);
|
||||
if (scripteq(s, script)) {
|
||||
/* If we found a used key in the keyscan_gap we should
|
||||
* remember that. */
|
||||
if (i > bip32_max_index)
|
||||
db_set_intvar(w->db, "bip32_max_index", i);
|
||||
tal_free(s);
|
||||
*index = i;
|
||||
return true;
|
||||
}
|
||||
tal_free(s);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -27,11 +27,19 @@
|
||||
#include <wally_psbt.h>
|
||||
#include <wire/wire_sync.h>
|
||||
|
||||
enum addrtype {
|
||||
/* Deprecated! */
|
||||
ADDR_P2SH_SEGWIT = 1,
|
||||
ADDR_BECH32 = 2,
|
||||
ADDR_P2TR = 4,
|
||||
ADDR_ALL = (ADDR_P2SH_SEGWIT + ADDR_BECH32 + ADDR_P2TR)
|
||||
};
|
||||
|
||||
/* May return NULL if encoding error occurs. */
|
||||
static char *
|
||||
encode_pubkey_to_addr(const tal_t *ctx,
|
||||
const struct pubkey *pubkey,
|
||||
bool is_p2sh_p2wpkh,
|
||||
enum addrtype addrtype,
|
||||
/* Output: redeemscript to use to redeem outputs
|
||||
* paying to the address.
|
||||
* May be NULL if redeemscript is do not care. */
|
||||
@ -44,14 +52,16 @@ encode_pubkey_to_addr(const tal_t *ctx,
|
||||
u8 *redeemscript;
|
||||
bool ok;
|
||||
|
||||
if (is_p2sh_p2wpkh) {
|
||||
assert(addrtype != ADDR_ALL);
|
||||
|
||||
if (addrtype == ADDR_P2SH_SEGWIT) {
|
||||
redeemscript = bitcoin_redeem_p2sh_p2wpkh(ctx, pubkey);
|
||||
sha256(&h, redeemscript, tal_count(redeemscript));
|
||||
ripemd160(&h160, h.u.u8, sizeof(h));
|
||||
out = p2sh_to_base58(ctx,
|
||||
chainparams,
|
||||
&h160);
|
||||
} else {
|
||||
} else if (addrtype == ADDR_BECH32) {
|
||||
hrp = chainparams->onchain_hrp;
|
||||
|
||||
/* out buffer is 73 + strlen(human readable part),
|
||||
@ -68,6 +78,21 @@ encode_pubkey_to_addr(const tal_t *ctx,
|
||||
ok = segwit_addr_encode(out, hrp, 0, h160.u.u8, sizeof(h160));
|
||||
if (!ok)
|
||||
out = tal_free(out);
|
||||
} else {
|
||||
assert(addrtype == 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);
|
||||
if (!ok)
|
||||
out = tal_free(out);
|
||||
}
|
||||
|
||||
if (out_redeemscript)
|
||||
@ -78,14 +103,6 @@ encode_pubkey_to_addr(const tal_t *ctx,
|
||||
return out;
|
||||
}
|
||||
|
||||
enum addrtype {
|
||||
/* Deprecated! */
|
||||
ADDR_P2SH_SEGWIT = 1,
|
||||
ADDR_BECH32 = 2,
|
||||
ADDR_ALL = (ADDR_P2SH_SEGWIT + ADDR_BECH32)
|
||||
};
|
||||
|
||||
/* Extract bool indicating "bech32" */
|
||||
static struct command_result *param_newaddr(struct command *cmd,
|
||||
const char *name,
|
||||
const char *buffer,
|
||||
@ -98,11 +115,13 @@ static struct command_result *param_newaddr(struct command *cmd,
|
||||
**addrtype = ADDR_P2SH_SEGWIT;
|
||||
else 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 'bech32', or 'all', not '%.*s'",
|
||||
"'%s' should be 'p2tr', 'bech32', or 'all', not '%.*s'",
|
||||
name, tok->end - tok->start, buffer + tok->start);
|
||||
return NULL;
|
||||
}
|
||||
@ -116,8 +135,9 @@ static struct command_result *json_newaddr(struct command *cmd,
|
||||
struct pubkey pubkey;
|
||||
enum addrtype *addrtype;
|
||||
s64 keyidx;
|
||||
char *p2sh, *bech32;
|
||||
char *p2sh, *bech32, *p2tr;
|
||||
u8 *b32script;
|
||||
u8 *p2tr_script;
|
||||
|
||||
if (!param(cmd, buffer, params,
|
||||
p_opt_def("addresstype", param_newaddr, &addrtype, ADDR_BECH32),
|
||||
@ -132,15 +152,19 @@ static struct command_result *json_newaddr(struct command *cmd,
|
||||
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);
|
||||
if (cmd->ld->deprecated_apis && (*addrtype & ADDR_P2SH_SEGWIT))
|
||||
txfilter_add_scriptpubkey(cmd->ld->owned_txfilter,
|
||||
scriptpubkey_p2sh(tmpctx, b32script));
|
||||
|
||||
p2sh = encode_pubkey_to_addr(cmd, &pubkey, true, NULL);
|
||||
bech32 = encode_pubkey_to_addr(cmd, &pubkey, false, NULL);
|
||||
if (!p2sh || !bech32) {
|
||||
p2sh = encode_pubkey_to_addr(cmd, &pubkey, ADDR_P2SH_SEGWIT, NULL);
|
||||
bech32 = encode_pubkey_to_addr(cmd, &pubkey, ADDR_BECH32, NULL);
|
||||
p2tr = encode_pubkey_to_addr(cmd, &pubkey, ADDR_P2TR, NULL);
|
||||
if (!p2sh || !bech32 || !p2tr) {
|
||||
return command_fail(cmd, LIGHTNINGD,
|
||||
"p2wpkh address encoding failure.");
|
||||
}
|
||||
@ -148,6 +172,8 @@ static struct command_result *json_newaddr(struct command *cmd,
|
||||
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);
|
||||
if (cmd->ld->deprecated_apis && (*addrtype & ADDR_P2SH_SEGWIT))
|
||||
json_add_string(response, "p2sh-segwit", p2sh);
|
||||
return command_success(cmd, response);
|
||||
@ -196,19 +222,28 @@ static struct command_result *json_listaddrs(struct command *cmd,
|
||||
u8 *redeemscript_p2sh;
|
||||
char *out_p2sh = encode_pubkey_to_addr(cmd,
|
||||
&pubkey,
|
||||
true,
|
||||
ADDR_P2SH_SEGWIT,
|
||||
&redeemscript_p2sh);
|
||||
|
||||
// bech32 : p2wpkh
|
||||
u8 *redeemscript_p2wpkh;
|
||||
char *out_p2wpkh = encode_pubkey_to_addr(cmd,
|
||||
&pubkey,
|
||||
false,
|
||||
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);
|
||||
@ -219,6 +254,7 @@ static struct command_result *json_listaddrs(struct command *cmd,
|
||||
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);
|
||||
@ -666,7 +702,8 @@ static void match_psbt_outputs_to_wallet(struct wally_psbt *psbt,
|
||||
abort();
|
||||
}
|
||||
|
||||
psbt_set_keypath(index, &ext, &psbt->outputs[outndx].keypaths);
|
||||
psbt_output_set_keypath(index, &ext, is_p2tr(script, NULL),
|
||||
&psbt->outputs[outndx]);
|
||||
}
|
||||
tal_wally_end(psbt);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user