diff --git a/Makefile b/Makefile index e56f81a4c636..311541fdfa4c 100644 --- a/Makefile +++ b/Makefile @@ -405,7 +405,7 @@ else endif endif -pytest: $(ALL_PROGRAMS) +pytest: $(ALL_PROGRAMS) $(ALL_TEST_PROGRAMS) ifeq ($(PYTEST),) @echo "py.test is required to run the integration tests, please install using 'pip3 install -r requirements.txt', and rerun 'configure'." exit 1 diff --git a/common/bech32.c b/common/bech32.c index cc62abdc0b77..de8b053024d1 100644 --- a/common/bech32.c +++ b/common/bech32.c @@ -1,7 +1,7 @@ /* Stolen from https://github.com/sipa/bech32/blob/master/ref/c/segwit_addr.c, * with only the two ' > 90' checks hoisted, and more internals exposed */ -/* Copyright (c) 2017 Pieter Wuille +/* Copyright (c) 2017, 2021 Pieter Wuille * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,6 +23,7 @@ */ #include "bech32.h" +#include #include static uint32_t bech32_polymod_step(uint32_t pre) { @@ -35,7 +36,13 @@ static uint32_t bech32_polymod_step(uint32_t pre) { (-((b >> 4) & 1) & 0x2a1462b3UL); } -const char bech32_charset[32] = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; +static uint32_t bech32_final_constant(bech32_encoding enc) { + if (enc == BECH32_ENCODING_BECH32) return 1; + if (enc == BECH32_ENCODING_BECH32M) return 0x2bc830a3; + assert(0); +} + +const char bech32_charset[] = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; const int8_t bech32_charset_rev[128] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -48,7 +55,7 @@ const int8_t bech32_charset_rev[128] = { 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1 }; -int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len, size_t max_input_len) { +int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len, size_t max_input_len, bech32_encoding enc) { uint32_t chk = 1; size_t i = 0; while (hrp[i] != 0) { @@ -76,7 +83,7 @@ int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t dat for (i = 0; i < 6; ++i) { chk = bech32_polymod_step(chk); } - chk ^= 1; + chk ^= bech32_final_constant(enc); for (i = 0; i < 6; ++i) { *(output++) = bech32_charset[(chk >> ((5 - i) * 5)) & 0x1f]; } @@ -84,15 +91,14 @@ int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t dat return 1; } -int bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input, - size_t max_input_len) { +bech32_encoding bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input, size_t max_input_len) { uint32_t chk = 1; size_t i; size_t input_len = strlen(input); size_t hrp_len; int have_lower = 0, have_upper = 0; if (input_len < 8 || input_len > max_input_len) { - return 0; + return BECH32_ENCODING_NONE; } *data_len = 0; while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') { @@ -100,13 +106,13 @@ int bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input, } hrp_len = input_len - (1 + *data_len); if (1 + *data_len >= input_len || *data_len < 6) { - return 0; + return BECH32_ENCODING_NONE; } *(data_len) -= 6; for (i = 0; i < hrp_len; ++i) { int ch = input[i]; if (ch < 33 || ch > 126) { - return 0; + return BECH32_ENCODING_NONE; } if (ch >= 'a' && ch <= 'z') { have_lower = 1; @@ -128,7 +134,7 @@ int bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input, if (input[i] >= 'a' && input[i] <= 'z') have_lower = 1; if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1; if (v == -1) { - return 0; + return BECH32_ENCODING_NONE; } chk = bech32_polymod_step(chk) ^ v; if (i + 6 < input_len) { @@ -137,9 +143,15 @@ int bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input, ++i; } if (have_lower && have_upper) { - return 0; + return BECH32_ENCODING_NONE; + } + if (chk == bech32_final_constant(BECH32_ENCODING_BECH32)) { + return BECH32_ENCODING_BECH32; + } else if (chk == bech32_final_constant(BECH32_ENCODING_BECH32M)) { + return BECH32_ENCODING_BECH32M; + } else { + return BECH32_ENCODING_NONE; } - return chk == 1; } int bech32_convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) { @@ -167,23 +179,28 @@ int bech32_convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t int segwit_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) { uint8_t data[65]; size_t datalen = 0; + bech32_encoding enc = BECH32_ENCODING_BECH32; if (witver > 16) return 0; if (witver == 0 && witprog_len != 20 && witprog_len != 32) return 0; if (witprog_len < 2 || witprog_len > 40) return 0; + if (witver > 0) enc = BECH32_ENCODING_BECH32M; data[0] = witver; bech32_convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1); ++datalen; - return bech32_encode(output, hrp, data, datalen, 90); + return bech32_encode(output, hrp, data, datalen, 90, enc); } int segwit_addr_decode(int* witver, uint8_t* witdata, size_t* witdata_len, const char* hrp, const char* addr) { uint8_t data[84]; char hrp_actual[84]; size_t data_len; - if (!bech32_decode(hrp_actual, data, &data_len, addr, 90)) return 0; + bech32_encoding enc = bech32_decode(hrp_actual, data, &data_len, addr, 90); + if (enc == BECH32_ENCODING_NONE) return 0; if (data_len == 0 || data_len > 65) return 0; if (strncmp(hrp, hrp_actual, 84) != 0) return 0; if (data[0] > 16) return 0; + if (data[0] == 0 && enc != BECH32_ENCODING_BECH32) return 0; + if (data[0] > 0 && enc != BECH32_ENCODING_BECH32M) return 0; *witdata_len = 0; if (!bech32_convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) return 0; if (*witdata_len < 2 || *witdata_len > 40) return 0; diff --git a/common/bech32.h b/common/bech32.h index 16fb69dcdb2c..614ad321e3df 100644 --- a/common/bech32.h +++ b/common/bech32.h @@ -1,7 +1,7 @@ /* Stolen from https://github.com/sipa/bech32/blob/master/ref/c/segwit_addr.h, * with only the two ' > 90' checks hoisted */ -/* Copyright (c) 2017 Pieter Wuille +/* Copyright (c) 2017, 2021 Pieter Wuille * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -69,7 +69,14 @@ int segwit_addr_decode( const char* addr ); -/** Encode a Bech32 string +/** Supported encodings. */ +typedef enum { + BECH32_ENCODING_NONE, + BECH32_ENCODING_BECH32, + BECH32_ENCODING_BECH32M +} bech32_encoding; + +/** Encode a Bech32 or Bech32m string * * Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that * will be updated to contain the null-terminated Bech32 string. @@ -77,6 +84,7 @@ int segwit_addr_decode( * data : Pointer to an array of 5-bit values. * data_len: Length of the data array. * max_input_len: Maximum valid length of input (90 for segwit usage). + * enc: Which encoding to use (BECH32_ENCODING_BECH32{,M}). * Returns 1 if successful. */ int bech32_encode( @@ -84,10 +92,11 @@ int bech32_encode( const char *hrp, const uint8_t *data, size_t data_len, - size_t max_input_len + size_t max_input_len, + bech32_encoding enc ); -/** Decode a Bech32 string +/** Decode a Bech32 or Bech32m string * * Out: hrp: Pointer to a buffer of size strlen(input) - 6. Will be * updated to contain the null-terminated human readable part. @@ -97,9 +106,11 @@ int bech32_encode( * of entries in data. * In: input: Pointer to a null-terminated Bech32 string. * max_input_len: Maximum valid length of input (90 for segwit usage). - * Returns 1 if successful. + * Returns BECH32_ENCODING_BECH32{,M} to indicate decoding was successful + * with the specified encoding standard. BECH32_ENCODING_NONE is returned if + * decoding failed. */ -int bech32_decode( +bech32_encoding bech32_decode( char *hrp, uint8_t *data, size_t *data_len, @@ -120,3 +131,4 @@ extern const char bech32_charset[32]; extern const int8_t bech32_charset_rev[128]; #endif /* LIGHTNING_COMMON_BECH32_H */ + diff --git a/common/bolt11.c b/common/bolt11.c index 36a1feacd049..65769f24ff13 100644 --- a/common/bolt11.c +++ b/common/bolt11.c @@ -584,7 +584,8 @@ struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str, hrp = tal_arr(tmpctx, char, strlen(str) - 6); data = tal_arr(tmpctx, u5, strlen(str) - 8); - if (!bech32_decode(hrp, data, &data_len, str, (size_t)-1)) + if (bech32_decode(hrp, data, &data_len, str, (size_t)-1) + != BECH32_ENCODING_BECH32) return decode_fail(b11, fail, "Bad bech32 string"); /* For signature checking at the end. */ @@ -1179,7 +1180,8 @@ char *bolt11_encode_(const tal_t *ctx, bech32_push_bits(&data, sig_and_recid, sizeof(sig_and_recid) * CHAR_BIT); output = tal_arr(ctx, char, strlen(hrp) + tal_count(data) + 8); - if (!bech32_encode(output, hrp, data, tal_count(data), (size_t)-1)) + if (!bech32_encode(output, hrp, data, tal_count(data), (size_t)-1, + BECH32_ENCODING_BECH32)) output = tal_free(output); return output; diff --git a/common/json_tok.c b/common/json_tok.c index e30dfc35bfb4..d6e292cc3b0d 100644 --- a/common/json_tok.c +++ b/common/json_tok.c @@ -433,14 +433,15 @@ json_to_address_scriptpubkey(const tal_t *ctx, bip173 = segwit_addr_net_decode(&witness_version, witness_program, &witness_program_len, addrz, chainparams); - if (bip173) { - bool witness_ok = false; - if (witness_version == 0 && (witness_program_len == 20 || - witness_program_len == 32)) { + bool witness_ok; + + /* We know the rules for v0, rest remain undefined */ + if (witness_version == 0) { + witness_ok = (witness_program_len == 20 || + witness_program_len == 32); + } else witness_ok = true; - } - /* Insert other witness versions here. */ if (witness_ok) { *scriptpubkey = scriptpubkey_witness_raw(ctx, witness_version, diff --git a/connectd/connectd.c b/connectd/connectd.c index 3aba28ddd88a..f9ccdafabecd 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -1412,7 +1412,8 @@ static const char **seednames(const tal_t *ctx, const struct node_id *id) const char **seednames = tal_arr(ctx, const char *, 0); bech32_push_bits(&data, id->k, ARRAY_SIZE(id->k)*8); - bech32_encode(bech32, "ln", data, tal_count(data), sizeof(bech32)); + bech32_encode(bech32, "ln", data, tal_count(data), sizeof(bech32), + BECH32_ENCODING_BECH32); /* This is cdecker's seed */ tal_arr_expand(&seednames, tal_fmt(seednames, "%s.lseed.bitcoinstats.com", bech32)); /* This is darosior's seed */ diff --git a/devtools/Makefile b/devtools/Makefile index 247f853a3301..a9c532fe5ce0 100644 --- a/devtools/Makefile +++ b/devtools/Makefile @@ -1,4 +1,4 @@ -DEVTOOLS := devtools/bolt11-cli devtools/decodemsg devtools/onion devtools/dump-gossipstore devtools/gossipwith devtools/create-gossipstore devtools/mkcommit devtools/mkfunding devtools/mkclose devtools/mkgossip devtools/mkencoded devtools/mkquery devtools/lightning-checkmessage devtools/topology devtools/route devtools/blindedpath devtools/bolt12-cli +DEVTOOLS := devtools/bolt11-cli devtools/decodemsg devtools/onion devtools/dump-gossipstore devtools/gossipwith devtools/create-gossipstore devtools/mkcommit devtools/mkfunding devtools/mkclose devtools/mkgossip devtools/mkencoded devtools/mkquery devtools/lightning-checkmessage devtools/topology devtools/route devtools/blindedpath devtools/bolt12-cli devtools/encodeaddr ifeq ($(HAVE_SQLITE3),1) DEVTOOLS += devtools/checkchannels endif @@ -46,6 +46,8 @@ DEVTOOLS_COMMON_OBJS := \ devtools/bolt11-cli: $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o devtools/bolt11-cli.o +devtools/encodeaddr: common/utils.o common/bech32.o devtools/encodeaddr.o + devtools/bolt12-cli: $(DEVTOOLS_COMMON_OBJS) $(CCAN_OBJS) $(BITCOIN_OBJS) wire/bolt12$(EXP)_wiregen.o wire/fromwire.o wire/towire.o common/bolt12.o common/bolt12_merkle.o devtools/bolt12-cli.o common/setup.o common/iso4217.o devtools/decodemsg: $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) $(BITCOIN_OBJS) $(WIRE_PRINT_OBJS) wire/fromwire.o wire/towire.o devtools/print_wire.o devtools/decodemsg.o diff --git a/devtools/encodeaddr.c b/devtools/encodeaddr.c new file mode 100644 index 000000000000..4cf8a82528e0 --- /dev/null +++ b/devtools/encodeaddr.c @@ -0,0 +1,42 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include + +static void test_enc(const char *hrp, const char *hex) +{ + u8 *val; + bool ok; + u8 ver; + char *out; + + val = tal_hexdata(NULL, hex, strlen(hex)); + assert(val); + out = tal_arr(NULL, char, 73 + strlen(hrp)); + /* First byte is version */ + ver = (val[0] == 0 ? 0 : val[0] - 0x50); + /* Second byte is OP_PUSH */ + assert(val[1] == tal_bytelen(val) - 2); + ok = segwit_addr_encode(out, hrp, ver, val+2, tal_bytelen(val)-2); + assert(ok); + printf("%s\n", out); +} + +int main(int argc, char *argv[]) +{ + const char *hrp = argv[1]; + + setup_locale(); + test_enc(hrp ?: "bc", "0014751e76e8199196d454941c45d1b3a323f1433bd6"); + test_enc(hrp ?: "tb", "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262"); + test_enc(hrp ?: "bc", "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6"); + test_enc(hrp ?: "bc", "6002751e"); + test_enc(hrp ?: "bc", "5210751e76e8199196d454941c45d1b3a323"); + test_enc(hrp ?: "tb", "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433"); + test_enc(hrp ?: "tb", "5120000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433"); + test_enc(hrp ?: "bc", "512079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"); +} diff --git a/doc/lightning-close.7 b/doc/lightning-close.7 index c6313e41716a..5255b73a81a9 100644 --- a/doc/lightning-close.7 +++ b/doc/lightning-close.7 @@ -27,7 +27,10 @@ The default is 2 days (172800 seconds)\. The \fIdestination\fR can be of any Bitcoin accepted type, including bech32\. -If it isn't specified, the default is a c-lightning wallet address\. +If it isn't specified, the default is a c-lightning wallet address\. If +the peer hasn't offered the \fBoption_shutdown_anysegwit\fR feature, then +taproot addresses (or other v1+ segwit) are not allowed\. Tell your +friends to upgrade! The \fIfee_negotiation_step\fR parameter controls how closing fee @@ -120,4 +123,4 @@ ZmnSCPxj \fI is mainly responsible\. Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:507a9ca707e244eef65c5e16daa5a4d7ba8f59e93e988d252f7e854ae9f44781 +\" SHA256STAMP:17f5bb362d8501b04314756c4134e3d5d20f8729dd55f5f3cfa0b5e111b104a1 diff --git a/doc/lightning-close.7.md b/doc/lightning-close.7.md index 306598ca7a85..067ec8df1ddf 100644 --- a/doc/lightning-close.7.md +++ b/doc/lightning-close.7.md @@ -26,7 +26,10 @@ indefinitely until the peer is online and can negotiate a mutual close. The default is 2 days (172800 seconds). The *destination* can be of any Bitcoin accepted type, including bech32. -If it isn't specified, the default is a c-lightning wallet address. +If it isn't specified, the default is a c-lightning wallet address. If +the peer hasn't offered the `option_shutdown_anysegwit` feature, then +taproot addresses (or other v1+ segwit) are not allowed. Tell your +friends to upgrade! The *fee_negotiation_step* parameter controls how closing fee negotiation is performed assuming the peer proposes a fee that is diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index e8c87401af1d..a322fe57ef3e 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -244,7 +244,7 @@ static void peer_got_shutdown(struct channel *channel, const u8 *msg) channel_fail_permanent(channel, REASON_PROTOCOL, "Bad shutdown scriptpubkey %s", - tal_hex(channel, scriptpubkey)); + tal_hex(tmpctx, scriptpubkey)); return; } diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 9d74abd01d8d..47957c1ab7aa 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1655,6 +1656,7 @@ static struct command_result *json_close(struct command *cmd, const char *fee_negotiation_step_str; struct bitcoin_outpoint *wrong_funding; char* end; + bool anysegwit; if (!param(cmd, buffer, params, p_req("id", param_tok, &idtok), @@ -1731,6 +1733,24 @@ 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)) { + /* Explicit check for future segwits. */ + if (!anysegwit && + valid_shutdown_scriptpubkey(channel->shutdown_scriptpubkey + [LOCAL], true)) { + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "Peer does not allow v1+ shutdown addresses"); + } + + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "Invalid close destination"); + } + if (fee_negotiation_step_str == NULL) { channel->closing_fee_negotiation_step = 50; channel->closing_fee_negotiation_step_unit = diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 8709fb588644..8a4fd854e092 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -670,6 +670,10 @@ u8 *towire_warningfmt(const tal_t *ctx UNNEEDED, const struct channel_id *channel UNNEEDED, const char *fmt UNNEEDED, ...) { fprintf(stderr, "towire_warningfmt called!\n"); abort(); } +/* Generated stub for valid_shutdown_scriptpubkey */ +bool valid_shutdown_scriptpubkey(const u8 *scriptpubkey UNNEEDED, + bool anysegwit UNNEEDED) +{ fprintf(stderr, "valid_shutdown_scriptpubkey called!\n"); abort(); } /* Generated stub for version */ const char *version(void) { fprintf(stderr, "version called!\n"); abort(); } diff --git a/tests/fuzz/fuzz-bech32.c b/tests/fuzz/fuzz-bech32.c index e9a8b6c0fab5..b3ab46f44c20 100644 --- a/tests/fuzz/fuzz-bech32.c +++ b/tests/fuzz/fuzz-bech32.c @@ -15,15 +15,17 @@ void run(const uint8_t *data, size_t size) uint8_t *data_out; size_t data_out_len; int wit_version; + bech32_encoding benc; /* Buffer size is defined in each function's doc comment. */ bech32_str = malloc(size + strlen(hrp_inv) + 8); + benc = data[0] ? BECH32_ENCODING_BECH32 : BECH32_ENCODING_BECH32M; /* FIXME: needs a dictionary / a startup seed corpus to pass this more * frequently. */ - if (bech32_encode(bech32_str, hrp_inv, data, size, size) == 1) { + if (bech32_encode(bech32_str, hrp_inv, data+1, size-1, size-1, benc) == 1) { hrp_out = malloc(strlen(bech32_str) - 6); data_out = malloc(strlen(bech32_str) - 8); - bech32_decode(hrp_out, data_out, &data_out_len, bech32_str, size); + assert(bech32_decode(hrp_out, data_out, &data_out_len, bech32_str, size) == benc); free(hrp_out); free(data_out); } diff --git a/tests/test_closing.py b/tests/test_closing.py index cd95224c2036..55d05d447dac 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -2740,3 +2740,59 @@ def test_shutdown_alternate_txid(node_factory, bitcoind): wait_for(lambda: l2.rpc.listpeers()['peers'] == []) wait_for(lambda: l1.rpc.listpeers()['peers'] == []) + + +@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', "Uses regtest addresses") +@pytest.mark.developer("too slow without fast polling for blocks") +def test_segwit_anyshutdown(node_factory, bitcoind, executor): + """Try a range of future segwit versions for shutdown""" + l1, l2 = node_factory.line_graph(2, fundchannel=False) + + l1.fundwallet(10**7) + + # Based on BIP-320, but all changed to regtest. + addrs = ("BCRT1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KYGT080", + "bcrt1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qzf4jry", + "bcrt1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k0ylj56", + "BCRT1SW50QT2UWHA", + "bcrt1zw508d6qejxtdg4y5r3zarvaryv2wuatf", + "bcrt1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvseswlauz7", + "bcrt1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesyga46z", + "bcrt1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqc8gma6") + + for addr in addrs: + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + l1.rpc.fundchannel(l2.info['id'], 10**6) + # If we don't actually make a payment, two of the above cases fail + # because the resulting tx is too small! Balance channel so close + # has two outputs. + bitcoind.generate_block(1, wait_for_mempool=1) + wait_for(lambda: any([c['state'] == 'CHANNELD_NORMAL' for c in only_one(l1.rpc.listpeers()['peers'])['channels']])) + l1.pay(l2, 10**9 // 2) + l1.rpc.close(l2.info['id'], destination=addr) + bitcoind.generate_block(1, wait_for_mempool=1) + wait_for(lambda: all([c['state'] == 'ONCHAIN' for c in only_one(l1.rpc.listpeers()['peers'])['channels']])) + + +@pytest.mark.developer("needs to manipulate features") +@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', "Uses regtest addresses") +def test_anysegwit_close_needs_feature(node_factory, bitcoind): + """Rather than have peer reject our shutdown, we should refuse to shutdown toa v1+ address if they don't support it""" + # L2 says "no option_shutdown_anysegwit" + l1, l2 = node_factory.line_graph(2, opts=[{'may_reconnect': True}, + {'may_reconnect': True, + 'dev-force-features': -27}]) + + with pytest.raises(RpcError, match=r'Peer does not allow v1\+ shutdown addresses'): + l1.rpc.close(l2.info['id'], destination='bcrt1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k0ylj56') + + # From TFM: "Tell your friends to upgrade!" + l2.stop() + del l2.daemon.opts['dev-force-features'] + l2.start() + + # Now it will work! + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + l1.rpc.close(l2.info['id'], destination='bcrt1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k0ylj56') + wait_for(lambda: only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['state'] == 'CLOSINGD_COMPLETE') + bitcoind.generate_block(1, wait_for_mempool=1) diff --git a/tests/test_wallet.py b/tests/test_wallet.py index 5e1b03bcd98e..d7c809da8d8b 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -1341,3 +1341,31 @@ def test_repro_4258(node_factory, bitcoind): assert(len(tx['vin']) == 1) i0 = tx['vin'][0] assert([i0['txid'], i0['vout']] == [out['txid'], out['output']]) + + +@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', "Uses regtest addresses") +def test_withdraw_bech32m(node_factory, bitcoind): + l1 = node_factory.get_node() + l1.fundwallet(10000000) + + # Based on BIP-320, but all changed to regtest. + addrs = ("BCRT1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KYGT080", + "bcrt1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qzf4jry", + "bcrt1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k0ylj56", + "BCRT1SW50QT2UWHA", + "bcrt1zw508d6qejxtdg4y5r3zarvaryv2wuatf", + "bcrt1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvseswlauz7", + "bcrt1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesyga46z", + "bcrt1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqc8gma6") + + for addr in addrs: + l1.rpc.withdraw(addr, 10**3) + bitcoind.generate_block(1, wait_for_mempool=1) + print(l1.rpc.listfunds()['outputs']) + wait_for(lambda: [o for o in l1.rpc.listfunds()['outputs'] if o['status'] == 'confirmed' and not o['reserved']] != []) + + # Test multiwithdraw + args = [] + for addr in addrs: + args += [{addr: 10**3}] + l1.rpc.multiwithdraw(args)["txid"] diff --git a/tools/hsmtool.c b/tools/hsmtool.c index 3bc076366c62..a202fdfb9c0c 100644 --- a/tools/hsmtool.c +++ b/tools/hsmtool.c @@ -363,7 +363,7 @@ static int guess_to_remote(const char *address, struct node_id *node_id, size_t witlen; /* Get the hrp to accept addresses from any network. */ - if (bech32_decode(hrp, goal_pubkeyhash, &witlen, address, 90) != 1) + if (bech32_decode(hrp, goal_pubkeyhash, &witlen, address, 90) != BECH32_ENCODING_BECH32) errx(ERROR_USAGE, "Could not get address' network"); if (segwit_addr_decode(&witver, goal_pubkeyhash, &witlen, hrp, address) != 1) errx(ERROR_USAGE, "Wrong bech32 address"); diff --git a/wallet/db_postgres_sqlgen.c b/wallet/db_postgres_sqlgen.c index 8a3b70c5776d..e85d5929d387 100644 --- a/wallet/db_postgres_sqlgen.c +++ b/wallet/db_postgres_sqlgen.c @@ -1924,4 +1924,4 @@ struct db_query db_postgres_queries[] = { #endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */ -// SHA256STAMP:1379bcdee314439910fc6b238f7ec986536543c53933883ffd1b750dfc34f9b9 +// SHA256STAMP:dbbcb7d784e7b3d6c7b27c2ff976dcc39335fdc26fbf095b65116488007799f7 diff --git a/wallet/db_sqlite3_sqlgen.c b/wallet/db_sqlite3_sqlgen.c index 98ed0bf0c4b6..5b6eb8fa06d6 100644 --- a/wallet/db_sqlite3_sqlgen.c +++ b/wallet/db_sqlite3_sqlgen.c @@ -1924,4 +1924,4 @@ struct db_query db_sqlite3_queries[] = { #endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */ -// SHA256STAMP:1379bcdee314439910fc6b238f7ec986536543c53933883ffd1b750dfc34f9b9 +// SHA256STAMP:dbbcb7d784e7b3d6c7b27c2ff976dcc39335fdc26fbf095b65116488007799f7 diff --git a/wallet/statements_gettextgen.po b/wallet/statements_gettextgen.po index 27896c8b6d17..030daf2061c8 100644 --- a/wallet/statements_gettextgen.po +++ b/wallet/statements_gettextgen.po @@ -1262,11 +1262,11 @@ msgstr "" msgid "not a valid SQL statement" msgstr "" -#: wallet/test/run-wallet.c:1451 +#: wallet/test/run-wallet.c:1455 msgid "SELECT COUNT(1) FROM channel_funding_inflights WHERE channel_id = ?;" msgstr "" -#: wallet/test/run-wallet.c:1649 +#: wallet/test/run-wallet.c:1653 msgid "INSERT INTO channels (id) VALUES (1);" msgstr "" -# SHA256STAMP:51de0bd1efd4b12ec550d3faf934a32f745018a46e61b50cc242c2d5bae09470 +# SHA256STAMP:e3c8d5cac8615668f0c9f37ebf6edff3b18833bafdf9643c2203b2a4ab654b7c diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index ede16ddd6795..c95aca7cb359 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -841,6 +841,10 @@ u8 *towire_warningfmt(const tal_t *ctx UNNEEDED, const struct channel_id *channel UNNEEDED, const char *fmt UNNEEDED, ...) { fprintf(stderr, "towire_warningfmt called!\n"); abort(); } +/* Generated stub for valid_shutdown_scriptpubkey */ +bool valid_shutdown_scriptpubkey(const u8 *scriptpubkey UNNEEDED, + bool anysegwit UNNEEDED) +{ fprintf(stderr, "valid_shutdown_scriptpubkey called!\n"); abort(); } /* Generated stub for watch_txid */ struct txwatch *watch_txid(const tal_t *ctx UNNEEDED, struct chain_topology *topo UNNEEDED,