diff --git a/channeld/channeld.c b/channeld/channeld.c index 6c9fbd83f..28f957c89 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -748,7 +748,9 @@ static void maybe_send_shutdown(struct peer *peer) * over us */ send_channel_update(peer, ROUTING_FLAGS_DISABLED); - msg = towire_shutdown(NULL, &peer->channel_id, peer->final_scriptpubkey); + /* FIXME: send wrong_funding */ + msg = towire_shutdown(NULL, &peer->channel_id, peer->final_scriptpubkey, + NULL); sync_crypto_write(peer->pps, take(msg)); peer->send_shutdown = false; peer->shutdown_sent[LOCAL] = true; @@ -1633,11 +1635,13 @@ static void handle_peer_shutdown(struct peer *peer, const u8 *shutdown) { struct channel_id channel_id; u8 *scriptpubkey; + struct tlv_shutdown_tlvs *tlvs = tlv_shutdown_tlvs_new(tmpctx); /* Disable the channel. */ send_channel_update(peer, ROUTING_FLAGS_DISABLED); - if (!fromwire_shutdown(tmpctx, shutdown, &channel_id, &scriptpubkey)) + if (!fromwire_shutdown(tmpctx, shutdown, &channel_id, &scriptpubkey, + tlvs)) peer_failed_warn(peer->pps, &peer->channel_id, "Bad shutdown %s", tal_hex(peer, shutdown)); @@ -1659,6 +1663,16 @@ static void handle_peer_shutdown(struct peer *peer, const u8 *shutdown) tal_hex(peer, scriptpubkey), tal_hex(peer, peer->remote_upfront_shutdown_script)); + if (tlvs->wrong_funding) { + if (!feature_negotiated(peer->our_features, + peer->their_features, + OPT_SHUTDOWN_WRONG_FUNDING)) + peer_failed_warn(peer->pps, &peer->channel_id, + "wrong_funding shutdown needs" + " feature %u", + OPT_SHUTDOWN_WRONG_FUNDING); + } + /* Tell master: we don't have to wait because on reconnect other end * will re-send anyway. */ wire_sync_write(MASTER_FD, diff --git a/closingd/closingd.c b/closingd/closingd.c index b0d367990..4693ba936 100644 --- a/closingd/closingd.c +++ b/closingd/closingd.c @@ -218,7 +218,8 @@ static void do_reconnect(struct per_peer_state *pps, * - if it has sent a previous `shutdown`: * - MUST retransmit `shutdown`. */ - msg = towire_shutdown(NULL, channel_id, final_scriptpubkey); + /* FIXME: retransmit wrong_funding */ + msg = towire_shutdown(NULL, channel_id, final_scriptpubkey, NULL); sync_crypto_write(pps, take(msg)); /* BOLT #2: diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 54b1c75da..0b990cb4b 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -376,8 +376,9 @@ static void send_shutdown(struct state *state, const u8 *final_scriptpubkey) { u8 *msg; + /* FIXME: send wrong_funding */ msg = towire_shutdown(NULL, &state->channel_id, - final_scriptpubkey); + final_scriptpubkey, NULL); sync_crypto_write(state->pps, take(msg)); state->shutdown_sent[LOCAL] = true; } @@ -386,8 +387,9 @@ static void handle_peer_shutdown(struct state *state, u8 *msg) { u8 *scriptpubkey; struct channel_id cid; + struct tlv_shutdown_tlvs *tlvs = tlv_shutdown_tlvs_new(msg); - if (!fromwire_shutdown(tmpctx, msg, &cid, &scriptpubkey)) + if (!fromwire_shutdown(tmpctx, msg, &cid, &scriptpubkey, tlvs)) open_err_warn(state, "Bad shutdown %s", tal_hex(msg, msg)); if (tal_count(state->upfront_shutdown_script[REMOTE]) @@ -400,6 +402,13 @@ static void handle_peer_shutdown(struct state *state, u8 *msg) tal_hex(state, state->upfront_shutdown_script[REMOTE])); + /* @niftynei points out that negotiated this together, so this + * hack is not required (or safe!). */ + if (tlvs->wrong_funding) + open_err_warn(state, + "wrong_funding shutdown" + " invalid for dual-funding"); + wire_sync_write(REQ_FD, take(towire_dualopend_got_shutdown(NULL, scriptpubkey))); diff --git a/wire/extracted_peer-shutdown-wrong_funding.patch b/wire/extracted_peer-shutdown-wrong_funding.patch new file mode 100644 index 000000000..114380237 --- /dev/null +++ b/wire/extracted_peer-shutdown-wrong_funding.patch @@ -0,0 +1,13 @@ +--- wire/peer_wire.csv ++++ wire/peer_wire.csv +@@ -90,6 +90,10 @@ msgtype,shutdown,38 + msgdata,shutdown,channel_id,channel_id, + msgdata,shutdown,len,u16, + msgdata,shutdown,scriptpubkey,byte,len ++msgdata,shutdown,tlvs,shutdown_tlvs, ++tlvtype,shutdown_tlvs,wrong_funding,100 ++tlvdata,shutdown_tlvs,wrong_funding,txid,sha256, ++tlvdata,shutdown_tlvs,wrong_funding,outnum,u32, + msgtype,closing_signed,39 + msgdata,closing_signed,channel_id,channel_id, + msgdata,closing_signed,fee_satoshis,u64, diff --git a/wire/peer_printgen.c b/wire/peer_printgen.c index 166fd4793..69d0345d2 100644 --- a/wire/peer_printgen.c +++ b/wire/peer_printgen.c @@ -362,6 +362,34 @@ static const struct tlv_print_record_type print_tlvs_accept_channel_tlvs[] = { { 0, printwire_tlv_accept_channel_tlvs_upfront_shutdown_script }, }; +static void printwire_tlv_shutdown_tlvs_wrong_funding(const char *fieldname, const u8 **cursor, size_t *plen) +{ + printf("(msg_name=%s)\n", "wrong_funding"); + + printf("txid="); + struct bitcoin_txid txid; + fromwire_bitcoin_txid(cursor, plen, &txid); + + printwire_bitcoin_txid(tal_fmt(NULL, "%s.txid", fieldname), &txid); + if (!*cursor) { + printf("**TRUNCATED**\n"); + return; + } + printf("outnum="); + u32 outnum = fromwire_u32(cursor, plen); + + printwire_u32(tal_fmt(NULL, "%s.outnum", fieldname), &outnum); + if (!*cursor) { + printf("**TRUNCATED**\n"); + return; + } + +} + +static const struct tlv_print_record_type print_tlvs_shutdown_tlvs[] = { + { 100, printwire_tlv_shutdown_tlvs_wrong_funding }, +}; + static void printwire_tlv_query_short_channel_ids_tlvs_query_flags(const char *fieldname, const u8 **cursor, size_t *plen) { printf("(msg_name=%s)\n", "query_flags"); @@ -1088,6 +1116,8 @@ void printwire_shutdown(const char *fieldname, const u8 *cursor) printf("**TRUNCATED**\n"); return; } + printf("tlvs="); + printwire_tlvs(tal_fmt(NULL, "%s.tlvs", fieldname), &cursor, &plen, print_tlvs_shutdown_tlvs, ARRAY_SIZE(print_tlvs_shutdown_tlvs)); if (plen != 0) @@ -2117,6 +2147,9 @@ void printpeer_wire_tlv_message(const char *tlv_name, const u8 *msg) { if (strcmp(tlv_name, "accept_channel_tlvs") == 0) { printwire_tlvs(tlv_name, &msg, &plen, print_tlvs_accept_channel_tlvs, ARRAY_SIZE(print_tlvs_accept_channel_tlvs)); } + if (strcmp(tlv_name, "shutdown_tlvs") == 0) { + printwire_tlvs(tlv_name, &msg, &plen, print_tlvs_shutdown_tlvs, ARRAY_SIZE(print_tlvs_shutdown_tlvs)); + } if (strcmp(tlv_name, "query_short_channel_ids_tlvs") == 0) { printwire_tlvs(tlv_name, &msg, &plen, print_tlvs_query_short_channel_ids_tlvs, ARRAY_SIZE(print_tlvs_query_short_channel_ids_tlvs)); } @@ -2130,4 +2163,4 @@ void printpeer_wire_tlv_message(const char *tlv_name, const u8 *msg) { printwire_tlvs(tlv_name, &msg, &plen, print_tlvs_onion_message_tlvs, ARRAY_SIZE(print_tlvs_onion_message_tlvs)); } } -// SHA256STAMP:1b0c5319cd9ab8c0281132a4c64ca51ecd9ee0158c7f645e102f401ac64ca439 +// SHA256STAMP:c7056cc0ec6b038e425e0800dce339f6ba38a18f14d1b33271656de218052ee2 diff --git a/wire/peer_printgen.h b/wire/peer_printgen.h index cc597757a..bdc545e63 100644 --- a/wire/peer_printgen.h +++ b/wire/peer_printgen.h @@ -74,4 +74,4 @@ void printwire_onion_message(const char *fieldname, const u8 *cursor); void printwire_channel_update_checksums(const char *fieldname, const u8 **cursor, size_t *plen); void printwire_channel_update_timestamps(const char *fieldname, const u8 **cursor, size_t *plen); #endif /* LIGHTNING_WIRE_PEER_PRINTGEN_H */ -// SHA256STAMP:1b0c5319cd9ab8c0281132a4c64ca51ecd9ee0158c7f645e102f401ac64ca439 +// SHA256STAMP:c7056cc0ec6b038e425e0800dce339f6ba38a18f14d1b33271656de218052ee2 diff --git a/wire/peer_wire.csv b/wire/peer_wire.csv index fba232650..daf2ff5c1 100644 --- a/wire/peer_wire.csv +++ b/wire/peer_wire.csv @@ -90,6 +90,10 @@ msgtype,shutdown,38 msgdata,shutdown,channel_id,channel_id, msgdata,shutdown,len,u16, msgdata,shutdown,scriptpubkey,byte,len +msgdata,shutdown,tlvs,shutdown_tlvs, +tlvtype,shutdown_tlvs,wrong_funding,100 +tlvdata,shutdown_tlvs,wrong_funding,txid,sha256, +tlvdata,shutdown_tlvs,wrong_funding,outnum,u32, msgtype,closing_signed,39 msgdata,closing_signed,channel_id,channel_id, msgdata,closing_signed,fee_satoshis,u64, diff --git a/wire/peer_wiregen.c b/wire/peer_wiregen.c index 8a6700b7c..036013e2e 100644 --- a/wire/peer_wiregen.c +++ b/wire/peer_wiregen.c @@ -504,6 +504,63 @@ bool accept_channel_tlvs_is_valid(const struct tlv_accept_channel_tlvs *record, } +struct tlv_shutdown_tlvs *tlv_shutdown_tlvs_new(const tal_t *ctx) +{ + /* Initialize everything to NULL. (Quiet, C pedants!) */ + struct tlv_shutdown_tlvs *inst = talz(ctx, struct tlv_shutdown_tlvs); + + /* Initialized the fields to an empty array. */ + inst->fields = tal_arr(inst, struct tlv_field, 0); + return inst; +} + +/* SHUTDOWN_TLVS MSG: wrong_funding */ +static u8 *towire_tlv_shutdown_tlvs_wrong_funding(const tal_t *ctx, const void *vrecord) +{ + const struct tlv_shutdown_tlvs *r = vrecord; + u8 *ptr; + + if (!r->wrong_funding) + return NULL; + + + ptr = tal_arr(ctx, u8, 0); + + towire_bitcoin_txid(&ptr, &r->wrong_funding->txid); + + towire_u32(&ptr, r->wrong_funding->outnum); + return ptr; +} +static void fromwire_tlv_shutdown_tlvs_wrong_funding(const u8 **cursor, size_t *plen, void *vrecord) +{ + struct tlv_shutdown_tlvs *r = vrecord; + + r->wrong_funding = tal(r, struct tlv_shutdown_tlvs_wrong_funding); + fromwire_bitcoin_txid(cursor, plen, &r->wrong_funding->txid); + r->wrong_funding->outnum = fromwire_u32(cursor, plen); +} + +static const struct tlv_record_type tlvs_shutdown_tlvs[] = { + { 100, towire_tlv_shutdown_tlvs_wrong_funding, fromwire_tlv_shutdown_tlvs_wrong_funding }, +}; + +void towire_shutdown_tlvs(u8 **pptr, const struct tlv_shutdown_tlvs *record) +{ + towire_tlv(pptr, tlvs_shutdown_tlvs, 1, record); +} + + +bool fromwire_shutdown_tlvs(const u8 **cursor, size_t *max, struct tlv_shutdown_tlvs *record) +{ + return fromwire_tlv(cursor, max, tlvs_shutdown_tlvs, 1, record, &record->fields); +} + +bool shutdown_tlvs_is_valid(const struct tlv_shutdown_tlvs *record, size_t *err_index) +{ + return tlv_fields_valid(record->fields, err_index); +} + + struct tlv_query_short_channel_ids_tlvs *tlv_query_short_channel_ids_tlvs_new(const tal_t *ctx) { /* Initialize everything to NULL. (Quiet, C pedants!) */ @@ -1094,7 +1151,7 @@ bool fromwire_funding_locked(const void *p, struct channel_id *channel_id, struc } /* WIRE: SHUTDOWN */ -u8 *towire_shutdown(const tal_t *ctx, const struct channel_id *channel_id, const u8 *scriptpubkey) +u8 *towire_shutdown(const tal_t *ctx, const struct channel_id *channel_id, const u8 *scriptpubkey, const struct tlv_shutdown_tlvs *tlvs) { u16 len = tal_count(scriptpubkey); u8 *p = tal_arr(ctx, u8, 0); @@ -1103,10 +1160,11 @@ u8 *towire_shutdown(const tal_t *ctx, const struct channel_id *channel_id, const towire_channel_id(&p, channel_id); towire_u16(&p, len); towire_u8_array(&p, scriptpubkey, len); + towire_shutdown_tlvs(&p, tlvs); return memcheck(p, tal_count(p)); } -bool fromwire_shutdown(const tal_t *ctx, const void *p, struct channel_id *channel_id, u8 **scriptpubkey) +bool fromwire_shutdown(const tal_t *ctx, const void *p, struct channel_id *channel_id, u8 **scriptpubkey, struct tlv_shutdown_tlvs *tlvs) { u16 len; @@ -1120,6 +1178,7 @@ bool fromwire_shutdown(const tal_t *ctx, const void *p, struct channel_id *chann // 2nd case scriptpubkey *scriptpubkey = len ? tal_arr(ctx, u8, len) : NULL; fromwire_u8_array(&cursor, &plen, *scriptpubkey, len); + fromwire_shutdown_tlvs(&cursor, &plen, tlvs); return cursor != NULL; } @@ -1749,4 +1808,4 @@ bool fromwire_channel_update_option_channel_htlc_max(const void *p, secp256k1_ec *htlc_maximum_msat = fromwire_amount_msat(&cursor, &plen); return cursor != NULL; } -// SHA256STAMP:1b0c5319cd9ab8c0281132a4c64ca51ecd9ee0158c7f645e102f401ac64ca439 +// SHA256STAMP:c7056cc0ec6b038e425e0800dce339f6ba38a18f14d1b33271656de218052ee2 diff --git a/wire/peer_wiregen.h b/wire/peer_wiregen.h index b3c9477b5..c8bddfd4a 100644 --- a/wire/peer_wiregen.h +++ b/wire/peer_wiregen.h @@ -73,6 +73,10 @@ struct tlv_n1_tlv3 { struct amount_msat amount_msat_1; struct amount_msat amount_msat_2; }; +struct tlv_shutdown_tlvs_wrong_funding { + struct bitcoin_txid txid; + u32 outnum; +}; struct tlv_query_short_channel_ids_tlvs_query_flags { u8 encoding_type; u8 *encoded_query_flags; @@ -125,6 +129,14 @@ struct tlv_accept_channel_tlvs { * tlv_field entries above to save on memory. */ u8 *upfront_shutdown_script; }; +struct tlv_shutdown_tlvs { + /* Raw fields including unknown ones. */ + struct tlv_field *fields; + + /* TODO The following explicit fields could just point into the + * tlv_field entries above to save on memory. */ + struct tlv_shutdown_tlvs_wrong_funding *wrong_funding; +}; struct tlv_query_short_channel_ids_tlvs { /* Raw fields including unknown ones. */ struct tlv_field *fields; @@ -368,6 +380,43 @@ void towire_accept_channel_tlvs(u8 **pptr, const struct tlv_accept_channel_tlvs bool accept_channel_tlvs_is_valid(const struct tlv_accept_channel_tlvs *record, size_t *err_index); +struct tlv_shutdown_tlvs *tlv_shutdown_tlvs_new(const tal_t *ctx); + +/** + * Deserialize a TLV stream for the shutdown_tlvs namespace. + * + * This function will parse any TLV stream, as long as the type, length and + * value fields are formatted correctly. Fields that are not known in the + * current namespace are stored in the `fields` member. Validity can be + * checked using shutdown_tlvs_is_valid. + */ +bool fromwire_shutdown_tlvs(const u8 **cursor, size_t *max, + struct tlv_shutdown_tlvs * record); + +/** + * Serialize a TLV stream for the shutdown_tlvs namespace. + * + * This function only considers known fields from the shutdown_tlvs namespace, + * and will ignore any fields that may be stored in the `fields` member. This + * ensures that the resulting stream is valid according to + * `shutdown_tlvs_is_valid`. + */ +void towire_shutdown_tlvs(u8 **pptr, const struct tlv_shutdown_tlvs *record); + +/** + * Check that the TLV stream is valid. + * + * Enforces the followin validity rules: + * - Types must be in monotonic non-repeating order + * - We must understand all even types + * + * Returns false if an error was detected, otherwise returns true. If err_index + * is non-null and we detect an error it is set to the index of the first error + * detected. + */ +bool shutdown_tlvs_is_valid(const struct tlv_shutdown_tlvs *record, + size_t *err_index); + struct tlv_query_short_channel_ids_tlvs *tlv_query_short_channel_ids_tlvs_new(const tal_t *ctx); /** @@ -565,8 +614,8 @@ u8 *towire_funding_locked(const tal_t *ctx, const struct channel_id *channel_id, bool fromwire_funding_locked(const void *p, struct channel_id *channel_id, struct pubkey *next_per_commitment_point); /* WIRE: SHUTDOWN */ -u8 *towire_shutdown(const tal_t *ctx, const struct channel_id *channel_id, const u8 *scriptpubkey); -bool fromwire_shutdown(const tal_t *ctx, const void *p, struct channel_id *channel_id, u8 **scriptpubkey); +u8 *towire_shutdown(const tal_t *ctx, const struct channel_id *channel_id, const u8 *scriptpubkey, const struct tlv_shutdown_tlvs *tlvs); +bool fromwire_shutdown(const tal_t *ctx, const void *p, struct channel_id *channel_id, u8 **scriptpubkey, struct tlv_shutdown_tlvs *tlvs); /* WIRE: CLOSING_SIGNED */ u8 *towire_closing_signed(const tal_t *ctx, const struct channel_id *channel_id, struct amount_sat fee_satoshis, const secp256k1_ecdsa_signature *signature); @@ -650,4 +699,4 @@ bool fromwire_channel_update_option_channel_htlc_max(const void *p, secp256k1_ec #endif /* LIGHTNING_WIRE_PEER_WIREGEN_H */ -// SHA256STAMP:1b0c5319cd9ab8c0281132a4c64ca51ecd9ee0158c7f645e102f401ac64ca439 +// SHA256STAMP:c7056cc0ec6b038e425e0800dce339f6ba38a18f14d1b33271656de218052ee2 diff --git a/wire/test/run-peer-wire.c b/wire/test/run-peer-wire.c index cd7b7665d..160a889bb 100644 --- a/wire/test/run-peer-wire.c +++ b/wire/test/run-peer-wire.c @@ -634,7 +634,8 @@ static void *towire_struct_shutdown(const tal_t *ctx, { return towire_shutdown(ctx, &s->channel_id, - s->scriptpubkey); + s->scriptpubkey, + NULL); } static struct msg_shutdown *fromwire_struct_shutdown(const tal_t *ctx, const void *p) @@ -642,8 +643,9 @@ static struct msg_shutdown *fromwire_struct_shutdown(const tal_t *ctx, const voi struct msg_shutdown *s = tal(ctx, struct msg_shutdown); if (!fromwire_shutdown(s, p, - &s->channel_id, - &s->scriptpubkey)) + &s->channel_id, + &s->scriptpubkey, + NULL)) return tal_free(s); return s; }