Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EXPERIMENTAL support for option_shutdown_anysegwit #4391

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 1 addition & 28 deletions bitcoin/script.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,8 @@
#include <common/utils.h>
#include <sodium/randombytes.h>

/* Some standard ops */
#define OP_0 0x00
/* To push 0-75 bytes onto stack. */
#define OP_PUSHBYTES(val) (val)
#define OP_PUSHDATA1 0x4C
#define OP_PUSHDATA2 0x4D
#define OP_PUSHDATA4 0x4E
#define OP_NOP 0x61
#define OP_IF 0x63
#define OP_NOTIF 0x64
#define OP_ELSE 0x67
#define OP_ENDIF 0x68
#define OP_RETURN 0x6a
#define OP_2DROP 0x6d
#define OP_IFDUP 0x73
#define OP_DEPTH 0x74
#define OP_DROP 0x75
#define OP_DUP 0x76
#define OP_SWAP 0x7c
#define OP_EQUAL 0x87
#define OP_EQUALVERIFY 0x88
#define OP_SIZE 0x82
#define OP_1SUB 0x8C
#define OP_ADD 0x93
#define OP_CHECKSIG 0xAC
#define OP_CHECKSIGVERIFY 0xAD
#define OP_CHECKMULTISIG 0xAE
#define OP_HASH160 0xA9
#define OP_CHECKSEQUENCEVERIFY 0xB2
#define OP_CHECKLOCKTIMEVERIFY 0xB1

/* Bitcoin's OP_HASH160 is RIPEMD(SHA256()) */
static void hash160(struct ripemd160 *redeemhash, const void *mem, size_t len)
Expand Down
1 change: 1 addition & 0 deletions bitcoin/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "tx.h"
#include <ccan/short_types/short_types.h>
#include <ccan/tal/tal.h>
#include <wally_script.h>

struct bitcoin_address;
struct preimage;
Expand Down
1 change: 1 addition & 0 deletions common/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ COMMON_SRC_NOGEN := \
common/read_peer_msg.c \
common/route.c \
common/setup.c \
common/shutdown_scriptpubkey.c \
common/socket_close.c \
common/sphinx.c \
common/status.c \
Expand Down
9 changes: 8 additions & 1 deletion common/features.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ static const struct feature_style feature_styles[] = {
.copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT,
[NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT,
[CHANNEL_FEATURE] = FEATURE_DONT_REPRESENT } },
{ OPT_SHUTDOWN_ANYSEGWIT,
.copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT,
[NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT,
[CHANNEL_FEATURE] = FEATURE_DONT_REPRESENT } },
{ OPT_DUAL_FUND,
.copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT,
[NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT,
Expand Down Expand Up @@ -385,9 +389,12 @@ static const char *feature_name(const tal_t *ctx, size_t f)
"option_basic_mpp",
"option_support_large_channel",
"option_anchor_outputs",
"option_anchors_zero_fee_htlc_tx",
NULL,
"option_shutdown_anysegwit",
};

if (f / 2 >= ARRAY_SIZE(fnames))
if (f / 2 >= ARRAY_SIZE(fnames) || !fnames[f / 2])
return tal_fmt(ctx, "option_unknown_%zu/%s",
COMPULSORY_FEATURE(f), (f & 1) ? "odd" : "even");

Expand Down
6 changes: 6 additions & 0 deletions common/features.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ u8 *featurebits_or(const tal_t *ctx, const u8 *f1 TAKES, const u8 *f2 TAKES);
#define OPT_LARGE_CHANNELS 18
#define OPT_ANCHOR_OUTPUTS 20

/* BOLT-4e329271a358ee52bf43ddbd96776943c5d74508 #9:
*
* | 26/27 | `option_shutdown_anysegwit` |... IN ...
*/
#define OPT_SHUTDOWN_ANYSEGWIT 26

/* BOLT-7b04b1461739c5036add61782d58ac490842d98b #9:
* | 222/223 | `option_dual_fund` | ... IN9 ...
*/
Expand Down
63 changes: 63 additions & 0 deletions common/shutdown_scriptpubkey.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include <bitcoin/script.h>
#include <common/shutdown_scriptpubkey.h>

#include <stdio.h>

/* BOLT-4e329271a358ee52bf43ddbd96776943c5d74508 #2:
* 5. if (and only if) `option_shutdown_anysegwit` is negotiated:
* * `OP_1` through `OP_16` inclusive, followed by a single
* push of 2 to 40 bytes
* (witness program versions 1 through 16)
*/
static bool is_valid_witnessprog(const u8 *scriptpubkey)
{
size_t pushlen;

if (tal_bytelen(scriptpubkey) < 2)
return false;

switch (scriptpubkey[0]) {
case OP_1:
case OP_2:
case OP_3:
case OP_4:
case OP_5:
case OP_6:
case OP_7:
case OP_8:
case OP_9:
case OP_10:
case OP_11:
case OP_12:
case OP_13:
case OP_14:
case OP_15:
case OP_16:
break;
default:
fprintf(stderr, "op = %u (invalid)\n", scriptpubkey[0]);
return false;
}

pushlen = scriptpubkey[1];
/* Must be all of the rest of scriptpubkey */
if (2 + pushlen != tal_bytelen(scriptpubkey)) {
fprintf(stderr, "2 + %zu != %zu\n", pushlen, tal_bytelen(scriptpubkey));
return false;
}

if (!(pushlen >= 2 && pushlen <= 40))
fprintf(stderr, "pushlen == %zu\n", pushlen);

return pushlen >= 2 && pushlen <= 40;
}

bool valid_shutdown_scriptpubkey(const u8 *scriptpubkey,
bool anysegwit)
{
return is_p2pkh(scriptpubkey, NULL)
|| is_p2sh(scriptpubkey, NULL)
|| is_p2wpkh(scriptpubkey, NULL)
|| is_p2wsh(scriptpubkey, NULL)
|| (anysegwit && is_valid_witnessprog(scriptpubkey));
}
22 changes: 22 additions & 0 deletions common/shutdown_scriptpubkey.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#ifndef LIGHTNING_COMMON_SHUTDOWN_SCRIPTPUBKEY_H
#define LIGHTNING_COMMON_SHUTDOWN_SCRIPTPUBKEY_H
#include "config.h"
#include <ccan/short_types/short_types.h>

/* BOLT #2:
*
* 1. `OP_DUP` `OP_HASH160` `20` 20-bytes `OP_EQUALVERIFY` `OP_CHECKSIG`
* (pay to pubkey hash), OR
* 2. `OP_HASH160` `20` 20-bytes `OP_EQUAL` (pay to script hash), OR
* 3. `OP_0` `20` 20-bytes (version 0 pay to witness pubkey), OR
* 4. `OP_0` `32` 32-bytes (version 0 pay to witness script hash)
*
* A receiving node:
*...
* - if the `scriptpubkey` is not in one of the above forms:
* - SHOULD fail the connection.
*/
bool valid_shutdown_scriptpubkey(const u8 *scriptpubkey,
bool anysegwit);

#endif /* LIGHTNING_COMMON_SHUTDOWN_SCRIPTPUBKEY_H */
1 change: 1 addition & 0 deletions lightningd/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ LIGHTNINGD_COMMON_OBJS := \
common/pseudorand.o \
common/random_select.o \
common/setup.o \
common/shutdown_scriptpubkey.o \
common/sphinx.o \
common/status_wire.o \
common/timeout.o \
Expand Down
20 changes: 5 additions & 15 deletions lightningd/channel_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <common/memleak.h>
#include <common/per_peer_state.h>
#include <common/psbt_open.h>
#include <common/shutdown_scriptpubkey.h>
#include <common/timeout.h>
#include <common/tx_roles.h>
#include <common/utils.h>
Expand Down Expand Up @@ -219,6 +220,9 @@ static void peer_got_shutdown(struct channel *channel, const u8 *msg)
{
u8 *scriptpubkey;
struct lightningd *ld = channel->peer->ld;
bool anysegwit = feature_negotiated(ld->our_features,
channel->peer->their_features,
OPT_SHUTDOWN_ANYSEGWIT);

if (!fromwire_channeld_got_shutdown(channel, msg, &scriptpubkey)) {
channel_internal_error(channel, "bad channel_got_shutdown %s",
Expand All @@ -230,21 +234,7 @@ static void peer_got_shutdown(struct channel *channel, const u8 *msg)
tal_free(channel->shutdown_scriptpubkey[REMOTE]);
channel->shutdown_scriptpubkey[REMOTE] = scriptpubkey;

/* BOLT #2:
*
* 1. `OP_DUP` `OP_HASH160` `20` 20-bytes `OP_EQUALVERIFY` `OP_CHECKSIG`
* (pay to pubkey hash), OR
* 2. `OP_HASH160` `20` 20-bytes `OP_EQUAL` (pay to script hash), OR
* 3. `OP_0` `20` 20-bytes (version 0 pay to witness pubkey), OR
* 4. `OP_0` `32` 32-bytes (version 0 pay to witness script hash)
*
* A receiving node:
*...
* - if the `scriptpubkey` is not in one of the above forms:
* - SHOULD fail the connection.
*/
if (!is_p2pkh(scriptpubkey, NULL) && !is_p2sh(scriptpubkey, NULL)
&& !is_p2wpkh(scriptpubkey, NULL) && !is_p2wsh(scriptpubkey, NULL)) {
if (!valid_shutdown_scriptpubkey(scriptpubkey, anysegwit)) {
channel_fail_permanent(channel,
REASON_PROTOCOL,
"Bad shutdown scriptpubkey %s",
Expand Down
1 change: 1 addition & 0 deletions lightningd/lightningd.c
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,7 @@ static struct feature_set *default_features(const tal_t *ctx)
#if EXPERIMENTAL_FEATURES
OPTIONAL_FEATURE(OPT_ANCHOR_OUTPUTS),
OPTIONAL_FEATURE(OPT_ONION_MESSAGES),
OPTIONAL_FEATURE(OPT_SHUTDOWN_ANYSEGWIT),
#endif
};

Expand Down
1 change: 1 addition & 0 deletions openingd/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ OPENINGD_COMMON_OBJS := \
common/pseudorand.o \
common/read_peer_msg.o \
common/setup.o \
common/shutdown_scriptpubkey.o \
common/status.o \
common/status_wire.o \
common/subdaemon.o \
Expand Down
25 changes: 21 additions & 4 deletions openingd/openingd.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <common/peer_status_wiregen.h>
#include <common/penalty_base.h>
#include <common/read_peer_msg.h>
#include <common/shutdown_scriptpubkey.h>
#include <common/status.h>
#include <common/subdaemon.h>
#include <common/type_to_string.h>
Expand Down Expand Up @@ -321,6 +322,24 @@ static bool setup_channel_funder(struct state *state)
return true;
}

static void set_remote_upfront_shutdown(struct state *state,
u8 *shutdown_scriptpubkey STEALS)
{
bool anysegwit = feature_negotiated(state->our_features,
state->their_features,
OPT_SHUTDOWN_ANYSEGWIT);

state->upfront_shutdown_script[REMOTE]
= tal_steal(state, shutdown_scriptpubkey);

if (shutdown_scriptpubkey
&& !valid_shutdown_scriptpubkey(shutdown_scriptpubkey, anysegwit))
peer_failed_err(state->pps,
&state->channel_id,
"Unacceptable upfront_shutdown_script %s",
tal_hex(tmpctx, shutdown_scriptpubkey));
}

/* We start the 'open a channel' negotation with the supplied peer, but
* stop when we get to the part where we need the funding txid */
static u8 *funder_channel_start(struct state *state, u8 channel_flags)
Expand Down Expand Up @@ -404,8 +423,7 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags)
&state->channel_id,
"Parsing accept_channel %s", tal_hex(msg, msg));
}
state->upfront_shutdown_script[REMOTE]
= tal_steal(state, accept_tlvs->upfront_shutdown_script);
set_remote_upfront_shutdown(state, accept_tlvs->upfront_shutdown_script);

/* BOLT #2:
*
Expand Down Expand Up @@ -764,8 +782,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg)
peer_failed_err(state->pps,
&state->channel_id,
"Parsing open_channel %s", tal_hex(tmpctx, open_channel_msg));
state->upfront_shutdown_script[REMOTE]
= tal_steal(state, open_tlvs->upfront_shutdown_script);
set_remote_upfront_shutdown(state, open_tlvs->upfront_shutdown_script);

/* BOLT #2:
*
Expand Down
Loading