From 559fc6c86402e10e1bf62962cf990a9c3227f8fb Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 3 Jun 2021 20:31:55 +0930 Subject: [PATCH 01/16] gen/impl_template: fix generation of singleton varsize elements. And as Lisa requested, add testcases. Signed-off-by: Rusty Russell --- channeld/channeld_wiregen.c | 2 +- channeld/channeld_wiregen.h | 2 +- closingd/closingd_wiregen.c | 2 +- closingd/closingd_wiregen.h | 2 +- common/peer_status_wiregen.c | 2 +- common/peer_status_wiregen.h | 2 +- common/status_wiregen.c | 2 +- common/status_wiregen.h | 2 +- connectd/connectd_gossipd_wiregen.c | 2 +- connectd/connectd_gossipd_wiregen.h | 2 +- connectd/connectd_wiregen.c | 2 +- connectd/connectd_wiregen.h | 2 +- gossipd/gossip_store_wiregen.c | 2 +- gossipd/gossip_store_wiregen.h | 2 +- gossipd/gossipd_peerd_wiregen.c | 2 +- gossipd/gossipd_peerd_wiregen.h | 2 +- gossipd/gossipd_wiregen.c | 2 +- gossipd/gossipd_wiregen.h | 2 +- hsmd/hsmd_wiregen.c | 2 +- hsmd/hsmd_wiregen.h | 2 +- onchaind/onchaind_wiregen.c | 2 +- onchaind/onchaind_wiregen.h | 2 +- openingd/dualopend_wiregen.c | 2 +- openingd/dualopend_wiregen.h | 2 +- openingd/openingd_wiregen.c | 2 +- openingd/openingd_wiregen.h | 2 +- tools/gen/impl_template | 2 +- tools/test/test_cases | 7 +++++++ wire/bolt12_wiregen.c | 2 +- wire/bolt12_wiregen.h | 2 +- wire/common_wiregen.c | 2 +- wire/common_wiregen.h | 2 +- wire/onion_printgen.c | 2 +- wire/onion_printgen.h | 2 +- wire/onion_wiregen.c | 2 +- wire/onion_wiregen.h | 2 +- wire/peer_printgen.c | 2 +- wire/peer_printgen.h | 2 +- wire/peer_wiregen.c | 2 +- wire/peer_wiregen.h | 2 +- 40 files changed, 46 insertions(+), 39 deletions(-) diff --git a/channeld/channeld_wiregen.c b/channeld/channeld_wiregen.c index 4d4fe6c676e4..ebf2efcae2f2 100644 --- a/channeld/channeld_wiregen.c +++ b/channeld/channeld_wiregen.c @@ -1113,4 +1113,4 @@ bool fromwire_channeld_dev_quiesce_reply(const void *p) return false; return cursor != NULL; } -// SHA256STAMP:720f9917311384d373593dc1550619ddf461bdabde8b312ed6dc632cb7860c34 +// SHA256STAMP:fa8ee25e2f6082e9889962218e6e345dcb4430840b8f831b40cbb0c415b690b5 diff --git a/channeld/channeld_wiregen.h b/channeld/channeld_wiregen.h index 7d6f16c5426d..1b4293a30853 100644 --- a/channeld/channeld_wiregen.h +++ b/channeld/channeld_wiregen.h @@ -225,4 +225,4 @@ bool fromwire_channeld_dev_quiesce_reply(const void *p); #endif /* LIGHTNING_CHANNELD_CHANNELD_WIREGEN_H */ -// SHA256STAMP:720f9917311384d373593dc1550619ddf461bdabde8b312ed6dc632cb7860c34 +// SHA256STAMP:fa8ee25e2f6082e9889962218e6e345dcb4430840b8f831b40cbb0c415b690b5 diff --git a/closingd/closingd_wiregen.c b/closingd/closingd_wiregen.c index 91f2693f80ca..d1a94dfb55f4 100644 --- a/closingd/closingd_wiregen.c +++ b/closingd/closingd_wiregen.c @@ -213,4 +213,4 @@ bool fromwire_closingd_complete(const void *p) return false; return cursor != NULL; } -// SHA256STAMP:95043321951ace6f7a5ee9f1dc0ae57c8a6427644b8b79d3e08e521dc9b3b49f +// SHA256STAMP:8a13df246be151bcef3dae15a9853016119248d330e76ab79d7013a11d5ecd23 diff --git a/closingd/closingd_wiregen.h b/closingd/closingd_wiregen.h index ea2aa4f2e144..9f46a12b97fe 100644 --- a/closingd/closingd_wiregen.h +++ b/closingd/closingd_wiregen.h @@ -56,4 +56,4 @@ bool fromwire_closingd_complete(const void *p); #endif /* LIGHTNING_CLOSINGD_CLOSINGD_WIREGEN_H */ -// SHA256STAMP:95043321951ace6f7a5ee9f1dc0ae57c8a6427644b8b79d3e08e521dc9b3b49f +// SHA256STAMP:8a13df246be151bcef3dae15a9853016119248d330e76ab79d7013a11d5ecd23 diff --git a/common/peer_status_wiregen.c b/common/peer_status_wiregen.c index 08982e737f80..0f12fa92a76f 100644 --- a/common/peer_status_wiregen.c +++ b/common/peer_status_wiregen.c @@ -80,4 +80,4 @@ bool fromwire_status_peer_error(const tal_t *ctx, const void *p, struct channel_ fromwire_u8_array(&cursor, &plen, *error_for_them, len); return cursor != NULL; } -// SHA256STAMP:c002247f54d5016e614dd6d757c7d06f65c713c3e19d17901f7f685a6bd4b9d9 +// SHA256STAMP:9d6739d97294bd0ec0691772616c4d3d0328d399ed2bef6c943f912aca7d438a diff --git a/common/peer_status_wiregen.h b/common/peer_status_wiregen.h index a95a6f27524e..52d7941aecff 100644 --- a/common/peer_status_wiregen.h +++ b/common/peer_status_wiregen.h @@ -34,4 +34,4 @@ bool fromwire_status_peer_error(const tal_t *ctx, const void *p, struct channel_ #endif /* LIGHTNING_COMMON_PEER_STATUS_WIREGEN_H */ -// SHA256STAMP:c002247f54d5016e614dd6d757c7d06f65c713c3e19d17901f7f685a6bd4b9d9 +// SHA256STAMP:9d6739d97294bd0ec0691772616c4d3d0328d399ed2bef6c943f912aca7d438a diff --git a/common/status_wiregen.c b/common/status_wiregen.c index e56e59aac151..d97b9ee0f765 100644 --- a/common/status_wiregen.c +++ b/common/status_wiregen.c @@ -214,4 +214,4 @@ bool fromwire_status_version(const tal_t *ctx, const void *p, wirestring **versi *version = fromwire_wirestring(ctx, &cursor, &plen); return cursor != NULL; } -// SHA256STAMP:8e1ba9cbc812c8aad76c5049fcecefea2d706a100423c93d3c3be0afcbee851e +// SHA256STAMP:3164c82c28124ba916aebd075baa2315cd82cee0d785908da25c6aa6c5b11f22 diff --git a/common/status_wiregen.h b/common/status_wiregen.h index c41cb23111ee..9a45697e02bc 100644 --- a/common/status_wiregen.h +++ b/common/status_wiregen.h @@ -58,4 +58,4 @@ bool fromwire_status_version(const tal_t *ctx, const void *p, wirestring **versi #endif /* LIGHTNING_COMMON_STATUS_WIREGEN_H */ -// SHA256STAMP:8e1ba9cbc812c8aad76c5049fcecefea2d706a100423c93d3c3be0afcbee851e +// SHA256STAMP:3164c82c28124ba916aebd075baa2315cd82cee0d785908da25c6aa6c5b11f22 diff --git a/connectd/connectd_gossipd_wiregen.c b/connectd/connectd_gossipd_wiregen.c index 7332fec6bcc1..ac2856c3abe5 100644 --- a/connectd/connectd_gossipd_wiregen.c +++ b/connectd/connectd_gossipd_wiregen.c @@ -161,4 +161,4 @@ bool fromwire_gossipd_get_addrs_reply(const tal_t *ctx, const void *p, struct wi fromwire_wireaddr(&cursor, &plen, *addrs + i); return cursor != NULL; } -// SHA256STAMP:3843c1c89472b3084feca4bb6d0a39598f768d4c4ff866f8dc94169716b6fadd +// SHA256STAMP:6bfe0677cb910aba63f79cfc4164ce26034da95e16341eab3aac6fddcc04e3e9 diff --git a/connectd/connectd_gossipd_wiregen.h b/connectd/connectd_gossipd_wiregen.h index 2bc0fb24721a..5c391775adcd 100644 --- a/connectd/connectd_gossipd_wiregen.h +++ b/connectd/connectd_gossipd_wiregen.h @@ -54,4 +54,4 @@ bool fromwire_gossipd_get_addrs_reply(const tal_t *ctx, const void *p, struct wi #endif /* LIGHTNING_CONNECTD_CONNECTD_GOSSIPD_WIREGEN_H */ -// SHA256STAMP:3843c1c89472b3084feca4bb6d0a39598f768d4c4ff866f8dc94169716b6fadd +// SHA256STAMP:6bfe0677cb910aba63f79cfc4164ce26034da95e16341eab3aac6fddcc04e3e9 diff --git a/connectd/connectd_wiregen.c b/connectd/connectd_wiregen.c index a76e3e007f5a..3ee9ea506f2e 100644 --- a/connectd/connectd_wiregen.c +++ b/connectd/connectd_wiregen.c @@ -443,4 +443,4 @@ bool fromwire_connectd_dev_memleak_reply(const void *p, bool *leak) *leak = fromwire_bool(&cursor, &plen); return cursor != NULL; } -// SHA256STAMP:7c9585941825eab65d734eb1c233eee5c78b5792e19ec68f0a9986abca2b0ffe +// SHA256STAMP:042c0ae692c223da86af3f09977fdc5f19655e99b928ab05812dd4c1ed95f1c5 diff --git a/connectd/connectd_wiregen.h b/connectd/connectd_wiregen.h index 46e1ecb00c77..34ad8ca34f41 100644 --- a/connectd/connectd_wiregen.h +++ b/connectd/connectd_wiregen.h @@ -110,4 +110,4 @@ bool fromwire_connectd_dev_memleak_reply(const void *p, bool *leak); #endif /* LIGHTNING_CONNECTD_CONNECTD_WIREGEN_H */ -// SHA256STAMP:7c9585941825eab65d734eb1c233eee5c78b5792e19ec68f0a9986abca2b0ffe +// SHA256STAMP:042c0ae692c223da86af3f09977fdc5f19655e99b928ab05812dd4c1ed95f1c5 diff --git a/gossipd/gossip_store_wiregen.c b/gossipd/gossip_store_wiregen.c index d4c464481687..90cbd0b07a7b 100644 --- a/gossipd/gossip_store_wiregen.c +++ b/gossipd/gossip_store_wiregen.c @@ -210,4 +210,4 @@ bool fromwire_gossipd_local_add_channel_obs(const tal_t *ctx, const void *p, str fromwire_u8_array(&cursor, &plen, *features, flen); return cursor != NULL; } -// SHA256STAMP:18d52e526a219c3a8bb29c6a29b7bd82880c5befdde88c12424d57cb98a28b17 +// SHA256STAMP:3e6e23b99855a3be9305cbc297d59d818cc193d6ebe5c2ca78dfb6ec5df31e94 diff --git a/gossipd/gossip_store_wiregen.h b/gossipd/gossip_store_wiregen.h index 2ff5bc91b8fc..0941d51e6151 100644 --- a/gossipd/gossip_store_wiregen.h +++ b/gossipd/gossip_store_wiregen.h @@ -63,4 +63,4 @@ bool fromwire_gossipd_local_add_channel_obs(const tal_t *ctx, const void *p, str #endif /* LIGHTNING_GOSSIPD_GOSSIP_STORE_WIREGEN_H */ -// SHA256STAMP:18d52e526a219c3a8bb29c6a29b7bd82880c5befdde88c12424d57cb98a28b17 +// SHA256STAMP:3e6e23b99855a3be9305cbc297d59d818cc193d6ebe5c2ca78dfb6ec5df31e94 diff --git a/gossipd/gossipd_peerd_wiregen.c b/gossipd/gossipd_peerd_wiregen.c index 4a8710da0e25..a6ff50636ec1 100644 --- a/gossipd/gossipd_peerd_wiregen.c +++ b/gossipd/gossipd_peerd_wiregen.c @@ -161,4 +161,4 @@ bool fromwire_gossipd_local_channel_announcement(const tal_t *ctx, const void *p fromwire_u8_array(&cursor, &plen, *cannount, len); return cursor != NULL; } -// SHA256STAMP:2ef99c782b9877add7912c680d3a48bed3372c6a6fe2410716651dbe777493eb +// SHA256STAMP:e55284452718ed1baf12a38736b4bfeecc8bb18dac8ad4f0ee0b5dc8904fbdc2 diff --git a/gossipd/gossipd_peerd_wiregen.h b/gossipd/gossipd_peerd_wiregen.h index e20d4a5f3f32..8240e6616c78 100644 --- a/gossipd/gossipd_peerd_wiregen.h +++ b/gossipd/gossipd_peerd_wiregen.h @@ -57,4 +57,4 @@ bool fromwire_gossipd_local_channel_announcement(const tal_t *ctx, const void *p #endif /* LIGHTNING_GOSSIPD_GOSSIPD_PEERD_WIREGEN_H */ -// SHA256STAMP:2ef99c782b9877add7912c680d3a48bed3372c6a6fe2410716651dbe777493eb +// SHA256STAMP:e55284452718ed1baf12a38736b4bfeecc8bb18dac8ad4f0ee0b5dc8904fbdc2 diff --git a/gossipd/gossipd_wiregen.c b/gossipd/gossipd_wiregen.c index c0a3b279e432..6e86ca01e0e8 100644 --- a/gossipd/gossipd_wiregen.c +++ b/gossipd/gossipd_wiregen.c @@ -1057,4 +1057,4 @@ bool fromwire_gossipd_addgossip_reply(const tal_t *ctx, const void *p, wirestrin *err = fromwire_wirestring(ctx, &cursor, &plen); return cursor != NULL; } -// SHA256STAMP:5fb4bcc3bb8c5f312041142d4bf555a2187c82d82921b819d5a45410efddf6f3 +// SHA256STAMP:a0d7494995d7f95fb7df295bab9d865e18670f15243116a0aaa9b9548534b922 diff --git a/gossipd/gossipd_wiregen.h b/gossipd/gossipd_wiregen.h index 5bbfca57c60b..0e989c517672 100644 --- a/gossipd/gossipd_wiregen.h +++ b/gossipd/gossipd_wiregen.h @@ -225,4 +225,4 @@ bool fromwire_gossipd_addgossip_reply(const tal_t *ctx, const void *p, wirestrin #endif /* LIGHTNING_GOSSIPD_GOSSIPD_WIREGEN_H */ -// SHA256STAMP:5fb4bcc3bb8c5f312041142d4bf555a2187c82d82921b819d5a45410efddf6f3 +// SHA256STAMP:a0d7494995d7f95fb7df295bab9d865e18670f15243116a0aaa9b9548534b922 diff --git a/hsmd/hsmd_wiregen.c b/hsmd/hsmd_wiregen.c index a664c0472d23..048a49a282d6 100644 --- a/hsmd/hsmd_wiregen.c +++ b/hsmd/hsmd_wiregen.c @@ -1278,4 +1278,4 @@ bool fromwire_hsmd_sign_bolt12_reply(const void *p, struct bip340sig *sig) fromwire_bip340sig(&cursor, &plen, sig); return cursor != NULL; } -// SHA256STAMP:b419989953cbf50796fc237b5d7e2043f96cb838a1356dbdb27943b341f611a8 +// SHA256STAMP:535c69a065c06a2e2ea151154ae83b53283d1c5b34e18b43a2c12c9444472548 diff --git a/hsmd/hsmd_wiregen.h b/hsmd/hsmd_wiregen.h index a86a7da16474..1da52edbcb21 100644 --- a/hsmd/hsmd_wiregen.h +++ b/hsmd/hsmd_wiregen.h @@ -283,4 +283,4 @@ bool fromwire_hsmd_sign_bolt12_reply(const void *p, struct bip340sig *sig); #endif /* LIGHTNING_HSMD_HSMD_WIREGEN_H */ -// SHA256STAMP:b419989953cbf50796fc237b5d7e2043f96cb838a1356dbdb27943b341f611a8 +// SHA256STAMP:535c69a065c06a2e2ea151154ae83b53283d1c5b34e18b43a2c12c9444472548 diff --git a/onchaind/onchaind_wiregen.c b/onchaind/onchaind_wiregen.c index 155bffbcd37b..27797ad01bc7 100644 --- a/onchaind/onchaind_wiregen.c +++ b/onchaind/onchaind_wiregen.c @@ -635,4 +635,4 @@ bool fromwire_onchaind_notify_coin_mvt(const void *p, struct chain_coin_mvt *mvt fromwire_chain_coin_mvt(&cursor, &plen, mvt); return cursor != NULL; } -// SHA256STAMP:ef6140d74f021a554c055b0f9b6322334559e6c2059ea51abf1bda2bc90add41 +// SHA256STAMP:6884d8c13750d6bb08de384fe35050309f8f66037662671c2aad2eaa16f47463 diff --git a/onchaind/onchaind_wiregen.h b/onchaind/onchaind_wiregen.h index e557d6dc3305..4d53b35f31ea 100644 --- a/onchaind/onchaind_wiregen.h +++ b/onchaind/onchaind_wiregen.h @@ -161,4 +161,4 @@ bool fromwire_onchaind_notify_coin_mvt(const void *p, struct chain_coin_mvt *mvt #endif /* LIGHTNING_ONCHAIND_ONCHAIND_WIREGEN_H */ -// SHA256STAMP:ef6140d74f021a554c055b0f9b6322334559e6c2059ea51abf1bda2bc90add41 +// SHA256STAMP:6884d8c13750d6bb08de384fe35050309f8f66037662671c2aad2eaa16f47463 diff --git a/openingd/dualopend_wiregen.c b/openingd/dualopend_wiregen.c index 21ace02e4cb4..21d658ecb710 100644 --- a/openingd/dualopend_wiregen.c +++ b/openingd/dualopend_wiregen.c @@ -912,4 +912,4 @@ bool fromwire_dualopend_dev_memleak_reply(const void *p, bool *leak) *leak = fromwire_bool(&cursor, &plen); return cursor != NULL; } -// SHA256STAMP:0cbaf66a07e1ffa2e01a85398b6937391af66eb78302e22fe7b9a3076963db4e +// SHA256STAMP:0a1ed6e8461512630be3bb328083495d5c5f682c59dfb24561024ba8fa0d3b70 diff --git a/openingd/dualopend_wiregen.h b/openingd/dualopend_wiregen.h index ac4c0597a1f2..de36baf2f782 100644 --- a/openingd/dualopend_wiregen.h +++ b/openingd/dualopend_wiregen.h @@ -216,4 +216,4 @@ bool fromwire_dualopend_dev_memleak_reply(const void *p, bool *leak); #endif /* LIGHTNING_OPENINGD_DUALOPEND_WIREGEN_H */ -// SHA256STAMP:0cbaf66a07e1ffa2e01a85398b6937391af66eb78302e22fe7b9a3076963db4e +// SHA256STAMP:0a1ed6e8461512630be3bb328083495d5c5f682c59dfb24561024ba8fa0d3b70 diff --git a/openingd/openingd_wiregen.c b/openingd/openingd_wiregen.c index 28442fda3cea..7f615aa0996d 100644 --- a/openingd/openingd_wiregen.c +++ b/openingd/openingd_wiregen.c @@ -569,4 +569,4 @@ bool fromwire_openingd_dev_memleak_reply(const void *p, bool *leak) *leak = fromwire_bool(&cursor, &plen); return cursor != NULL; } -// SHA256STAMP:edd7ee392dff0ddd0dff3a383692ba852a403e64e43290dba5dece69ae438e61 +// SHA256STAMP:d2fcabdf157b098608e47dcdc37db0f46fe8d466d74159969544d7c4bb77f061 diff --git a/openingd/openingd_wiregen.h b/openingd/openingd_wiregen.h index ba64e5567272..047c82110783 100644 --- a/openingd/openingd_wiregen.h +++ b/openingd/openingd_wiregen.h @@ -121,4 +121,4 @@ bool fromwire_openingd_dev_memleak_reply(const void *p, bool *leak); #endif /* LIGHTNING_OPENINGD_OPENINGD_WIREGEN_H */ -// SHA256STAMP:edd7ee392dff0ddd0dff3a383692ba852a403e64e43290dba5dece69ae438e61 +// SHA256STAMP:d2fcabdf157b098608e47dcdc37db0f46fe8d466d74159969544d7c4bb77f061 diff --git a/tools/gen/impl_template b/tools/gen/impl_template index 0d1cc6991453..8df0bb035fa1 100644 --- a/tools/gen/impl_template +++ b/tools/gen/impl_template @@ -244,7 +244,7 @@ static void fromwire_${msg.struct_name()}(const u8 **cursor, size_t *plen, void fieldname = 'r->{}->{}'.format(msg.name, f.name) ctx = 'r->{}'.format(msg.name) %>\ - ${fromwire_subtype_field(fieldname, f, ctx, msg.singleton())}\ + ${fromwire_subtype_field(fieldname, f, ctx, msg.singleton() and not f.type_obj.is_varsize())}\ % endfor } % endfor diff --git a/tools/test/test_cases b/tools/test/test_cases index 4854a1dbfa16..6ff99f53afd4 100644 --- a/tools/test/test_cases +++ b/tools/test/test_cases @@ -148,3 +148,10 @@ tlvdata,test_n3,tlv3,len_varlenvarsize,u8, tlvdata,test_n3,tlv3,varlen_varsize,test_features,len_varlenvarsize # implicit length tlvdata,test_n3,tlv3,remainder,byte,... +# Singletons which needs a context. +tlvtype,test_n3,tlv4,4 +tlvdata,test_n3,tlv4,singleton_varlen,subtype_var_len, +tlvtype,test_n3,tlv5,5 +tlvdata,test_n3,tlv5,singleton_varlen_arr,subtype_var_len,... +tlvtype,test_n3,tlv6,6 +tlvdata,test_n3,tlv6,singleton_varlen_assign,subtype_var_assign, diff --git a/wire/bolt12_wiregen.c b/wire/bolt12_wiregen.c index eadac6be9eab..9624c2129123 100644 --- a/wire/bolt12_wiregen.c +++ b/wire/bolt12_wiregen.c @@ -1562,4 +1562,4 @@ bool invoice_error_is_valid(const struct tlv_invoice_error *record, size_t *err_ return tlv_fields_valid(record->fields, err_index); } -// SHA256STAMP:3c8dc54796300320573ccf24c2ec022c4f95f545576e909e55da001c1d04392d +// SHA256STAMP:85a22376bfbb4d4b5c1104ae7823b477443ac693db9b2ee53c16b777b74f7d2a diff --git a/wire/bolt12_wiregen.h b/wire/bolt12_wiregen.h index 182bf4d98561..b8859094ac7c 100644 --- a/wire/bolt12_wiregen.h +++ b/wire/bolt12_wiregen.h @@ -316,4 +316,4 @@ struct fallback_address *fromwire_fallback_address(const tal_t *ctx, const u8 ** #endif /* LIGHTNING_WIRE_BOLT12_WIREGEN_H */ -// SHA256STAMP:3c8dc54796300320573ccf24c2ec022c4f95f545576e909e55da001c1d04392d +// SHA256STAMP:85a22376bfbb4d4b5c1104ae7823b477443ac693db9b2ee53c16b777b74f7d2a diff --git a/wire/common_wiregen.c b/wire/common_wiregen.c index a855dfd58194..1355150fd480 100644 --- a/wire/common_wiregen.c +++ b/wire/common_wiregen.c @@ -100,4 +100,4 @@ bool fromwire_custommsg_out(const tal_t *ctx, const void *p, u8 **msg) fromwire_u8_array(&cursor, &plen, *msg, msg_len); return cursor != NULL; } -// SHA256STAMP:4498506058a2fd50f9b5adca97e08dce48d1812157ee24829b962eff59e3afa6 +// SHA256STAMP:a747ee0bc8a91c00e719bae883b505d6e7c85b33165a9156a571a0aa171a7256 diff --git a/wire/common_wiregen.h b/wire/common_wiregen.h index fc33a4afa27c..9efd995e40c3 100644 --- a/wire/common_wiregen.h +++ b/wire/common_wiregen.h @@ -41,4 +41,4 @@ bool fromwire_custommsg_out(const tal_t *ctx, const void *p, u8 **msg); #endif /* LIGHTNING_WIRE_COMMON_WIREGEN_H */ -// SHA256STAMP:4498506058a2fd50f9b5adca97e08dce48d1812157ee24829b962eff59e3afa6 +// SHA256STAMP:a747ee0bc8a91c00e719bae883b505d6e7c85b33165a9156a571a0aa171a7256 diff --git a/wire/onion_printgen.c b/wire/onion_printgen.c index 7d6d7d734d02..8ea922f610e5 100644 --- a/wire/onion_printgen.c +++ b/wire/onion_printgen.c @@ -859,4 +859,4 @@ void printonion_wire_tlv_message(const char *tlv_name, const u8 *msg) { printwire_tlvs(tlv_name, &msg, &plen, print_tlvs_encmsg_tlvs, ARRAY_SIZE(print_tlvs_encmsg_tlvs)); } } -// SHA256STAMP:474b138bc0e571b8e5b3a9ce48b263b13b9dc3d516eaada1154e3c3d518d46f9 +// SHA256STAMP:c3ff8c1573066a7cae73a1e5ce1c8c5b5dd7e241129393e600eaf2a4fd6b9f3e diff --git a/wire/onion_printgen.h b/wire/onion_printgen.h index fa89d3865984..7a7a1ea743b4 100644 --- a/wire/onion_printgen.h +++ b/wire/onion_printgen.h @@ -58,4 +58,4 @@ void printwire_mpp_timeout(const char *fieldname, const u8 *cursor); void printwire_onionmsg_path(const char *fieldname, const u8 **cursor, size_t *plen); #endif /* LIGHTNING_WIRE_ONION_PRINTGEN_H */ -// SHA256STAMP:474b138bc0e571b8e5b3a9ce48b263b13b9dc3d516eaada1154e3c3d518d46f9 +// SHA256STAMP:c3ff8c1573066a7cae73a1e5ce1c8c5b5dd7e241129393e600eaf2a4fd6b9f3e diff --git a/wire/onion_wiregen.c b/wire/onion_wiregen.c index 8083c45de98d..425ad34f79ad 100644 --- a/wire/onion_wiregen.c +++ b/wire/onion_wiregen.c @@ -1026,4 +1026,4 @@ bool fromwire_mpp_timeout(const void *p) return false; return cursor != NULL; } -// SHA256STAMP:474b138bc0e571b8e5b3a9ce48b263b13b9dc3d516eaada1154e3c3d518d46f9 +// SHA256STAMP:c3ff8c1573066a7cae73a1e5ce1c8c5b5dd7e241129393e600eaf2a4fd6b9f3e diff --git a/wire/onion_wiregen.h b/wire/onion_wiregen.h index e7b95a7c3899..5ca402e6d232 100644 --- a/wire/onion_wiregen.h +++ b/wire/onion_wiregen.h @@ -317,4 +317,4 @@ bool fromwire_mpp_timeout(const void *p); #endif /* LIGHTNING_WIRE_ONION_WIREGEN_H */ -// SHA256STAMP:474b138bc0e571b8e5b3a9ce48b263b13b9dc3d516eaada1154e3c3d518d46f9 +// SHA256STAMP:c3ff8c1573066a7cae73a1e5ce1c8c5b5dd7e241129393e600eaf2a4fd6b9f3e diff --git a/wire/peer_printgen.c b/wire/peer_printgen.c index 42b8111a5d01..b2ae43f11b83 100644 --- a/wire/peer_printgen.c +++ b/wire/peer_printgen.c @@ -2935,4 +2935,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:aecb66d3600732f50b4279272e4c057d1ea410bddf41cbb01b6326320f5b9de8 +// SHA256STAMP:3ecafff6be37e4049f121dcd6816aada2818fc7c02099372d1358d1b5b9da1ca diff --git a/wire/peer_printgen.h b/wire/peer_printgen.h index c482da369df7..7e494852b018 100644 --- a/wire/peer_printgen.h +++ b/wire/peer_printgen.h @@ -96,4 +96,4 @@ void printwire_channel_update_checksums(const char *fieldname, const u8 **cursor void printwire_channel_update_timestamps(const char *fieldname, const u8 **cursor, size_t *plen); void printwire_witness_stack(const char *fieldname, const u8 **cursor, size_t *plen); #endif /* LIGHTNING_WIRE_PEER_PRINTGEN_H */ -// SHA256STAMP:aecb66d3600732f50b4279272e4c057d1ea410bddf41cbb01b6326320f5b9de8 +// SHA256STAMP:3ecafff6be37e4049f121dcd6816aada2818fc7c02099372d1358d1b5b9da1ca diff --git a/wire/peer_wiregen.c b/wire/peer_wiregen.c index 0f4a630e893a..d025048e5afb 100644 --- a/wire/peer_wiregen.c +++ b/wire/peer_wiregen.c @@ -2330,4 +2330,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:aecb66d3600732f50b4279272e4c057d1ea410bddf41cbb01b6326320f5b9de8 +// SHA256STAMP:3ecafff6be37e4049f121dcd6816aada2818fc7c02099372d1358d1b5b9da1ca diff --git a/wire/peer_wiregen.h b/wire/peer_wiregen.h index f112c1182080..f4b5b7722b43 100644 --- a/wire/peer_wiregen.h +++ b/wire/peer_wiregen.h @@ -859,4 +859,4 @@ bool fromwire_channel_update_option_channel_htlc_max(const void *p, secp256k1_ec #endif /* LIGHTNING_WIRE_PEER_WIREGEN_H */ -// SHA256STAMP:aecb66d3600732f50b4279272e4c057d1ea410bddf41cbb01b6326320f5b9de8 +// SHA256STAMP:3ecafff6be37e4049f121dcd6816aada2818fc7c02099372d1358d1b5b9da1ca From a6e93fafb30efd344941be6008e895a7d23846a8 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 4 Jun 2021 11:23:43 +0930 Subject: [PATCH 02/16] onchaind: don't rely on knowing option_static_remotekey for unknown commitments. Just always handle both cases. Signed-off-by: Rusty Russell --- onchaind/onchaind.c | 91 ++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index 1e1857fa085b..76a060ae3838 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -3594,79 +3594,86 @@ static void handle_unknown_commitment(const struct tx_parts *tx, bool is_replay) { int to_us_output = -1; - u8 *local_script; + /* We have two possible local scripts, depending on options */ + u8 *local_scripts[2]; struct amount_sat amt_salvaged = AMOUNT_SAT(0); onchain_annotate_txin(&tx->txid, 0, TX_CHANNEL_UNILATERAL | TX_THEIRS); resolved_by_other(outs[0], &tx->txid, UNKNOWN_UNILATERAL); - /* If they don't give us a per-commitment point and we rotate keys, - * we're out of luck. */ - if (!possible_remote_per_commitment_point - && !option_static_remotekey) { - goto search_done; - } - - if (!option_static_remotekey) { + /* This is the not-option_static_remotekey case, if we got a hint + * from them about the per-commitment point */ + if (possible_remote_per_commitment_point) { struct keyset *ks = tal(tmpctx, struct keyset); if (!derive_keyset(possible_remote_per_commitment_point, &basepoints[REMOTE], &basepoints[LOCAL], - option_static_remotekey, + false, ks)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Deriving keyset for possible_remote_per_commitment_point %s", type_to_string(tmpctx, struct pubkey, possible_remote_per_commitment_point)); - local_script = scriptpubkey_p2wpkh(tmpctx, - &ks->other_payment_key); + local_scripts[0] = scriptpubkey_p2wpkh(tmpctx, + &ks->other_payment_key); } else { - local_script = scriptpubkey_to_remote(tmpctx, - &basepoints[LOCAL].payment); + local_scripts[0] = NULL; } + /* Other possible local script is for option_static_remotekey */ + local_scripts[1] = scriptpubkey_to_remote(tmpctx, + &basepoints[LOCAL].payment); + for (size_t i = 0; i < tal_count(tx->outputs); i++) { struct tracked_output *out; struct amount_asset asset = wally_tx_output_get_amount(tx->outputs[i]); struct amount_sat amt; + int which_script; + assert(amount_asset_is_main(&asset)); amt = amount_asset_to_sat(&asset); - if (local_script - && wally_tx_output_scripteq(tx->outputs[i], - local_script)) { - /* BOLT #5: - * - * - MAY take no action in regard to the associated - * `to_remote`, which is simply a P2WPKH output to - * the *local node*. - * - Note: `to_remote` is considered *resolved* by the - * commitment transaction itself. - */ - out = new_tracked_output(&outs, &tx->txid, tx_blockheight, - UNKNOWN_UNILATERAL, - i, amt, - OUTPUT_TO_US, NULL, NULL, NULL); - ignore_output(out); + /* Elements can have empty output scripts (fee output) */ + if (local_scripts[0] + && wally_tx_output_scripteq(tx->outputs[i], local_scripts[0])) + which_script = 0; + else if (local_scripts[1] + && wally_tx_output_scripteq(tx->outputs[i], + local_scripts[1])) + which_script = 1; + else + continue; - if (!is_replay) - record_channel_withdrawal(&tx->txid, tx_blockheight, out); + /* BOLT #5: + * + * - MAY take no action in regard to the associated + * `to_remote`, which is simply a P2WPKH output to + * the *local node*. + * - Note: `to_remote` is considered *resolved* by the + * commitment transaction itself. + */ + out = new_tracked_output(&outs, &tx->txid, tx_blockheight, + UNKNOWN_UNILATERAL, + i, amt, + OUTPUT_TO_US, NULL, NULL, NULL); + ignore_output(out); - add_amt(&amt_salvaged, amt); + if (!is_replay) + record_channel_withdrawal(&tx->txid, tx_blockheight, out); - tell_wallet_to_remote(tx, i, - tx_blockheight, - local_script, - possible_remote_per_commitment_point, - option_static_remotekey); - local_script = NULL; - to_us_output = i; - } + add_amt(&amt_salvaged, amt); + + tell_wallet_to_remote(tx, i, + tx_blockheight, + local_scripts[which_script], + possible_remote_per_commitment_point, + which_script == 1); + local_scripts[0] = local_scripts[1] = NULL; + to_us_output = i; } -search_done: if (to_us_output == -1) { status_broken("FUNDS LOST. Unknown commitment #%"PRIu64"!", commit_num); From 1241362b96640377541817c89bfd952fb1bb4d2e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 4 Jun 2021 11:23:55 +0930 Subject: [PATCH 03/16] onchaind: don't hand redundant commit_num to handle_unknown_commitment. It's a global. Signed-off-by: Rusty Russell --- onchaind/onchaind.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index 76a060ae3838..788c65b26ee3 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -3585,7 +3585,6 @@ static void update_ledger_unknown(const struct bitcoin_txid *txid, static void handle_unknown_commitment(const struct tx_parts *tx, u32 tx_blockheight, - u64 commit_num, const struct pubkey *possible_remote_per_commitment_point, const struct basepoints basepoints[NUM_SIDES], const struct htlc_stub *htlcs, @@ -3912,7 +3911,6 @@ int main(int argc, char *argv[]) open_is_replay); } else { handle_unknown_commitment(tx, tx_blockheight, - commit_num, possible_remote_per_commitment_point, basepoints, htlcs, From 7d5693fcaa8be2547d235fc39c175366701395fa Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 4 Jun 2021 11:23:55 +0930 Subject: [PATCH 04/16] onchaind: limp along if we cheat. We don't handle our own cheat txs: rather than crash, we should just log broken and limp along. This also makes our upcoming penalty test easier: we don't have to spin up a new node. Signed-off-by: Rusty Russell --- onchaind/onchaind.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index 788c65b26ee3..e35a694faa60 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -3206,10 +3206,10 @@ static void handle_their_cheat(const struct tx_parts *tx, } matches = match_htlc_output(tmpctx, tx->outputs[i], htlc_scripts); - if (tal_count(matches) == 0) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Could not find resolution for output %zu", - i); + if (tal_count(matches) == 0) { + status_broken("Could not find resolution for output %zu: did *we* cheat?", i); + continue; + } /* In this case, we don't care which HTLC we choose; so pick first one */ From 67a10cba0b0b665e20c8de6766e0cc1785d42e6f Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 4 Jun 2021 11:23:55 +0930 Subject: [PATCH 05/16] channeld: tweak function to allow testing for pending *uncommitted* changes. For quiescence, we can't have sent any updates at all. But for upgrades on reconnection, we may have already added uncommitted HTLCs for retransmission, but they don't count towards "are we quiesced" since they're not sent yet. Signed-off-by: Rusty Russell --- channeld/channeld.c | 6 +++--- channeld/full_channel.c | 20 ++++++++++++++++---- channeld/full_channel.h | 4 +++- common/fee_states.c | 6 +++++- common/fee_states.h | 5 +++-- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index d33e9da1e2fe..95802ad13715 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -290,7 +290,7 @@ static void maybe_send_stfu(struct peer *peer) if (!peer->stfu) return; - if (!peer->stfu_sent[LOCAL] && !pending_updates(peer->channel, LOCAL)) { + if (!peer->stfu_sent[LOCAL] && !pending_updates(peer->channel, LOCAL, false)) { u8 *msg = towire_stfu(NULL, &peer->channel_id, peer->stfu_initiator == LOCAL); sync_crypto_write(peer->pps, take(msg)); @@ -323,7 +323,7 @@ static void handle_stfu(struct peer *peer, const u8 *stfu) } /* Sanity check */ - if (pending_updates(peer->channel, REMOTE)) + if (pending_updates(peer->channel, REMOTE, false)) peer_failed_warn(peer->pps, &peer->channel_id, "STFU but you still have updates pending?"); @@ -1141,7 +1141,7 @@ static void send_commit(struct peer *peer) /* FIXME: We occasionally desynchronize with LND here, so * don't stress things by having more than one feerate change * in-flight! */ - if (feerate_changes_done(peer->channel->fee_states)) { + if (feerate_changes_done(peer->channel->fee_states, false)) { u8 *msg; if (!channel_update_feerate(peer->channel, feerate_target)) diff --git a/channeld/full_channel.c b/channeld/full_channel.c index 55ae6214c0b3..eb6f0375d1ec 100644 --- a/channeld/full_channel.c +++ b/channeld/full_channel.c @@ -1252,26 +1252,38 @@ static bool adjust_balance(struct balance view_owed[NUM_SIDES][NUM_SIDES], return true; } -bool pending_updates(const struct channel *channel, enum side side) +bool pending_updates(const struct channel *channel, + enum side side, + bool uncommitted_ok) { struct htlc_map_iter it; const struct htlc *htlc; /* Initiator might have fee changes in play. */ if (side == channel->opener) { - if (!feerate_changes_done(channel->fee_states)) + if (!feerate_changes_done(channel->fee_states, uncommitted_ok)) return true; } for (htlc = htlc_map_first(channel->htlcs, &it); htlc; htlc = htlc_map_next(channel->htlcs, &it)) { - /* If it's still being added, it's owner added it. */ - if (htlc_state_flags(htlc->state) & HTLC_ADDING) { + int flags = htlc_state_flags(htlc->state); + + /* If it's still being added, its owner added it. */ + if (flags & HTLC_ADDING) { + /* It might be OK if it's added, but not committed */ + if (uncommitted_ok + && (flags & HTLC_FLAG(!side, HTLC_F_PENDING))) + continue; if (htlc_owner(htlc) == side) return true; /* If it's being removed, non-owner removed it */ } else if (htlc_state_flags(htlc->state) & HTLC_REMOVING) { + /* It might be OK if it's removed, but not committed */ + if (uncommitted_ok + && (flags & HTLC_FLAG(!side, HTLC_F_PENDING))) + continue; if (htlc_owner(htlc) != side) return true; } diff --git a/channeld/full_channel.h b/channeld/full_channel.h index 8f04547eb70b..e23deb3b11fa 100644 --- a/channeld/full_channel.h +++ b/channeld/full_channel.h @@ -258,8 +258,10 @@ void dump_htlcs(const struct channel *channel, const char *prefix); * pending_updates: does this side have updates pending in channel? * @channel: the channel * @side: the side who is offering or failing/fulfilling HTLC, or feechange + * @uncommitted_ok: don't count uncommitted changes. */ -bool pending_updates(const struct channel *channel, enum side side); +bool pending_updates(const struct channel *channel, enum side side, + bool uncommitted_ok); const char *channel_add_err_name(enum channel_add_err e); const char *channel_remove_err_name(enum channel_remove_err e); diff --git a/common/fee_states.c b/common/fee_states.c index c12470911e1d..451d3849f150 100644 --- a/common/fee_states.c +++ b/common/fee_states.c @@ -74,10 +74,14 @@ u32 get_feerate(const struct fee_states *fee_states, } /* Are feerates all agreed by both sides? */ -bool feerate_changes_done(const struct fee_states *fee_states) +bool feerate_changes_done(const struct fee_states *fee_states, + bool ignore_uncommitted) { size_t num_feerates = 0; for (size_t i = 0; i < ARRAY_SIZE(fee_states->feerate); i++) { + if (ignore_uncommitted + && (i == RCVD_ADD_HTLC || i == SENT_ADD_HTLC)) + continue; num_feerates += (fee_states->feerate[i] != NULL); } return num_feerates == 1; diff --git a/common/fee_states.h b/common/fee_states.h index 40cc18ddccd3..cf846002b90e 100644 --- a/common/fee_states.h +++ b/common/fee_states.h @@ -86,7 +86,8 @@ struct fee_states *fromwire_fee_states(const tal_t *ctx, */ bool fee_states_valid(const struct fee_states *fee_states, enum side opener); -/* Are therre no more fee changes in-flight? */ -bool feerate_changes_done(const struct fee_states *fee_states); +/* Are there no more fee changes in-flight? */ +bool feerate_changes_done(const struct fee_states *fee_states, + bool ignore_uncommitted); #endif /* LIGHTNING_COMMON_FEE_STATES_H */ From 5a613c2f3fe9ebc38fbf7f666793e8e2381de6a2 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 4 Jun 2021 11:23:55 +0930 Subject: [PATCH 06/16] common/features: helper to pretty-print feature bits. Signed-off-by: Rusty Russell --- common/features.c | 15 +++++++++++++++ common/features.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/common/features.c b/common/features.c index 681fdc334e99..a0e6fe7bc357 100644 --- a/common/features.c +++ b/common/features.c @@ -497,3 +497,18 @@ void towire_feature_set(u8 **pptr, const struct feature_set *fset) towire_u8_array(pptr, fset->bits[i], tal_bytelen(fset->bits[i])); } } + +const char *fmt_featurebits(const tal_t *ctx, const u8 *featurebits) +{ + size_t size = tal_count(featurebits); + char *fmt = tal_strdup(ctx, ""); + const char *prefix = ""; + + for (size_t i = 0; i < size * 8; i++) { + if (feature_is_set(featurebits, i)) { + tal_append_fmt(&fmt, "%s%zu", prefix, i); + prefix = ","; + } + } + return fmt; +} diff --git a/common/features.h b/common/features.h index a03d6b5ced8e..485262acef6d 100644 --- a/common/features.h +++ b/common/features.h @@ -71,6 +71,9 @@ void set_feature_bit(u8 **ptr, u32 bit); /* Given two featurebit vectors, combine them by applying a logical OR. */ u8 *featurebits_or(const tal_t *ctx, const u8 *f1 TAKES, const u8 *f2 TAKES); +/* Good for debugging: returns comma-separated string of bits. */ +const char *fmt_featurebits(const tal_t *ctx, const u8 *featurebits); + /* BOLT #9: * * Flags are numbered from the least-significant bit, at bit 0 (i.e. 0x1, From f12987005e534b36e45dbf6a1ebdcaa39911ea01 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 4 Jun 2021 14:43:45 +0930 Subject: [PATCH 07/16] channel: import upgrade spec. See https://github.com/lightningnetwork/lightning-rfc/pull/868 Signed-off-by: Rusty Russell --- channeld/channeld.c | 38 +++++++++++++++++++++--- closingd/closingd.c | 19 ++++++++++-- openingd/dualopend.c | 15 ++++++++-- wire/extracted_peer_exp_upgradable.patch | 21 +++++++++++++ wire/peer_wire.c | 9 +++++- 5 files changed, 93 insertions(+), 9 deletions(-) create mode 100644 wire/extracted_peer_exp_upgradable.patch diff --git a/channeld/channeld.c b/channeld/channeld.c index 95802ad13715..620b191b311a 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -1930,12 +1930,19 @@ static void handle_unexpected_reestablish(struct peer *peer, const u8 *msg) u64 next_revocation_number; struct secret your_last_per_commitment_secret; struct pubkey my_current_per_commitment_point; +#if EXPERIMENTAL_FEATURES + struct tlv_channel_reestablish_tlvs *tlvs = tlv_channel_reestablish_tlvs_new(tmpctx); +#endif if (!fromwire_channel_reestablish(msg, &channel_id, &next_commitment_number, &next_revocation_number, &your_last_per_commitment_secret, - &my_current_per_commitment_point)) + &my_current_per_commitment_point +#if EXPERIMENTAL_FEATURES + , tlvs +#endif + )) peer_failed_warn(peer->pps, &peer->channel_id, "Bad channel_reestablish %s", tal_hex(peer, msg)); @@ -2474,6 +2481,9 @@ static void peer_reconnect(struct peer *peer, struct secret last_local_per_commitment_secret; bool dataloss_protect, check_extra_fields; const u8 **premature_msgs = tal_arr(peer, const u8 *, 0); +#if EXPERIMENTAL_FEATURES + struct tlv_channel_reestablish_tlvs *send_tlvs, *recv_tlvs; +#endif dataloss_protect = feature_negotiated(peer->our_features, peer->their_features, @@ -2488,6 +2498,10 @@ static void peer_reconnect(struct peer *peer, get_per_commitment_point(peer->next_index[LOCAL] - 1, &my_current_per_commitment_point, NULL); +#if EXPERIMENTAL_FEATURES + send_tlvs = tlv_channel_reestablish_tlvs_new(tmpctx); +#endif + /* BOLT #2: * * - upon reconnection: @@ -2525,14 +2539,22 @@ static void peer_reconnect(struct peer *peer, peer->revocations_received, last_remote_per_commit_secret, /* Can send any (valid) point here */ - &peer->remote_per_commit); + &peer->remote_per_commit +#if EXPERIMENTAL_FEATURES + , send_tlvs +#endif + ); } else { msg = towire_channel_reestablish (NULL, &peer->channel_id, peer->next_index[LOCAL], peer->revocations_received, last_remote_per_commit_secret, - &my_current_per_commitment_point); + &my_current_per_commitment_point +#if EXPERIMENTAL_FEATURES + , send_tlvs +#endif + ); } sync_crypto_write(peer->pps, take(msg)); @@ -2552,12 +2574,20 @@ static void peer_reconnect(struct peer *peer, msg) || capture_premature_msg(&premature_msgs, msg)); +#if EXPERIMENTAL_FEATURES + recv_tlvs = tlv_channel_reestablish_tlvs_new(tmpctx); +#endif + if (!fromwire_channel_reestablish(msg, &channel_id, &next_commitment_number, &next_revocation_number, &last_local_per_commitment_secret, - &remote_current_per_commitment_point)) { + &remote_current_per_commitment_point +#if EXPERIMENTAL_FEATURES + , recv_tlvs +#endif + )) { peer_failed_warn(peer->pps, &peer->channel_id, "bad reestablish msg: %s %s", diff --git a/closingd/closingd.c b/closingd/closingd.c index 80c10adcaa87..1184b12a712a 100644 --- a/closingd/closingd.c +++ b/closingd/closingd.c @@ -176,6 +176,9 @@ static void do_reconnect(struct per_peer_state *pps, struct pubkey my_current_per_commitment_point, next_commitment_point; struct secret their_secret; struct tlv_shutdown_tlvs *tlvs; +#if EXPERIMENTAL_FEATURES + struct tlv_channel_reestablish_tlvs *reestablish_tlvs = tlv_channel_reestablish_tlvs_new(tmpctx); +#endif my_current_per_commitment_point = get_per_commitment_point(next_index[LOCAL]-1); @@ -201,7 +204,11 @@ static void do_reconnect(struct per_peer_state *pps, next_index[LOCAL], revocations_received, last_remote_per_commit_secret, - &my_current_per_commitment_point); + &my_current_per_commitment_point +#if EXPERIMENTAL_FEATURES + , reestablish_tlvs +#endif + ); sync_crypto_write(pps, take(msg)); /* They might have already sent reestablish, which triggered us */ @@ -217,11 +224,19 @@ static void do_reconnect(struct per_peer_state *pps, != WIRE_CHANNEL_REESTABLISH); } +#if EXPERIMENTAL_FEATURES + reestablish_tlvs = tlv_channel_reestablish_tlvs_new(tmpctx); +#endif + if (!fromwire_channel_reestablish(channel_reestablish, &their_channel_id, &next_local_commitment_number, &next_remote_revocation_number, &their_secret, - &next_commitment_point)) { + &next_commitment_point +#if EXPERIMENTAL_FEATURES + , reestablish_tlvs +#endif + )) { peer_failed_warn(pps, channel_id, "bad reestablish msg: %s %s", peer_wire_name(fromwire_peektype(channel_reestablish)), diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 5ebae60b291f..ed5f58300198 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -3164,6 +3164,9 @@ static void do_reconnect_dance(struct state *state) last_remote_per_commit_secret; struct pubkey remote_current_per_commit_point; struct tx_state *tx_state = state->tx_state; +#if EXPERIMENTAL_FEATURES + struct tlv_channel_reestablish_tlvs *tlvs = tlv_channel_reestablish_tlvs_new(tmpctx); +#endif /* BOLT #2: * - if `next_revocation_number` equals 0: @@ -3177,7 +3180,11 @@ static void do_reconnect_dance(struct state *state) msg = towire_channel_reestablish (NULL, &state->channel_id, 1, 0, &last_remote_per_commit_secret, - &state->first_per_commitment_point[LOCAL]); + &state->first_per_commitment_point[LOCAL] +#if EXPERIMENTAL_FEATURES + , tlvs +#endif + ); sync_crypto_write(state->pps, take(msg)); peer_billboard(false, "Sent reestablish, waiting for theirs"); @@ -3200,7 +3207,11 @@ static void do_reconnect_dance(struct state *state) &next_commitment_number, &next_revocation_number, &last_local_per_commit_secret, - &remote_current_per_commit_point)) + &remote_current_per_commit_point +#if EXPERIMENTAL_FEATURES + , tlvs +#endif + )) open_err_fatal(state, "Bad reestablish msg: %s %s", peer_wire_name(fromwire_peektype(msg)), tal_hex(msg, msg)); diff --git a/wire/extracted_peer_exp_upgradable.patch b/wire/extracted_peer_exp_upgradable.patch new file mode 100644 index 000000000000..db26af74680e --- /dev/null +++ b/wire/extracted_peer_exp_upgradable.patch @@ -0,0 +1,21 @@ +--- wire/peer_wire.csv 2021-05-09 15:44:59.166135652 +0930 ++++ wire/peer_wire.csv.raw 2021-05-11 09:59:31.695459756 +0930 +@@ -221,6 +131,18 @@ + msgdata,channel_reestablish,next_revocation_number,u64, + msgdata,channel_reestablish,your_last_per_commitment_secret,byte,32 + msgdata,channel_reestablish,my_current_per_commitment_point,point, ++msgdata,channel_reestablish,tlvs,channel_reestablish_tlvs, ++tlvtype,channel_reestablish_tlvs,next_to_send,1 ++tlvdata,channel_reestablish_tlvs,next_to_send,commitment_number,tu64, ++tlvtype,channel_reestablish_tlvs,desired_type,3 ++tlvdata,channel_reestablish_tlvs,desired_type,type,channel_type, ++tlvtype,channel_reestablish_tlvs,current_type,5 ++tlvdata,channel_reestablish_tlvs,current_type,type,channel_type, ++tlvtype,channel_reestablish_tlvs,upgradable,7 ++tlvdata,channel_reestablish_tlvs,upgradable,upgrades,channel_type,... ++subtype,channel_type ++subtypedata,channel_type,len,u16, ++subtypedata,channel_type,features,byte,len + msgtype,announcement_signatures,259 + msgdata,announcement_signatures,channel_id,channel_id, + msgdata,announcement_signatures,short_channel_id,short_channel_id, diff --git a/wire/peer_wire.c b/wire/peer_wire.c index 1f8fc3731306..afc60a2203bb 100644 --- a/wire/peer_wire.c +++ b/wire/peer_wire.c @@ -124,10 +124,17 @@ bool extract_channel_id(const u8 *in_pkt, struct channel_id *channel_id) struct bitcoin_blkid ignored_chainhash; struct secret ignored_secret; struct tlv_open_channel_tlvs *tlvs = tlv_open_channel_tlvs_new(tmpctx); +#if EXPERIMENTAL_FEATURES + struct tlv_channel_reestablish_tlvs *reestab_tlvs = tlv_channel_reestablish_tlvs_new(tmpctx); +#endif if (fromwire_channel_reestablish(in_pkt, channel_id, &ignored_u64, &ignored_u64, - &ignored_secret, &ignored_pubkey)) + &ignored_secret, &ignored_pubkey +#if EXPERIMENTAL_FEATURES + , reestab_tlvs +#endif + )) return true; if (fromwire_open_channel(in_pkt, &ignored_chainhash, channel_id, &ignored_sat, From 50e65aea74a48cc56ec30eae8bf492a4435185dd Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 4 Jun 2021 14:43:47 +0930 Subject: [PATCH 08/16] channeld: send next_to_send if EXPERIMENTAL_FEATURES Signed-off-by: Rusty Russell --- channeld/channeld.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/channeld/channeld.c b/channeld/channeld.c index 620b191b311a..025395067419 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -2500,6 +2500,12 @@ static void peer_reconnect(struct peer *peer, #if EXPERIMENTAL_FEATURES send_tlvs = tlv_channel_reestablish_tlvs_new(tmpctx); + /* BOLT-upgrade_protocol #2: + * A node sending `channel_reestablish`, if it supports upgrading channels: + * - MUST set `next_to_send` the commitment number of the next + * `commitment_signed` it expects to send. + */ + send_tlvs->next_to_send = tal_dup(send_tlvs, u64, &peer->next_index[REMOTE]); #endif /* BOLT #2: From 7136b25f484e7401802078d66ecc9556444fbc35 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 4 Jun 2021 14:43:47 +0930 Subject: [PATCH 09/16] channeld: send current features (EXPERIMENTAL_FEATURES) Signed-off-by: Rusty Russell --- channeld/channeld.c | 19 ++++++++++++ channeld/test/run-full_channel.c | 3 ++ common/initial_channel.c | 52 ++++++++++++++++++++++++++++++++ common/initial_channel.h | 9 ++++++ 4 files changed, 83 insertions(+) diff --git a/channeld/channeld.c b/channeld/channeld.c index 025395067419..93c1477ce34d 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -2506,6 +2506,25 @@ static void peer_reconnect(struct peer *peer, * `commitment_signed` it expects to send. */ send_tlvs->next_to_send = tal_dup(send_tlvs, u64, &peer->next_index[REMOTE]); + + /* BOLT-upgrade_protocol #2: + * - if it initiated the channel: + * - MUST set `desired_type` to the channel_type it wants for the + * channel. + */ + if (peer->channel->opener == LOCAL) + send_tlvs->desired_type = channel_type(send_tlvs, peer->channel); + else { + /* BOLT-upgrade_protocol #2: + * - otherwise: + * - MUST set `current_type` to the current channel_type of the + * channel. + * - MUST set `upgradable` to the channel types it could change + * to. + * - MAY not set `upgradable` if it would be empty. + */ + send_tlvs->current_type = channel_type(send_tlvs, peer->channel); + } #endif /* BOLT #2: diff --git a/channeld/test/run-full_channel.c b/channeld/test/run-full_channel.c index acee63ef097a..89eb791e758b 100644 --- a/channeld/test/run-full_channel.c +++ b/channeld/test/run-full_channel.c @@ -29,6 +29,9 @@ void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memt /* Generated stub for memleak_remove_htable */ void memleak_remove_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) { fprintf(stderr, "memleak_remove_htable called!\n"); abort(); } +/* Generated stub for set_feature_bit */ +void set_feature_bit(u8 **ptr UNNEEDED, u32 bit UNNEEDED) +{ fprintf(stderr, "set_feature_bit called!\n"); abort(); } /* Generated stub for status_failed */ void status_failed(enum status_failreason code UNNEEDED, const char *fmt UNNEEDED, ...) diff --git a/common/initial_channel.c b/common/initial_channel.c index fef91fb3ca70..9ca0da0df4fc 100644 --- a/common/initial_channel.c +++ b/common/initial_channel.c @@ -6,12 +6,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include struct channel *new_initial_channel(const tal_t *ctx, const struct channel_id *cid, @@ -136,6 +138,56 @@ u32 channel_feerate(const struct channel *channel, enum side side) return get_feerate(channel->fee_states, channel->opener, side); } +#if EXPERIMENTAL_FEATURES +/* BOLT-upgrade_protocol #2: + * Channel features are explicitly enumerated as `channel_type` bitfields, + * using odd features bits. The currently defined types are: + * - no features (no bits set) + * - `option_static_remotekey` (bit 13) + * - `option_anchor_outputs` and `option_static_remotekey` (bits 21 and 13) + * - `option_anchors_zero_fee_htlc_tx` and `option_static_remotekey` (bits 23 + * and 13) + */ +static struct channel_type *new_channel_type(const tal_t *ctx) +{ + struct channel_type *type = tal(ctx, struct channel_type); + + type->features = tal_arr(type, u8, 0); + return type; +} + +static struct channel_type *type_static_remotekey(const tal_t *ctx) +{ + struct channel_type *type = new_channel_type(ctx); + + set_feature_bit(&type->features, + OPTIONAL_FEATURE(OPT_STATIC_REMOTEKEY)); + return type; +} + +static struct channel_type *type_anchor_outputs(const tal_t *ctx) +{ + struct channel_type *type = new_channel_type(ctx); + + set_feature_bit(&type->features, + OPTIONAL_FEATURE(OPT_ANCHOR_OUTPUTS)); + set_feature_bit(&type->features, + OPTIONAL_FEATURE(OPT_STATIC_REMOTEKEY)); + return type; +} + +struct channel_type *channel_type(const tal_t *ctx, + const struct channel *channel) +{ + if (channel->option_anchor_outputs) + return type_anchor_outputs(ctx); + if (channel->option_static_remotekey) + return type_static_remotekey(ctx); + + return new_channel_type(ctx); +} +#endif /* EXPERIMENTAL_FEATURES */ + static char *fmt_channel_view(const tal_t *ctx, const struct channel_view *view) { return tal_fmt(ctx, "{ owed_local=%s," diff --git a/common/initial_channel.h b/common/initial_channel.h index a70649afed8f..788c33f71fda 100644 --- a/common/initial_channel.h +++ b/common/initial_channel.h @@ -140,4 +140,13 @@ struct bitcoin_tx *initial_channel_tx(const tal_t *ctx, */ u32 channel_feerate(const struct channel *channel, enum side side); +#if EXPERIMENTAL_FEATURES +/* BOLT-upgrade_protocol #2: + * Channel features are explicitly enumerated as `channel_type` bitfields, + * using odd features bits. + */ +struct channel_type *channel_type(const tal_t *ctx, + const struct channel *channel); +#endif /* EXPERIMENTAL_FEATURES */ + #endif /* LIGHTNING_COMMON_INITIAL_CHANNEL_H */ From 996511caa8afa07b09aed76ba62ef722bbdf4285 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 4 Jun 2021 14:43:47 +0930 Subject: [PATCH 10/16] channeld: send upgradable types, add logging (EXPERIMENTAL_FEATURES) For now the only upgrade possible is to enable option_static_remotekey. Signed-off-by: Rusty Russell --- channeld/channeld.c | 19 +++++++++++++++++++ common/initial_channel.c | 11 +++++++++++ common/initial_channel.h | 4 ++++ tests/test_connection.py | 16 ++++++++++++++++ 4 files changed, 50 insertions(+) diff --git a/channeld/channeld.c b/channeld/channeld.c index 93c1477ce34d..d453df2525d2 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -2524,6 +2524,8 @@ static void peer_reconnect(struct peer *peer, * - MAY not set `upgradable` if it would be empty. */ send_tlvs->current_type = channel_type(send_tlvs, peer->channel); + send_tlvs->upgradable = channel_upgradable_types(send_tlvs, + peer->channel); } #endif @@ -2780,6 +2782,23 @@ static void peer_reconnect(struct peer *peer, /* (If we had sent `closing_signed`, we'd be in closingd). */ maybe_send_shutdown(peer); +#if EXPERIMENTAL_FEATURES + if (recv_tlvs->desired_type) + status_debug("They sent desired_type [%s]", + fmt_featurebits(tmpctx, + recv_tlvs->desired_type->features)); + if (recv_tlvs->current_type) + status_debug("They sent current_type [%s]", + fmt_featurebits(tmpctx, + recv_tlvs->current_type->features)); + + for (size_t i = 0; i < tal_count(recv_tlvs->upgradable); i++) { + status_debug("They offered upgrade to [%s]", + fmt_featurebits(tmpctx, + recv_tlvs->upgradable[i]->features)); + } +#endif /* EXPERIMENTAL_FEATURES */ + /* Corner case: we didn't send shutdown before because update_add_htlc * pending, but now they're cleared by restart, and we're actually * complete. In that case, their `shutdown` will trigger us. */ diff --git a/common/initial_channel.c b/common/initial_channel.c index 9ca0da0df4fc..e62f49d93b9a 100644 --- a/common/initial_channel.c +++ b/common/initial_channel.c @@ -186,6 +186,17 @@ struct channel_type *channel_type(const tal_t *ctx, return new_channel_type(ctx); } + +struct channel_type **channel_upgradable_types(const tal_t *ctx, + const struct channel *channel) +{ + struct channel_type **arr = tal_arr(ctx, struct channel_type *, 0); + + if (!channel->option_static_remotekey) + tal_arr_expand(&arr, type_static_remotekey(arr)); + + return arr; +} #endif /* EXPERIMENTAL_FEATURES */ static char *fmt_channel_view(const tal_t *ctx, const struct channel_view *view) diff --git a/common/initial_channel.h b/common/initial_channel.h index 788c33f71fda..f756cd0b0a21 100644 --- a/common/initial_channel.h +++ b/common/initial_channel.h @@ -147,6 +147,10 @@ u32 channel_feerate(const struct channel *channel, enum side side); */ struct channel_type *channel_type(const tal_t *ctx, const struct channel *channel); + +/* What features can we upgrade? (Returns NULL if none). */ +struct channel_type **channel_upgradable_types(const tal_t *ctx, + const struct channel *channel); #endif /* EXPERIMENTAL_FEATURES */ #endif /* LIGHTNING_COMMON_INITIAL_CHANNEL_H */ diff --git a/tests/test_connection.py b/tests/test_connection.py index e2ede44dfe8a..89920f59dfc6 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -3478,6 +3478,22 @@ def test_openchannel_init_alternate(node_factory, executor): print("nothing to do") +@unittest.skipIf(not EXPERIMENTAL_FEATURES, "upgrade protocol not available") +@pytest.mark.developer("dev-force-features required") +def test_upgrade_statickey(node_factory, executor): + """l1 doesn't have option_static_remotekey, l2 offers it.""" + l1, l2 = node_factory.line_graph(2, opts=[{'may_reconnect': True, + 'dev-force-features': ["-13", "-21"]}, + {'may_reconnect': True}]) + + l1.rpc.disconnect(l2.info['id'], force=True) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + + l1.daemon.wait_for_logs([r"They sent current_type \[\]", + r"They offered upgrade to \[13\]"]) + l2.daemon.wait_for_log(r"They sent desired_type \[\]") + + @unittest.skipIf(not EXPERIMENTAL_FEATURES, "quiescence is experimental") @pytest.mark.developer("quiescence triggering is dev only") def test_quiescence(node_factory, executor): From 2cf0fbc24c65d678d8ac169eba25d9d29cc23851 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 4 Jun 2021 14:43:47 +0930 Subject: [PATCH 11/16] wallet: save thresholds for option_static_remotekey. Since we will soon be able to activate it on existing channels, we need to mark the threshold. Signed-off-by: Rusty Russell --- channeld/channeld.c | 3 + lightningd/channel.c | 9 +- lightningd/channel.h | 7 +- lightningd/channel_control.c | 8 +- lightningd/onchain_control.c | 6 +- lightningd/opening_control.c | 15 +- lightningd/peer_control.c | 2 +- wallet/db.c | 11 ++ wallet/db_postgres_sqlgen.c | 32 +++- wallet/db_sqlite3_sqlgen.c | 32 +++- wallet/statements_gettextgen.po | 250 +++++++++++++++++--------------- wallet/test/run-wallet.c | 4 +- wallet/wallet.c | 90 ++++++------ 13 files changed, 270 insertions(+), 199 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index d453df2525d2..f3ba9e201893 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -3353,6 +3353,9 @@ static void init_channel(struct peer *peer) master_badmsg(WIRE_CHANNELD_INIT, msg); } + status_debug("option_static_remotekey = %u, option_anchor_outputs = %u", + option_static_remotekey, option_anchor_outputs); + /* Keeping an array of pointers is better since it allows us to avoid * extra allocations later. */ peer->pbases = tal_arr(peer, struct penalty_base *, 0); diff --git a/lightningd/channel.c b/lightningd/channel.c index a6ef05ea51c0..074a058efb18 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -263,7 +263,8 @@ struct channel *new_unsaved_channel(struct peer *peer, * | Use v2 of channel open, enables dual funding * | IN9 * | `option_anchor_outputs` */ - channel->option_static_remotekey = true; + channel->static_remotekey_start[LOCAL] + = channel->static_remotekey_start[REMOTE] = 0; channel->option_anchor_outputs = true; channel->future_per_commitment_point = NULL; @@ -334,7 +335,8 @@ struct channel *new_channel(struct peer *peer, u64 dbid, u32 feerate_base, u32 feerate_ppm, const u8 *remote_upfront_shutdown_script, - bool option_static_remotekey, + u64 local_static_remotekey_start, + u64 remote_static_remotekey_start, bool option_anchor_outputs, enum side closer, enum state_change reason, @@ -423,7 +425,8 @@ struct channel *new_channel(struct peer *peer, u64 dbid, channel->feerate_ppm = feerate_ppm; channel->remote_upfront_shutdown_script = tal_steal(channel, remote_upfront_shutdown_script); - channel->option_static_remotekey = option_static_remotekey; + channel->static_remotekey_start[LOCAL] = local_static_remotekey_start; + channel->static_remotekey_start[REMOTE] = remote_static_remotekey_start; channel->option_anchor_outputs = option_anchor_outputs; channel->forgets = tal_arr(channel, struct command *, 0); diff --git a/lightningd/channel.h b/lightningd/channel.h index d04746450baf..0ea0ca451a12 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -188,8 +188,8 @@ struct channel { /* If they used option_upfront_shutdown_script. */ const u8 *remote_upfront_shutdown_script; - /* Was this negotiated with `option_static_remotekey? */ - bool option_static_remotekey; + /* At what commit numbers does `option_static_remotekey` apply? */ + u64 static_remotekey_start[NUM_SIDES]; /* Was this negotiated with `option_anchor_outputs? */ bool option_anchor_outputs; @@ -267,7 +267,8 @@ struct channel *new_channel(struct peer *peer, u64 dbid, u32 feerate_ppm, /* NULL or stolen */ const u8 *remote_upfront_shutdown_script STEALS, - bool option_static_remotekey, + u64 local_static_remotekey_start, + u64 remote_static_remotekey_start, bool option_anchor_outputs, enum side closer, enum state_change reason, diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index bf9f91cf52ff..51107817b6bf 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -275,12 +275,6 @@ void channel_fallen_behind(struct channel *channel, const u8 *msg) * use its presence as a flag so set it any valid key in that case. */ if (!channel->future_per_commitment_point) { struct pubkey *any = tal(channel, struct pubkey); - if (!channel->option_static_remotekey) { - channel_internal_error(channel, - "bad channel_fail_fallen_behind %s", - tal_hex(tmpctx, msg)); - return; - } if (!pubkey_from_node_id(any, &channel->peer->ld->id)) fatal("Our own id invalid?"); channel->future_per_commitment_point = any; @@ -608,7 +602,7 @@ void peer_start_channeld(struct channel *channel, remote_ann_bitcoin_sig, /* Set at channel open, even if not * negotiated now! */ - channel->option_static_remotekey, + channel->next_index[LOCAL] >= channel->static_remotekey_start[LOCAL], channel->option_anchor_outputs, IFDEV(ld->dev_fast_gossip, false), IFDEV(dev_fail_process_onionpacket, false), diff --git a/lightningd/onchain_control.c b/lightningd/onchain_control.c index fd6d8e7ea7d5..3c0ce0b73f2d 100644 --- a/lightningd/onchain_control.c +++ b/lightningd/onchain_control.c @@ -657,6 +657,9 @@ enum watch_result onchaind_funding_spent(struct channel *channel, } } + log_debug(channel->log, "channel->static_remotekey_start[LOCAL] %"PRIu64, + channel->static_remotekey_start[LOCAL]); + msg = towire_onchaind_init(channel, &channel->their_shachain.chain, chainparams, @@ -694,7 +697,8 @@ enum watch_result onchaind_funding_spent(struct channel *channel, channel->future_per_commitment_point, &channel->local_funding_pubkey, &channel->channel_info.remote_fundingkey, - channel->option_static_remotekey, + /* FIXME! onchaind needs start numbers! */ + channel->static_remotekey_start[LOCAL] == 0, channel->option_anchor_outputs, is_replay, feerate_min(ld, NULL)); diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 684c472b154e..7a1ffe91e7d6 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -103,7 +103,7 @@ wallet_commit_channel(struct lightningd *ld, struct amount_msat our_msat; struct amount_sat local_funding; s64 final_key_idx; - bool option_static_remotekey; + u64 static_remotekey_start; bool option_anchor_outputs; /* We cannot both be the fundee *and* have a `fundchannel_start` @@ -153,10 +153,13 @@ wallet_commit_channel(struct lightningd *ld, * transactions */ /* i.e. We set it now for the channel permanently. */ - option_static_remotekey - = feature_negotiated(ld->our_features, - uc->peer->their_features, - OPT_STATIC_REMOTEKEY); + if (feature_negotiated(ld->our_features, + uc->peer->their_features, + OPT_STATIC_REMOTEKEY)) + static_remotekey_start = 0; + else + static_remotekey_start = 0x7FFFFFFFFFFFFFFF; + option_anchor_outputs = feature_negotiated(ld->our_features, uc->peer->their_features, @@ -209,7 +212,7 @@ wallet_commit_channel(struct lightningd *ld, ld->config.fee_base, ld->config.fee_per_satoshi, remote_upfront_shutdown_script, - option_static_remotekey, + static_remotekey_start, static_remotekey_start, option_anchor_outputs, NUM_SIDES, /* closer not yet known */ uc->fc ? REASON_USER : REASON_REMOTE, diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 812e3f12168d..86d2c69993c5 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -848,7 +848,7 @@ static void json_add_channel(struct lightningd *ld, json_add_null(response, "closer"); json_array_start(response, "features"); - if (channel->option_static_remotekey) + if (channel->static_remotekey_start[LOCAL] != 0x7FFFFFFFFFFFFFFF) json_add_string(response, NULL, "option_static_remotekey"); if (channel->option_anchor_outputs) json_add_string(response, NULL, "option_anchor_outputs"); diff --git a/wallet/db.c b/wallet/db.c index 60e5b73396f6..be0fc74d42ff 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -717,6 +717,17 @@ static struct migration dbmigrations[] = { {SQL("ALTER TABLE channels ADD shutdown_wrong_txid BLOB DEFAULT NULL"), NULL}, {SQL("ALTER TABLE channels ADD shutdown_wrong_outnum INTEGER DEFAULT NULL"), NULL}, {NULL, migrate_inflight_last_tx_to_psbt}, + /* Channels can now change their type at specific commit indexes. */ + {SQL("ALTER TABLE channels ADD local_static_remotekey_start BIGINT DEFAULT 0"), + NULL}, + {SQL("ALTER TABLE channels ADD remote_static_remotekey_start BIGINT DEFAULT 0"), + NULL}, + /* Set counter past 2^48 if they don't have option */ + {SQL("UPDATE channels SET" + " remote_static_remotekey_start = 9223372036854775807," + " local_static_remotekey_start = 9223372036854775807" + " WHERE option_static_remotekey = 0"), + NULL}, }; /* Leak tracking. */ diff --git a/wallet/db_postgres_sqlgen.c b/wallet/db_postgres_sqlgen.c index 1e4899c67f3c..fdc08f9dd521 100644 --- a/wallet/db_postgres_sqlgen.c +++ b/wallet/db_postgres_sqlgen.c @@ -938,6 +938,24 @@ struct db_query db_postgres_queries[] = { .placeholders = 0, .readonly = false, }, + { + .name = "ALTER TABLE channels ADD local_static_remotekey_start BIGINT DEFAULT 0", + .query = "ALTER TABLE channels ADD local_static_remotekey_start BIGINT DEFAULT 0", + .placeholders = 0, + .readonly = false, + }, + { + .name = "ALTER TABLE channels ADD remote_static_remotekey_start BIGINT DEFAULT 0", + .query = "ALTER TABLE channels ADD remote_static_remotekey_start BIGINT DEFAULT 0", + .placeholders = 0, + .readonly = false, + }, + { + .name = "UPDATE channels SET remote_static_remotekey_start = 9223372036854775807, local_static_remotekey_start = 9223372036854775807 WHERE option_static_remotekey = 0", + .query = "UPDATE channels SET remote_static_remotekey_start = 9223372036854775807, local_static_remotekey_start = 9223372036854775807 WHERE option_static_remotekey = 0", + .placeholders = 0, + .readonly = false, + }, { .name = "UPDATE vars SET intval = intval + 1 WHERE name = 'data_version' AND intval = ?", .query = "UPDATE vars SET intval = intval + 1 WHERE name = 'data_version' AND intval = $1", @@ -1305,8 +1323,8 @@ struct db_query db_postgres_queries[] = { .readonly = true, }, { - .name = "SELECT id, peer_id, short_channel_id, full_channel_id, channel_config_local, channel_config_remote, state, funder, channel_flags, minimum_depth, next_index_local, next_index_remote, next_htlc_id, funding_tx_id, funding_tx_outnum, funding_satoshi, our_funding_satoshi, funding_locked_remote, push_msatoshi, msatoshi_local, fundingkey_remote, revocation_basepoint_remote, payment_basepoint_remote, htlc_basepoint_remote, delayed_payment_basepoint_remote, per_commit_remote, old_per_commit_remote, local_feerate_per_kw, remote_feerate_per_kw, shachain_remote_id, shutdown_scriptpubkey_remote, shutdown_keyidx_local, last_sent_commit_state, last_sent_commit_id, last_tx, last_sig, last_was_revoke, first_blocknum, min_possible_feerate, max_possible_feerate, msatoshi_to_us_min, msatoshi_to_us_max, future_per_commitment_point, last_sent_commit, feerate_base, feerate_ppm, remote_upfront_shutdown_script, option_static_remotekey, option_anchor_outputs, shutdown_scriptpubkey_local, closer, state_change_reason, revocation_basepoint_local, payment_basepoint_local, htlc_basepoint_local, delayed_payment_basepoint_local, funding_pubkey_local, shutdown_wrong_txid, shutdown_wrong_outnum FROM channels WHERE state != ?;", - .query = "SELECT id, peer_id, short_channel_id, full_channel_id, channel_config_local, channel_config_remote, state, funder, channel_flags, minimum_depth, next_index_local, next_index_remote, next_htlc_id, funding_tx_id, funding_tx_outnum, funding_satoshi, our_funding_satoshi, funding_locked_remote, push_msatoshi, msatoshi_local, fundingkey_remote, revocation_basepoint_remote, payment_basepoint_remote, htlc_basepoint_remote, delayed_payment_basepoint_remote, per_commit_remote, old_per_commit_remote, local_feerate_per_kw, remote_feerate_per_kw, shachain_remote_id, shutdown_scriptpubkey_remote, shutdown_keyidx_local, last_sent_commit_state, last_sent_commit_id, last_tx, last_sig, last_was_revoke, first_blocknum, min_possible_feerate, max_possible_feerate, msatoshi_to_us_min, msatoshi_to_us_max, future_per_commitment_point, last_sent_commit, feerate_base, feerate_ppm, remote_upfront_shutdown_script, option_static_remotekey, option_anchor_outputs, shutdown_scriptpubkey_local, closer, state_change_reason, revocation_basepoint_local, payment_basepoint_local, htlc_basepoint_local, delayed_payment_basepoint_local, funding_pubkey_local, shutdown_wrong_txid, shutdown_wrong_outnum FROM channels WHERE state != $1;", + .name = "SELECT id, peer_id, short_channel_id, full_channel_id, channel_config_local, channel_config_remote, state, funder, channel_flags, minimum_depth, next_index_local, next_index_remote, next_htlc_id, funding_tx_id, funding_tx_outnum, funding_satoshi, our_funding_satoshi, funding_locked_remote, push_msatoshi, msatoshi_local, fundingkey_remote, revocation_basepoint_remote, payment_basepoint_remote, htlc_basepoint_remote, delayed_payment_basepoint_remote, per_commit_remote, old_per_commit_remote, local_feerate_per_kw, remote_feerate_per_kw, shachain_remote_id, shutdown_scriptpubkey_remote, shutdown_keyidx_local, last_sent_commit_state, last_sent_commit_id, last_tx, last_sig, last_was_revoke, first_blocknum, min_possible_feerate, max_possible_feerate, msatoshi_to_us_min, msatoshi_to_us_max, future_per_commitment_point, last_sent_commit, feerate_base, feerate_ppm, remote_upfront_shutdown_script, local_static_remotekey_start, remote_static_remotekey_start, option_anchor_outputs, shutdown_scriptpubkey_local, closer, state_change_reason, revocation_basepoint_local, payment_basepoint_local, htlc_basepoint_local, delayed_payment_basepoint_local, funding_pubkey_local, shutdown_wrong_txid, shutdown_wrong_outnum FROM channels WHERE state != ?;", + .query = "SELECT id, peer_id, short_channel_id, full_channel_id, channel_config_local, channel_config_remote, state, funder, channel_flags, minimum_depth, next_index_local, next_index_remote, next_htlc_id, funding_tx_id, funding_tx_outnum, funding_satoshi, our_funding_satoshi, funding_locked_remote, push_msatoshi, msatoshi_local, fundingkey_remote, revocation_basepoint_remote, payment_basepoint_remote, htlc_basepoint_remote, delayed_payment_basepoint_remote, per_commit_remote, old_per_commit_remote, local_feerate_per_kw, remote_feerate_per_kw, shachain_remote_id, shutdown_scriptpubkey_remote, shutdown_keyidx_local, last_sent_commit_state, last_sent_commit_id, last_tx, last_sig, last_was_revoke, first_blocknum, min_possible_feerate, max_possible_feerate, msatoshi_to_us_min, msatoshi_to_us_max, future_per_commitment_point, last_sent_commit, feerate_base, feerate_ppm, remote_upfront_shutdown_script, local_static_remotekey_start, remote_static_remotekey_start, option_anchor_outputs, shutdown_scriptpubkey_local, closer, state_change_reason, revocation_basepoint_local, payment_basepoint_local, htlc_basepoint_local, delayed_payment_basepoint_local, funding_pubkey_local, shutdown_wrong_txid, shutdown_wrong_outnum FROM channels WHERE state != $1;", .placeholders = 1, .readonly = true, }, @@ -1371,9 +1389,9 @@ struct db_query db_postgres_queries[] = { .readonly = false, }, { - .name = "UPDATE channels SET shachain_remote_id=?, short_channel_id=?, full_channel_id=?, state=?, funder=?, channel_flags=?, minimum_depth=?, next_index_local=?, next_index_remote=?, next_htlc_id=?, funding_tx_id=?, funding_tx_outnum=?, funding_satoshi=?, our_funding_satoshi=?, funding_locked_remote=?, push_msatoshi=?, msatoshi_local=?, shutdown_scriptpubkey_remote=?, shutdown_keyidx_local=?, channel_config_local=?, last_tx=?, last_sig=?, last_was_revoke=?, min_possible_feerate=?, max_possible_feerate=?, msatoshi_to_us_min=?, msatoshi_to_us_max=?, feerate_base=?, feerate_ppm=?, remote_upfront_shutdown_script=?, option_static_remotekey=?, option_anchor_outputs=?, shutdown_scriptpubkey_local=?, closer=?, state_change_reason=?, shutdown_wrong_txid=?, shutdown_wrong_outnum=? WHERE id=?", - .query = "UPDATE channels SET shachain_remote_id=$1, short_channel_id=$2, full_channel_id=$3, state=$4, funder=$5, channel_flags=$6, minimum_depth=$7, next_index_local=$8, next_index_remote=$9, next_htlc_id=$10, funding_tx_id=$11, funding_tx_outnum=$12, funding_satoshi=$13, our_funding_satoshi=$14, funding_locked_remote=$15, push_msatoshi=$16, msatoshi_local=$17, shutdown_scriptpubkey_remote=$18, shutdown_keyidx_local=$19, channel_config_local=$20, last_tx=$21, last_sig=$22, last_was_revoke=$23, min_possible_feerate=$24, max_possible_feerate=$25, msatoshi_to_us_min=$26, msatoshi_to_us_max=$27, feerate_base=$28, feerate_ppm=$29, remote_upfront_shutdown_script=$30, option_static_remotekey=$31, option_anchor_outputs=$32, shutdown_scriptpubkey_local=$33, closer=$34, state_change_reason=$35, shutdown_wrong_txid=$36, shutdown_wrong_outnum=$37 WHERE id=$38", - .placeholders = 38, + .name = "UPDATE channels SET shachain_remote_id=?, short_channel_id=?, full_channel_id=?, state=?, funder=?, channel_flags=?, minimum_depth=?, next_index_local=?, next_index_remote=?, next_htlc_id=?, funding_tx_id=?, funding_tx_outnum=?, funding_satoshi=?, our_funding_satoshi=?, funding_locked_remote=?, push_msatoshi=?, msatoshi_local=?, shutdown_scriptpubkey_remote=?, shutdown_keyidx_local=?, channel_config_local=?, last_tx=?, last_sig=?, last_was_revoke=?, min_possible_feerate=?, max_possible_feerate=?, msatoshi_to_us_min=?, msatoshi_to_us_max=?, feerate_base=?, feerate_ppm=?, remote_upfront_shutdown_script=?, local_static_remotekey_start=?, remote_static_remotekey_start=?, option_anchor_outputs=?, shutdown_scriptpubkey_local=?, closer=?, state_change_reason=?, shutdown_wrong_txid=?, shutdown_wrong_outnum=? WHERE id=?", + .query = "UPDATE channels SET shachain_remote_id=$1, short_channel_id=$2, full_channel_id=$3, state=$4, funder=$5, channel_flags=$6, minimum_depth=$7, next_index_local=$8, next_index_remote=$9, next_htlc_id=$10, funding_tx_id=$11, funding_tx_outnum=$12, funding_satoshi=$13, our_funding_satoshi=$14, funding_locked_remote=$15, push_msatoshi=$16, msatoshi_local=$17, shutdown_scriptpubkey_remote=$18, shutdown_keyidx_local=$19, channel_config_local=$20, last_tx=$21, last_sig=$22, last_was_revoke=$23, min_possible_feerate=$24, max_possible_feerate=$25, msatoshi_to_us_min=$26, msatoshi_to_us_max=$27, feerate_base=$28, feerate_ppm=$29, remote_upfront_shutdown_script=$30, local_static_remotekey_start=$31, remote_static_remotekey_start=$32, option_anchor_outputs=$33, shutdown_scriptpubkey_local=$34, closer=$35, state_change_reason=$36, shutdown_wrong_txid=$37, shutdown_wrong_outnum=$38 WHERE id=$39", + .placeholders = 39, .readonly = false, }, { @@ -1900,10 +1918,10 @@ struct db_query db_postgres_queries[] = { }, }; -#define DB_POSTGRES_QUERY_COUNT 315 +#define DB_POSTGRES_QUERY_COUNT 318 #endif /* HAVE_POSTGRES */ #endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */ -// SHA256STAMP:2839b3ea02654d43cce04742850e4c42541818c1641ab5119f077d859a288e5a +// SHA256STAMP:8881af1d864eeb8541b44a9dbbd48b8be848146d60ef45011e91c6e3009e9c75 diff --git a/wallet/db_sqlite3_sqlgen.c b/wallet/db_sqlite3_sqlgen.c index 79582f04f224..be9d769fb831 100644 --- a/wallet/db_sqlite3_sqlgen.c +++ b/wallet/db_sqlite3_sqlgen.c @@ -938,6 +938,24 @@ struct db_query db_sqlite3_queries[] = { .placeholders = 0, .readonly = false, }, + { + .name = "ALTER TABLE channels ADD local_static_remotekey_start BIGINT DEFAULT 0", + .query = "ALTER TABLE channels ADD local_static_remotekey_start INTEGER DEFAULT 0", + .placeholders = 0, + .readonly = false, + }, + { + .name = "ALTER TABLE channels ADD remote_static_remotekey_start BIGINT DEFAULT 0", + .query = "ALTER TABLE channels ADD remote_static_remotekey_start INTEGER DEFAULT 0", + .placeholders = 0, + .readonly = false, + }, + { + .name = "UPDATE channels SET remote_static_remotekey_start = 9223372036854775807, local_static_remotekey_start = 9223372036854775807 WHERE option_static_remotekey = 0", + .query = "UPDATE channels SET remote_static_remotekey_start = 9223372036854775807, local_static_remotekey_start = 9223372036854775807 WHERE option_static_remotekey = 0", + .placeholders = 0, + .readonly = false, + }, { .name = "UPDATE vars SET intval = intval + 1 WHERE name = 'data_version' AND intval = ?", .query = "UPDATE vars SET intval = intval + 1 WHERE name = 'data_version' AND intval = ?", @@ -1305,8 +1323,8 @@ struct db_query db_sqlite3_queries[] = { .readonly = true, }, { - .name = "SELECT id, peer_id, short_channel_id, full_channel_id, channel_config_local, channel_config_remote, state, funder, channel_flags, minimum_depth, next_index_local, next_index_remote, next_htlc_id, funding_tx_id, funding_tx_outnum, funding_satoshi, our_funding_satoshi, funding_locked_remote, push_msatoshi, msatoshi_local, fundingkey_remote, revocation_basepoint_remote, payment_basepoint_remote, htlc_basepoint_remote, delayed_payment_basepoint_remote, per_commit_remote, old_per_commit_remote, local_feerate_per_kw, remote_feerate_per_kw, shachain_remote_id, shutdown_scriptpubkey_remote, shutdown_keyidx_local, last_sent_commit_state, last_sent_commit_id, last_tx, last_sig, last_was_revoke, first_blocknum, min_possible_feerate, max_possible_feerate, msatoshi_to_us_min, msatoshi_to_us_max, future_per_commitment_point, last_sent_commit, feerate_base, feerate_ppm, remote_upfront_shutdown_script, option_static_remotekey, option_anchor_outputs, shutdown_scriptpubkey_local, closer, state_change_reason, revocation_basepoint_local, payment_basepoint_local, htlc_basepoint_local, delayed_payment_basepoint_local, funding_pubkey_local, shutdown_wrong_txid, shutdown_wrong_outnum FROM channels WHERE state != ?;", - .query = "SELECT id, peer_id, short_channel_id, full_channel_id, channel_config_local, channel_config_remote, state, funder, channel_flags, minimum_depth, next_index_local, next_index_remote, next_htlc_id, funding_tx_id, funding_tx_outnum, funding_satoshi, our_funding_satoshi, funding_locked_remote, push_msatoshi, msatoshi_local, fundingkey_remote, revocation_basepoint_remote, payment_basepoint_remote, htlc_basepoint_remote, delayed_payment_basepoint_remote, per_commit_remote, old_per_commit_remote, local_feerate_per_kw, remote_feerate_per_kw, shachain_remote_id, shutdown_scriptpubkey_remote, shutdown_keyidx_local, last_sent_commit_state, last_sent_commit_id, last_tx, last_sig, last_was_revoke, first_blocknum, min_possible_feerate, max_possible_feerate, msatoshi_to_us_min, msatoshi_to_us_max, future_per_commitment_point, last_sent_commit, feerate_base, feerate_ppm, remote_upfront_shutdown_script, option_static_remotekey, option_anchor_outputs, shutdown_scriptpubkey_local, closer, state_change_reason, revocation_basepoint_local, payment_basepoint_local, htlc_basepoint_local, delayed_payment_basepoint_local, funding_pubkey_local, shutdown_wrong_txid, shutdown_wrong_outnum FROM channels WHERE state != ?;", + .name = "SELECT id, peer_id, short_channel_id, full_channel_id, channel_config_local, channel_config_remote, state, funder, channel_flags, minimum_depth, next_index_local, next_index_remote, next_htlc_id, funding_tx_id, funding_tx_outnum, funding_satoshi, our_funding_satoshi, funding_locked_remote, push_msatoshi, msatoshi_local, fundingkey_remote, revocation_basepoint_remote, payment_basepoint_remote, htlc_basepoint_remote, delayed_payment_basepoint_remote, per_commit_remote, old_per_commit_remote, local_feerate_per_kw, remote_feerate_per_kw, shachain_remote_id, shutdown_scriptpubkey_remote, shutdown_keyidx_local, last_sent_commit_state, last_sent_commit_id, last_tx, last_sig, last_was_revoke, first_blocknum, min_possible_feerate, max_possible_feerate, msatoshi_to_us_min, msatoshi_to_us_max, future_per_commitment_point, last_sent_commit, feerate_base, feerate_ppm, remote_upfront_shutdown_script, local_static_remotekey_start, remote_static_remotekey_start, option_anchor_outputs, shutdown_scriptpubkey_local, closer, state_change_reason, revocation_basepoint_local, payment_basepoint_local, htlc_basepoint_local, delayed_payment_basepoint_local, funding_pubkey_local, shutdown_wrong_txid, shutdown_wrong_outnum FROM channels WHERE state != ?;", + .query = "SELECT id, peer_id, short_channel_id, full_channel_id, channel_config_local, channel_config_remote, state, funder, channel_flags, minimum_depth, next_index_local, next_index_remote, next_htlc_id, funding_tx_id, funding_tx_outnum, funding_satoshi, our_funding_satoshi, funding_locked_remote, push_msatoshi, msatoshi_local, fundingkey_remote, revocation_basepoint_remote, payment_basepoint_remote, htlc_basepoint_remote, delayed_payment_basepoint_remote, per_commit_remote, old_per_commit_remote, local_feerate_per_kw, remote_feerate_per_kw, shachain_remote_id, shutdown_scriptpubkey_remote, shutdown_keyidx_local, last_sent_commit_state, last_sent_commit_id, last_tx, last_sig, last_was_revoke, first_blocknum, min_possible_feerate, max_possible_feerate, msatoshi_to_us_min, msatoshi_to_us_max, future_per_commitment_point, last_sent_commit, feerate_base, feerate_ppm, remote_upfront_shutdown_script, local_static_remotekey_start, remote_static_remotekey_start, option_anchor_outputs, shutdown_scriptpubkey_local, closer, state_change_reason, revocation_basepoint_local, payment_basepoint_local, htlc_basepoint_local, delayed_payment_basepoint_local, funding_pubkey_local, shutdown_wrong_txid, shutdown_wrong_outnum FROM channels WHERE state != ?;", .placeholders = 1, .readonly = true, }, @@ -1371,9 +1389,9 @@ struct db_query db_sqlite3_queries[] = { .readonly = false, }, { - .name = "UPDATE channels SET shachain_remote_id=?, short_channel_id=?, full_channel_id=?, state=?, funder=?, channel_flags=?, minimum_depth=?, next_index_local=?, next_index_remote=?, next_htlc_id=?, funding_tx_id=?, funding_tx_outnum=?, funding_satoshi=?, our_funding_satoshi=?, funding_locked_remote=?, push_msatoshi=?, msatoshi_local=?, shutdown_scriptpubkey_remote=?, shutdown_keyidx_local=?, channel_config_local=?, last_tx=?, last_sig=?, last_was_revoke=?, min_possible_feerate=?, max_possible_feerate=?, msatoshi_to_us_min=?, msatoshi_to_us_max=?, feerate_base=?, feerate_ppm=?, remote_upfront_shutdown_script=?, option_static_remotekey=?, option_anchor_outputs=?, shutdown_scriptpubkey_local=?, closer=?, state_change_reason=?, shutdown_wrong_txid=?, shutdown_wrong_outnum=? WHERE id=?", - .query = "UPDATE channels SET shachain_remote_id=?, short_channel_id=?, full_channel_id=?, state=?, funder=?, channel_flags=?, minimum_depth=?, next_index_local=?, next_index_remote=?, next_htlc_id=?, funding_tx_id=?, funding_tx_outnum=?, funding_satoshi=?, our_funding_satoshi=?, funding_locked_remote=?, push_msatoshi=?, msatoshi_local=?, shutdown_scriptpubkey_remote=?, shutdown_keyidx_local=?, channel_config_local=?, last_tx=?, last_sig=?, last_was_revoke=?, min_possible_feerate=?, max_possible_feerate=?, msatoshi_to_us_min=?, msatoshi_to_us_max=?, feerate_base=?, feerate_ppm=?, remote_upfront_shutdown_script=?, option_static_remotekey=?, option_anchor_outputs=?, shutdown_scriptpubkey_local=?, closer=?, state_change_reason=?, shutdown_wrong_txid=?, shutdown_wrong_outnum=? WHERE id=?", - .placeholders = 38, + .name = "UPDATE channels SET shachain_remote_id=?, short_channel_id=?, full_channel_id=?, state=?, funder=?, channel_flags=?, minimum_depth=?, next_index_local=?, next_index_remote=?, next_htlc_id=?, funding_tx_id=?, funding_tx_outnum=?, funding_satoshi=?, our_funding_satoshi=?, funding_locked_remote=?, push_msatoshi=?, msatoshi_local=?, shutdown_scriptpubkey_remote=?, shutdown_keyidx_local=?, channel_config_local=?, last_tx=?, last_sig=?, last_was_revoke=?, min_possible_feerate=?, max_possible_feerate=?, msatoshi_to_us_min=?, msatoshi_to_us_max=?, feerate_base=?, feerate_ppm=?, remote_upfront_shutdown_script=?, local_static_remotekey_start=?, remote_static_remotekey_start=?, option_anchor_outputs=?, shutdown_scriptpubkey_local=?, closer=?, state_change_reason=?, shutdown_wrong_txid=?, shutdown_wrong_outnum=? WHERE id=?", + .query = "UPDATE channels SET shachain_remote_id=?, short_channel_id=?, full_channel_id=?, state=?, funder=?, channel_flags=?, minimum_depth=?, next_index_local=?, next_index_remote=?, next_htlc_id=?, funding_tx_id=?, funding_tx_outnum=?, funding_satoshi=?, our_funding_satoshi=?, funding_locked_remote=?, push_msatoshi=?, msatoshi_local=?, shutdown_scriptpubkey_remote=?, shutdown_keyidx_local=?, channel_config_local=?, last_tx=?, last_sig=?, last_was_revoke=?, min_possible_feerate=?, max_possible_feerate=?, msatoshi_to_us_min=?, msatoshi_to_us_max=?, feerate_base=?, feerate_ppm=?, remote_upfront_shutdown_script=?, local_static_remotekey_start=?, remote_static_remotekey_start=?, option_anchor_outputs=?, shutdown_scriptpubkey_local=?, closer=?, state_change_reason=?, shutdown_wrong_txid=?, shutdown_wrong_outnum=? WHERE id=?", + .placeholders = 39, .readonly = false, }, { @@ -1900,10 +1918,10 @@ struct db_query db_sqlite3_queries[] = { }, }; -#define DB_SQLITE3_QUERY_COUNT 315 +#define DB_SQLITE3_QUERY_COUNT 318 #endif /* HAVE_SQLITE3 */ #endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */ -// SHA256STAMP:2839b3ea02654d43cce04742850e4c42541818c1641ab5119f077d859a288e5a +// SHA256STAMP:8881af1d864eeb8541b44a9dbbd48b8be848146d60ef45011e91c6e3009e9c75 diff --git a/wallet/statements_gettextgen.po b/wallet/statements_gettextgen.po index f41b5e86ab1b..0e9325b6037c 100644 --- a/wallet/statements_gettextgen.po +++ b/wallet/statements_gettextgen.po @@ -618,83 +618,95 @@ msgstr "" msgid "ALTER TABLE channels ADD shutdown_wrong_outnum INTEGER DEFAULT NULL" msgstr "" -#: wallet/db.c:946 +#: wallet/db.c:721 +msgid "ALTER TABLE channels ADD local_static_remotekey_start BIGINT DEFAULT 0" +msgstr "" + +#: wallet/db.c:723 +msgid "ALTER TABLE channels ADD remote_static_remotekey_start BIGINT DEFAULT 0" +msgstr "" + +#: wallet/db.c:726 +msgid "UPDATE channels SET remote_static_remotekey_start = 9223372036854775807, local_static_remotekey_start = 9223372036854775807 WHERE option_static_remotekey = 0" +msgstr "" + +#: wallet/db.c:957 msgid "UPDATE vars SET intval = intval + 1 WHERE name = 'data_version' AND intval = ?" msgstr "" -#: wallet/db.c:1046 +#: wallet/db.c:1057 msgid "SELECT version FROM version LIMIT 1" msgstr "" -#: wallet/db.c:1108 +#: wallet/db.c:1119 msgid "UPDATE version SET version=?;" msgstr "" -#: wallet/db.c:1116 +#: wallet/db.c:1127 msgid "INSERT INTO db_upgrades VALUES (?, ?);" msgstr "" -#: wallet/db.c:1128 +#: wallet/db.c:1139 msgid "SELECT intval FROM vars WHERE name = 'data_version'" msgstr "" -#: wallet/db.c:1155 +#: wallet/db.c:1166 msgid "SELECT intval FROM vars WHERE name= ? LIMIT 1" msgstr "" -#: wallet/db.c:1171 +#: wallet/db.c:1182 msgid "UPDATE vars SET intval=? WHERE name=?;" msgstr "" -#: wallet/db.c:1180 +#: wallet/db.c:1191 msgid "INSERT INTO vars (name, intval) VALUES (?, ?);" msgstr "" -#: wallet/db.c:1194 +#: wallet/db.c:1205 msgid "UPDATE channels SET feerate_base = ?, feerate_ppm = ?;" msgstr "" -#: wallet/db.c:1215 +#: wallet/db.c:1226 msgid "UPDATE channels SET our_funding_satoshi = funding_satoshi WHERE funder = 0;" msgstr "" -#: wallet/db.c:1231 +#: wallet/db.c:1242 msgid "SELECT type, keyindex, prev_out_tx, prev_out_index, channel_id, peer_id, commitment_point FROM outputs WHERE scriptpubkey IS NULL;" msgstr "" -#: wallet/db.c:1293 +#: wallet/db.c:1304 msgid "UPDATE outputs SET scriptpubkey = ? WHERE prev_out_tx = ? AND prev_out_index = ?" msgstr "" -#: wallet/db.c:1318 +#: wallet/db.c:1329 msgid "SELECT id, funding_tx_id, funding_tx_outnum FROM channels;" msgstr "" -#: wallet/db.c:1337 +#: wallet/db.c:1348 msgid "UPDATE channels SET full_channel_id = ? WHERE id = ?;" msgstr "" -#: wallet/db.c:1358 +#: wallet/db.c:1369 msgid "SELECT channels.id, peers.node_id FROM channels JOIN peers ON (peers.id = channels.peer_id)" msgstr "" -#: wallet/db.c:1391 +#: wallet/db.c:1402 msgid "UPDATE channels SET revocation_basepoint_local = ?, payment_basepoint_local = ?, htlc_basepoint_local = ?, delayed_payment_basepoint_local = ?, funding_pubkey_local = ? WHERE id = ?;" msgstr "" -#: wallet/db.c:1417 +#: wallet/db.c:1428 msgid "SELECT c.id, p.node_id, c.fundingkey_remote, inflight.last_tx, inflight.last_sig, inflight.funding_satoshi, inflight.funding_tx_id FROM channels c LEFT OUTER JOIN peers p ON p.id = c.peer_id LEFT OUTER JOIN channel_funding_inflights inflight ON c.id = inflight.channel_id WHERE inflight.last_tx IS NOT NULL;" msgstr "" -#: wallet/db.c:1484 +#: wallet/db.c:1495 msgid "UPDATE channel_funding_inflights SET last_tx = ? WHERE channel_id = ? AND funding_tx_id = ?;" msgstr "" -#: wallet/db.c:1508 +#: wallet/db.c:1519 msgid "SELECT c.id, p.node_id, c.last_tx, c.funding_satoshi, c.fundingkey_remote, c.last_sig FROM channels c LEFT OUTER JOIN peers p ON p.id = c.peer_id;" msgstr "" -#: wallet/db.c:1575 +#: wallet/db.c:1586 msgid "UPDATE channels SET last_tx = ? WHERE id = ?;" msgstr "" @@ -858,387 +870,387 @@ msgstr "" msgid "SELECT funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, funding_tx_remote_sigs_received FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate" msgstr "" -#: wallet/wallet.c:1308 +#: wallet/wallet.c:1309 msgid "SELECT id FROM channels ORDER BY id DESC LIMIT 1;" msgstr "" -#: wallet/wallet.c:1325 -msgid "SELECT id, peer_id, short_channel_id, full_channel_id, channel_config_local, channel_config_remote, state, funder, channel_flags, minimum_depth, next_index_local, next_index_remote, next_htlc_id, funding_tx_id, funding_tx_outnum, funding_satoshi, our_funding_satoshi, funding_locked_remote, push_msatoshi, msatoshi_local, fundingkey_remote, revocation_basepoint_remote, payment_basepoint_remote, htlc_basepoint_remote, delayed_payment_basepoint_remote, per_commit_remote, old_per_commit_remote, local_feerate_per_kw, remote_feerate_per_kw, shachain_remote_id, shutdown_scriptpubkey_remote, shutdown_keyidx_local, last_sent_commit_state, last_sent_commit_id, last_tx, last_sig, last_was_revoke, first_blocknum, min_possible_feerate, max_possible_feerate, msatoshi_to_us_min, msatoshi_to_us_max, future_per_commitment_point, last_sent_commit, feerate_base, feerate_ppm, remote_upfront_shutdown_script, option_static_remotekey, option_anchor_outputs, shutdown_scriptpubkey_local, closer, state_change_reason, revocation_basepoint_local, payment_basepoint_local, htlc_basepoint_local, delayed_payment_basepoint_local, funding_pubkey_local, shutdown_wrong_txid, shutdown_wrong_outnum FROM channels WHERE state != ?;" +#: wallet/wallet.c:1326 +msgid "SELECT id, peer_id, short_channel_id, full_channel_id, channel_config_local, channel_config_remote, state, funder, channel_flags, minimum_depth, next_index_local, next_index_remote, next_htlc_id, funding_tx_id, funding_tx_outnum, funding_satoshi, our_funding_satoshi, funding_locked_remote, push_msatoshi, msatoshi_local, fundingkey_remote, revocation_basepoint_remote, payment_basepoint_remote, htlc_basepoint_remote, delayed_payment_basepoint_remote, per_commit_remote, old_per_commit_remote, local_feerate_per_kw, remote_feerate_per_kw, shachain_remote_id, shutdown_scriptpubkey_remote, shutdown_keyidx_local, last_sent_commit_state, last_sent_commit_id, last_tx, last_sig, last_was_revoke, first_blocknum, min_possible_feerate, max_possible_feerate, msatoshi_to_us_min, msatoshi_to_us_max, future_per_commitment_point, last_sent_commit, feerate_base, feerate_ppm, remote_upfront_shutdown_script, local_static_remotekey_start, remote_static_remotekey_start, option_anchor_outputs, shutdown_scriptpubkey_local, closer, state_change_reason, revocation_basepoint_local, payment_basepoint_local, htlc_basepoint_local, delayed_payment_basepoint_local, funding_pubkey_local, shutdown_wrong_txid, shutdown_wrong_outnum FROM channels WHERE state != ?;" msgstr "" -#: wallet/wallet.c:1432 +#: wallet/wallet.c:1434 msgid "UPDATE channels SET in_payments_offered = COALESCE(in_payments_offered, 0) + 1 , in_msatoshi_offered = COALESCE(in_msatoshi_offered, 0) + ? WHERE id = ?;" msgstr "" -#: wallet/wallet.c:1438 +#: wallet/wallet.c:1440 msgid "UPDATE channels SET in_payments_fulfilled = COALESCE(in_payments_fulfilled, 0) + 1 , in_msatoshi_fulfilled = COALESCE(in_msatoshi_fulfilled, 0) + ? WHERE id = ?;" msgstr "" -#: wallet/wallet.c:1444 +#: wallet/wallet.c:1446 msgid "UPDATE channels SET out_payments_offered = COALESCE(out_payments_offered, 0) + 1 , out_msatoshi_offered = COALESCE(out_msatoshi_offered, 0) + ? WHERE id = ?;" msgstr "" -#: wallet/wallet.c:1450 +#: wallet/wallet.c:1452 msgid "UPDATE channels SET out_payments_fulfilled = COALESCE(out_payments_fulfilled, 0) + 1 , out_msatoshi_fulfilled = COALESCE(out_msatoshi_fulfilled, 0) + ? WHERE id = ?;" msgstr "" -#: wallet/wallet.c:1495 +#: wallet/wallet.c:1497 msgid "SELECT in_payments_offered, in_payments_fulfilled, in_msatoshi_offered, in_msatoshi_fulfilled, out_payments_offered, out_payments_fulfilled, out_msatoshi_offered, out_msatoshi_fulfilled FROM channels WHERE id = ?" msgstr "" -#: wallet/wallet.c:1524 +#: wallet/wallet.c:1526 msgid "SELECT MIN(height), MAX(height) FROM blocks;" msgstr "" -#: wallet/wallet.c:1546 +#: wallet/wallet.c:1548 msgid "INSERT INTO channel_configs DEFAULT VALUES;" msgstr "" -#: wallet/wallet.c:1558 +#: wallet/wallet.c:1560 msgid "UPDATE channel_configs SET dust_limit_satoshis=?, max_htlc_value_in_flight_msat=?, channel_reserve_satoshis=?, htlc_minimum_msat=?, to_self_delay=?, max_accepted_htlcs=? WHERE id=?;" msgstr "" -#: wallet/wallet.c:1582 +#: wallet/wallet.c:1584 msgid "SELECT id, dust_limit_satoshis, max_htlc_value_in_flight_msat, channel_reserve_satoshis, htlc_minimum_msat, to_self_delay, max_accepted_htlcs FROM channel_configs WHERE id= ? ;" msgstr "" -#: wallet/wallet.c:1616 +#: wallet/wallet.c:1618 msgid "UPDATE channels SET remote_ann_node_sig=?, remote_ann_bitcoin_sig=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1635 -msgid "UPDATE channels SET shachain_remote_id=?, short_channel_id=?, full_channel_id=?, state=?, funder=?, channel_flags=?, minimum_depth=?, next_index_local=?, next_index_remote=?, next_htlc_id=?, funding_tx_id=?, funding_tx_outnum=?, funding_satoshi=?, our_funding_satoshi=?, funding_locked_remote=?, push_msatoshi=?, msatoshi_local=?, shutdown_scriptpubkey_remote=?, shutdown_keyidx_local=?, channel_config_local=?, last_tx=?, last_sig=?, last_was_revoke=?, min_possible_feerate=?, max_possible_feerate=?, msatoshi_to_us_min=?, msatoshi_to_us_max=?, feerate_base=?, feerate_ppm=?, remote_upfront_shutdown_script=?, option_static_remotekey=?, option_anchor_outputs=?, shutdown_scriptpubkey_local=?, closer=?, state_change_reason=?, shutdown_wrong_txid=?, shutdown_wrong_outnum=? WHERE id=?" +#: wallet/wallet.c:1637 +msgid "UPDATE channels SET shachain_remote_id=?, short_channel_id=?, full_channel_id=?, state=?, funder=?, channel_flags=?, minimum_depth=?, next_index_local=?, next_index_remote=?, next_htlc_id=?, funding_tx_id=?, funding_tx_outnum=?, funding_satoshi=?, our_funding_satoshi=?, funding_locked_remote=?, push_msatoshi=?, msatoshi_local=?, shutdown_scriptpubkey_remote=?, shutdown_keyidx_local=?, channel_config_local=?, last_tx=?, last_sig=?, last_was_revoke=?, min_possible_feerate=?, max_possible_feerate=?, msatoshi_to_us_min=?, msatoshi_to_us_max=?, feerate_base=?, feerate_ppm=?, remote_upfront_shutdown_script=?, local_static_remotekey_start=?, remote_static_remotekey_start=?, option_anchor_outputs=?, shutdown_scriptpubkey_local=?, closer=?, state_change_reason=?, shutdown_wrong_txid=?, shutdown_wrong_outnum=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1727 +#: wallet/wallet.c:1731 msgid "UPDATE channels SET fundingkey_remote=?, revocation_basepoint_remote=?, payment_basepoint_remote=?, htlc_basepoint_remote=?, delayed_payment_basepoint_remote=?, per_commit_remote=?, old_per_commit_remote=?, channel_config_remote=?, future_per_commitment_point=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1754 +#: wallet/wallet.c:1758 msgid "DELETE FROM channel_feerates WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:1764 +#: wallet/wallet.c:1768 msgid "INSERT INTO channel_feerates VALUES(?, ?, ?)" msgstr "" -#: wallet/wallet.c:1781 +#: wallet/wallet.c:1785 msgid "UPDATE channels SET last_sent_commit=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1804 +#: wallet/wallet.c:1808 msgid "INSERT INTO channel_state_changes ( channel_id, timestamp, old_state, new_state, cause, message) VALUES (?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:1832 +#: wallet/wallet.c:1836 msgid "SELECT timestamp, old_state, new_state, cause, message FROM channel_state_changes WHERE channel_id = ? ORDER BY timestamp ASC;" msgstr "" -#: wallet/wallet.c:1861 +#: wallet/wallet.c:1865 msgid "SELECT id FROM peers WHERE node_id = ?" msgstr "" -#: wallet/wallet.c:1873 +#: wallet/wallet.c:1877 msgid "UPDATE peers SET address = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:1882 +#: wallet/wallet.c:1886 msgid "INSERT INTO peers (node_id, address) VALUES (?, ?);" msgstr "" -#: wallet/wallet.c:1903 +#: wallet/wallet.c:1907 msgid "INSERT INTO channels ( peer_id, first_blocknum, id, revocation_basepoint_local, payment_basepoint_local, htlc_basepoint_local, delayed_payment_basepoint_local, funding_pubkey_local) VALUES (?, ?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:1944 +#: wallet/wallet.c:1948 msgid "DELETE FROM channel_htlcs WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:1950 +#: wallet/wallet.c:1954 msgid "DELETE FROM htlc_sigs WHERE channelid=?" msgstr "" -#: wallet/wallet.c:1956 +#: wallet/wallet.c:1960 msgid "DELETE FROM channeltxs WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:1963 +#: wallet/wallet.c:1967 msgid "DELETE FROM channel_funding_inflights WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:1969 +#: wallet/wallet.c:1973 msgid "DELETE FROM shachains WHERE id IN ( SELECT shachain_remote_id FROM channels WHERE channels.id=?)" msgstr "" -#: wallet/wallet.c:1979 +#: wallet/wallet.c:1983 msgid "UPDATE channels SET state=?, peer_id=? WHERE channels.id=?" msgstr "" -#: wallet/wallet.c:1993 +#: wallet/wallet.c:1997 msgid "SELECT * FROM channels WHERE peer_id = ?;" msgstr "" -#: wallet/wallet.c:2001 +#: wallet/wallet.c:2005 msgid "DELETE FROM peers WHERE id=?" msgstr "" -#: wallet/wallet.c:2012 +#: wallet/wallet.c:2016 msgid "UPDATE outputs SET confirmation_height = ? WHERE prev_out_tx = ?" msgstr "" -#: wallet/wallet.c:2115 +#: wallet/wallet.c:2119 msgid "INSERT INTO channel_htlcs ( channel_id, channel_htlc_id, direction, msatoshi, cltv_expiry, payment_hash, payment_key, hstate, shared_secret, routing_onion, received_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:2168 +#: wallet/wallet.c:2172 msgid "INSERT INTO channel_htlcs ( channel_id, channel_htlc_id, direction, origin_htlc, msatoshi, cltv_expiry, payment_hash, payment_key, hstate, routing_onion, malformed_onion, partid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?);" msgstr "" -#: wallet/wallet.c:2229 +#: wallet/wallet.c:2233 msgid "UPDATE channel_htlcs SET hstate=?, payment_key=?, malformed_onion=?, failuremsg=?, localfailmsg=?, we_filled=? WHERE id=?" msgstr "" -#: wallet/wallet.c:2445 +#: wallet/wallet.c:2449 msgid "SELECT id, channel_htlc_id, msatoshi, cltv_expiry, hstate, payment_hash, payment_key, routing_onion, failuremsg, malformed_onion, origin_htlc, shared_secret, received_time, we_filled FROM channel_htlcs WHERE direction= ? AND channel_id= ? AND hstate != ?" msgstr "" -#: wallet/wallet.c:2492 +#: wallet/wallet.c:2496 msgid "SELECT id, channel_htlc_id, msatoshi, cltv_expiry, hstate, payment_hash, payment_key, routing_onion, failuremsg, malformed_onion, origin_htlc, shared_secret, received_time, partid, localfailmsg FROM channel_htlcs WHERE direction = ? AND channel_id = ? AND hstate != ?" msgstr "" -#: wallet/wallet.c:2623 +#: wallet/wallet.c:2627 msgid "SELECT channel_id, direction, cltv_expiry, channel_htlc_id, payment_hash FROM channel_htlcs WHERE channel_id = ?;" msgstr "" -#: wallet/wallet.c:2657 +#: wallet/wallet.c:2661 msgid "DELETE FROM channel_htlcs WHERE direction = ? AND origin_htlc = ? AND payment_hash = ? AND partid = ?;" msgstr "" -#: wallet/wallet.c:2710 +#: wallet/wallet.c:2714 msgid "SELECT status FROM payments WHERE payment_hash=? AND partid = ?;" msgstr "" -#: wallet/wallet.c:2728 +#: wallet/wallet.c:2732 msgid "INSERT INTO payments ( status, payment_hash, destination, msatoshi, timestamp, path_secrets, route_nodes, route_channels, msatoshi_sent, description, bolt11, total_msat, partid, local_offer_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:2817 +#: wallet/wallet.c:2821 msgid "DELETE FROM payments WHERE payment_hash = ? AND partid = ?" msgstr "" -#: wallet/wallet.c:2831 +#: wallet/wallet.c:2835 msgid "DELETE FROM payments WHERE payment_hash = ?" msgstr "" -#: wallet/wallet.c:2932 +#: wallet/wallet.c:2936 msgid "SELECT id, status, destination, msatoshi, payment_hash, timestamp, payment_preimage, path_secrets, route_nodes, route_channels, msatoshi_sent, description, bolt11, failonionreply, total_msat, partid, local_offer_id FROM payments WHERE payment_hash = ? AND partid = ?" msgstr "" -#: wallet/wallet.c:2982 +#: wallet/wallet.c:2986 msgid "UPDATE payments SET status=? WHERE payment_hash=? AND partid=?" msgstr "" -#: wallet/wallet.c:2992 +#: wallet/wallet.c:2996 msgid "UPDATE payments SET payment_preimage=? WHERE payment_hash=? AND partid=?" msgstr "" -#: wallet/wallet.c:3002 +#: wallet/wallet.c:3006 msgid "UPDATE payments SET path_secrets = NULL , route_nodes = NULL , route_channels = NULL WHERE payment_hash = ? AND partid = ?;" msgstr "" -#: wallet/wallet.c:3034 +#: wallet/wallet.c:3038 msgid "SELECT failonionreply, faildestperm, failindex, failcode, failnode, failchannel, failupdate, faildetail, faildirection FROM payments WHERE payment_hash=? AND partid=?;" msgstr "" -#: wallet/wallet.c:3101 +#: wallet/wallet.c:3105 msgid "UPDATE payments SET failonionreply=? , faildestperm=? , failindex=? , failcode=? , failnode=? , failchannel=? , failupdate=? , faildetail=? , faildirection=? WHERE payment_hash=? AND partid=?;" msgstr "" -#: wallet/wallet.c:3160 +#: wallet/wallet.c:3164 msgid "SELECT id, status, destination, msatoshi, payment_hash, timestamp, payment_preimage, path_secrets, route_nodes, route_channels, msatoshi_sent, description, bolt11, failonionreply, total_msat, partid, local_offer_id FROM payments WHERE payment_hash = ? ORDER BY id;" msgstr "" -#: wallet/wallet.c:3183 +#: wallet/wallet.c:3187 msgid "SELECT id, status, destination, msatoshi, payment_hash, timestamp, payment_preimage, path_secrets, route_nodes, route_channels, msatoshi_sent, description, bolt11, failonionreply, total_msat, partid, local_offer_id FROM payments ORDER BY id;" msgstr "" -#: wallet/wallet.c:3234 +#: wallet/wallet.c:3238 msgid "SELECT id, status, destination, msatoshi, payment_hash, timestamp, payment_preimage, path_secrets, route_nodes, route_channels, msatoshi_sent, description, bolt11, failonionreply, total_msat, partid, local_offer_id FROM payments WHERE local_offer_id = ?;" msgstr "" -#: wallet/wallet.c:3279 +#: wallet/wallet.c:3283 msgid "DELETE FROM htlc_sigs WHERE channelid = ?" msgstr "" -#: wallet/wallet.c:3286 +#: wallet/wallet.c:3290 msgid "INSERT INTO htlc_sigs (channelid, signature) VALUES (?, ?)" msgstr "" -#: wallet/wallet.c:3298 +#: wallet/wallet.c:3302 msgid "SELECT blobval FROM vars WHERE name='genesis_hash'" msgstr "" -#: wallet/wallet.c:3322 +#: wallet/wallet.c:3326 msgid "INSERT INTO vars (name, blobval) VALUES ('genesis_hash', ?);" msgstr "" -#: wallet/wallet.c:3340 +#: wallet/wallet.c:3344 msgid "SELECT txid, outnum FROM utxoset WHERE spendheight < ?" msgstr "" -#: wallet/wallet.c:3352 +#: wallet/wallet.c:3356 msgid "DELETE FROM utxoset WHERE spendheight < ?" msgstr "" -#: wallet/wallet.c:3360 wallet/wallet.c:3474 +#: wallet/wallet.c:3364 wallet/wallet.c:3478 msgid "INSERT INTO blocks (height, hash, prev_hash) VALUES (?, ?, ?);" msgstr "" -#: wallet/wallet.c:3379 +#: wallet/wallet.c:3383 msgid "DELETE FROM blocks WHERE hash = ?" msgstr "" -#: wallet/wallet.c:3385 +#: wallet/wallet.c:3389 msgid "SELECT * FROM blocks WHERE height >= ?;" msgstr "" -#: wallet/wallet.c:3394 +#: wallet/wallet.c:3398 msgid "DELETE FROM blocks WHERE height > ?" msgstr "" -#: wallet/wallet.c:3406 +#: wallet/wallet.c:3410 msgid "UPDATE outputs SET spend_height = ?, status = ? WHERE prev_out_tx = ? AND prev_out_index = ?" msgstr "" -#: wallet/wallet.c:3424 +#: wallet/wallet.c:3428 msgid "UPDATE utxoset SET spendheight = ? WHERE txid = ? AND outnum = ?" msgstr "" -#: wallet/wallet.c:3447 wallet/wallet.c:3485 +#: wallet/wallet.c:3451 wallet/wallet.c:3489 msgid "INSERT INTO utxoset ( txid, outnum, blockheight, spendheight, txindex, scriptpubkey, satoshis) VALUES(?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3511 +#: wallet/wallet.c:3515 msgid "SELECT height FROM blocks WHERE height = ?" msgstr "" -#: wallet/wallet.c:3524 +#: wallet/wallet.c:3528 msgid "SELECT txid, spendheight, scriptpubkey, satoshis FROM utxoset WHERE blockheight = ? AND txindex = ? AND outnum = ? AND spendheight IS NULL" msgstr "" -#: wallet/wallet.c:3566 +#: wallet/wallet.c:3570 msgid "SELECT blockheight, txindex, outnum FROM utxoset WHERE spendheight = ?" msgstr "" -#: wallet/wallet.c:3597 wallet/wallet.c:3757 +#: wallet/wallet.c:3601 wallet/wallet.c:3761 msgid "SELECT blockheight FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3607 +#: wallet/wallet.c:3611 msgid "INSERT INTO transactions ( id, blockheight, txindex, rawtx) VALUES (?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3628 +#: wallet/wallet.c:3632 msgid "UPDATE transactions SET blockheight = ?, txindex = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:3645 +#: wallet/wallet.c:3649 msgid "INSERT INTO transaction_annotations (txid, idx, location, type, channel) VALUES (?, ?, ?, ?, ?) ON CONFLICT(txid,idx) DO NOTHING;" msgstr "" -#: wallet/wallet.c:3677 +#: wallet/wallet.c:3681 msgid "SELECT type, channel_id FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3693 +#: wallet/wallet.c:3697 msgid "UPDATE transactions SET type = ?, channel_id = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:3712 +#: wallet/wallet.c:3716 msgid "SELECT type FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3735 +#: wallet/wallet.c:3739 msgid "SELECT rawtx FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3781 +#: wallet/wallet.c:3785 msgid "SELECT blockheight, txindex FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3809 +#: wallet/wallet.c:3813 msgid "SELECT id FROM transactions WHERE blockheight=?" msgstr "" -#: wallet/wallet.c:3828 +#: wallet/wallet.c:3832 msgid "INSERT INTO channeltxs ( channel_id, type, transaction_id, input_num, blockheight) VALUES (?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3852 +#: wallet/wallet.c:3856 msgid "SELECT DISTINCT(channel_id) FROM channeltxs WHERE type = ?;" msgstr "" -#: wallet/wallet.c:3873 +#: wallet/wallet.c:3877 msgid "SELECT c.type, c.blockheight, t.rawtx, c.input_num, c.blockheight - t.blockheight + 1 AS depth, t.id as txid FROM channeltxs c JOIN transactions t ON t.id = c.transaction_id WHERE c.channel_id = ? ORDER BY c.id ASC;" msgstr "" -#: wallet/wallet.c:3918 +#: wallet/wallet.c:3922 msgid "UPDATE forwarded_payments SET in_msatoshi=?, out_msatoshi=?, state=?, resolved_time=?, failcode=? WHERE in_htlc_id=?" msgstr "" -#: wallet/wallet.c:3976 +#: wallet/wallet.c:3980 msgid "INSERT INTO forwarded_payments ( in_htlc_id, out_htlc_id, in_channel_scid, out_channel_scid, in_msatoshi, out_msatoshi, state, received_time, resolved_time, failcode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:4035 +#: wallet/wallet.c:4039 msgid "SELECT CAST(COALESCE(SUM(in_msatoshi - out_msatoshi), 0) AS BIGINT)FROM forwarded_payments WHERE state = ?;" msgstr "" -#: wallet/wallet.c:4084 +#: wallet/wallet.c:4088 msgid "SELECT f.state, in_msatoshi, out_msatoshi, hin.payment_hash as payment_hash, in_channel_scid, out_channel_scid, f.received_time, f.resolved_time, f.failcode FROM forwarded_payments f LEFT JOIN channel_htlcs hin ON (f.in_htlc_id = hin.id) WHERE (1 = ? OR f.state = ?) AND (1 = ? OR f.in_channel_scid = ?) AND (1 = ? OR f.out_channel_scid = ?)" msgstr "" -#: wallet/wallet.c:4206 +#: wallet/wallet.c:4210 msgid "SELECT t.id, t.rawtx, t.blockheight, t.txindex, t.type as txtype, c2.short_channel_id as txchan, a.location, a.idx as ann_idx, a.type as annotation_type, c.short_channel_id FROM transactions t LEFT JOIN transaction_annotations a ON (a.txid = t.id) LEFT JOIN channels c ON (a.channel = c.id) LEFT JOIN channels c2 ON (t.channel_id = c2.id) ORDER BY t.blockheight, t.txindex ASC" msgstr "" -#: wallet/wallet.c:4300 +#: wallet/wallet.c:4304 msgid "INSERT INTO penalty_bases ( channel_id, commitnum, txid, outnum, amount) VALUES (?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:4325 +#: wallet/wallet.c:4329 msgid "SELECT commitnum, txid, outnum, amount FROM penalty_bases WHERE channel_id = ?" msgstr "" -#: wallet/wallet.c:4349 +#: wallet/wallet.c:4353 msgid "DELETE FROM penalty_bases WHERE channel_id = ? AND commitnum = ?" msgstr "" -#: wallet/wallet.c:4367 +#: wallet/wallet.c:4371 msgid "SELECT 1 FROM offers WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4380 +#: wallet/wallet.c:4384 msgid "INSERT INTO offers ( offer_id, bolt12, label, status) VALUES (?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:4407 +#: wallet/wallet.c:4411 msgid "SELECT bolt12, label, status FROM offers WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4435 +#: wallet/wallet.c:4439 msgid "SELECT offer_id FROM offers;" msgstr "" -#: wallet/wallet.c:4461 +#: wallet/wallet.c:4465 msgid "UPDATE offers SET status=? WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4472 +#: wallet/wallet.c:4476 msgid "UPDATE invoices SET state=? WHERE state=? AND local_offer_id = ?;" msgstr "" -#: wallet/wallet.c:4500 +#: wallet/wallet.c:4504 msgid "SELECT status FROM offers WHERE offer_id = ?;" msgstr "" @@ -1257,4 +1269,4 @@ msgstr "" #: wallet/test/run-wallet.c:1649 msgid "INSERT INTO channels (id) VALUES (1);" msgstr "" -# SHA256STAMP:61244f420c5eefe9cf60f0599cdd6c17d38f719ed2bc5acac93ee1109f121dcf +# SHA256STAMP:16bc289317e93dbae2af010cde394060c0d5cbf610e5fcb995d6fa5ad4587bf1 diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index e93ebe418c85..ede16ddd6795 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -1521,7 +1521,7 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) &txid, 1, funding_sats, AMOUNT_MSAT(0), our_sats, - false, false, + 0, false, &cid, AMOUNT_MSAT(3333333000), AMOUNT_MSAT(33333), @@ -1540,7 +1540,7 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) &basepoints, &pk, NULL, 1000, 100, - NULL, true, true, + NULL, 0, 0, true, LOCAL, REASON_UNKNOWN, NULL); db_begin_transaction(w->db); CHECK(!wallet_err); diff --git a/wallet/wallet.c b/wallet/wallet.c index 70a895e6bf0f..c3336c915955 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1154,7 +1154,7 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm ok &= wallet_shachain_load(w, db_column_u64(stmt, 29), &wshachain); remote_shutdown_scriptpubkey = db_column_arr(tmpctx, stmt, 30, u8); - local_shutdown_scriptpubkey = db_column_arr(tmpctx, stmt, 49, u8); + local_shutdown_scriptpubkey = db_column_arr(tmpctx, stmt, 50, u8); /* Do we have a last_sent_commit, if yes, populate */ if (!db_column_is_null(stmt, 43)) { @@ -1222,17 +1222,17 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm return NULL; } - db_column_pubkey(stmt, 52, &local_basepoints.revocation); - db_column_pubkey(stmt, 53, &local_basepoints.payment); - db_column_pubkey(stmt, 54, &local_basepoints.htlc); - db_column_pubkey(stmt, 55, &local_basepoints.delayed_payment); - db_column_pubkey(stmt, 56, &local_funding_pubkey); - if (db_column_is_null(stmt, 57)) + db_column_pubkey(stmt, 53, &local_basepoints.revocation); + db_column_pubkey(stmt, 54, &local_basepoints.payment); + db_column_pubkey(stmt, 55, &local_basepoints.htlc); + db_column_pubkey(stmt, 56, &local_basepoints.delayed_payment); + db_column_pubkey(stmt, 57, &local_funding_pubkey); + if (db_column_is_null(stmt, 58)) shutdown_wrong_funding = NULL; else { shutdown_wrong_funding = tal(tmpctx, struct bitcoin_outpoint); - db_column_txid(stmt, 57, &shutdown_wrong_funding->txid); - shutdown_wrong_funding->n = db_column_int(stmt, 58); + db_column_txid(stmt, 58, &shutdown_wrong_funding->txid); + shutdown_wrong_funding->n = db_column_int(stmt, 59); } db_column_amount_sat(stmt, 15, &funding_sat); @@ -1269,7 +1269,7 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm &last_sig, wallet_htlc_sigs_load(tmpctx, w, db_column_u64(stmt, 0), - db_column_int(stmt, 48)), + db_column_int(stmt, 49)), &channel_info, take(fee_states), remote_shutdown_scriptpubkey, @@ -1287,10 +1287,11 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm db_column_int(stmt, 44), db_column_int(stmt, 45), db_column_arr(tmpctx, stmt, 46, u8), - db_column_int(stmt, 47), - db_column_int(stmt, 48), - db_column_int(stmt, 50), + db_column_u64(stmt, 47), + db_column_u64(stmt, 48), + db_column_int(stmt, 49), db_column_int(stmt, 51), + db_column_int(stmt, 52), shutdown_wrong_funding); if (!wallet_channel_load_inflights(w, chan)) { @@ -1370,18 +1371,19 @@ static bool wallet_channels_load_active(struct wallet *w) ", feerate_base" // 44 ", feerate_ppm" // 45 ", remote_upfront_shutdown_script" // 46 - ", option_static_remotekey" // 47 - ", option_anchor_outputs" // 48 - ", shutdown_scriptpubkey_local" // 49 - ", closer" // 50 - ", state_change_reason" // 51 - ", revocation_basepoint_local" // 52 - ", payment_basepoint_local" // 53 - ", htlc_basepoint_local" // 54 - ", delayed_payment_basepoint_local" // 55 - ", funding_pubkey_local" // 56 - ", shutdown_wrong_txid" // 57 - ", shutdown_wrong_outnum" // 58 + ", local_static_remotekey_start" // 47 + ", remote_static_remotekey_start" // 48 + ", option_anchor_outputs" // 49 + ", shutdown_scriptpubkey_local" // 50 + ", closer" // 51 + ", state_change_reason" // 52 + ", revocation_basepoint_local" // 53 + ", payment_basepoint_local" // 54 + ", htlc_basepoint_local" // 55 + ", delayed_payment_basepoint_local" // 56 + ", funding_pubkey_local" // 57 + ", shutdown_wrong_txid" // 58 + ", shutdown_wrong_outnum" // 59 " FROM channels" " WHERE state != ?;")); //? 0 db_bind_int(stmt, 0, CLOSED); @@ -1661,15 +1663,16 @@ void wallet_channel_save(struct wallet *w, struct channel *chan) " msatoshi_to_us_max=?," // 26 " feerate_base=?," // 27 " feerate_ppm=?," // 28 - " remote_upfront_shutdown_script=?," - " option_static_remotekey=?," // 30 - " option_anchor_outputs=?," // 31 - " shutdown_scriptpubkey_local=?," // 32 - " closer=?," // 33 - " state_change_reason=?," // 34 - " shutdown_wrong_txid=?," // 35 - " shutdown_wrong_outnum=?" // 36 - " WHERE id=?")); // 37 + " remote_upfront_shutdown_script=?," // 29 + " local_static_remotekey_start=?," // 30 + " remote_static_remotekey_start=?," // 31 + " option_anchor_outputs=?," // 32 + " shutdown_scriptpubkey_local=?," // 33 + " closer=?," // 34 + " state_change_reason=?," // 35 + " shutdown_wrong_txid=?," // 36 + " shutdown_wrong_outnum=?" // 37 + " WHERE id=?")); // 38 db_bind_u64(stmt, 0, chan->their_shachain.id); if (chan->scid) db_bind_short_channel_id(stmt, 1, chan->scid); @@ -1708,19 +1711,20 @@ void wallet_channel_save(struct wallet *w, struct channel *chan) db_bind_int(stmt, 27, chan->feerate_base); db_bind_int(stmt, 28, chan->feerate_ppm); db_bind_talarr(stmt, 29, chan->remote_upfront_shutdown_script); - db_bind_int(stmt, 30, chan->option_static_remotekey); - db_bind_int(stmt, 31, chan->option_anchor_outputs); - db_bind_talarr(stmt, 32, chan->shutdown_scriptpubkey[LOCAL]); - db_bind_int(stmt, 33, chan->closer); - db_bind_int(stmt, 34, chan->state_change_cause); + db_bind_u64(stmt, 30, chan->static_remotekey_start[LOCAL]); + db_bind_u64(stmt, 31, chan->static_remotekey_start[REMOTE]); + db_bind_int(stmt, 32, chan->option_anchor_outputs); + db_bind_talarr(stmt, 33, chan->shutdown_scriptpubkey[LOCAL]); + db_bind_int(stmt, 34, chan->closer); + db_bind_int(stmt, 35, chan->state_change_cause); if (chan->shutdown_wrong_funding) { - db_bind_txid(stmt, 35, &chan->shutdown_wrong_funding->txid); - db_bind_int(stmt, 36, chan->shutdown_wrong_funding->n); + db_bind_txid(stmt, 36, &chan->shutdown_wrong_funding->txid); + db_bind_int(stmt, 37, chan->shutdown_wrong_funding->n); } else { - db_bind_null(stmt, 35); db_bind_null(stmt, 36); + db_bind_null(stmt, 37); } - db_bind_u64(stmt, 37, chan->dbid); + db_bind_u64(stmt, 38, chan->dbid); db_exec_prepared_v2(take(stmt)); wallet_channel_config_save(w, &chan->channel_info.their_config); From 90687dea6ec247c6a5baa08f995fcbfb27614ccd Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 4 Jun 2021 14:43:47 +0930 Subject: [PATCH 12/16] onchaind: handle static_remotekey thresholds. No longer a global "on" or "off", it depends on the commitment number. Signed-off-by: Rusty Russell --- lightningd/onchain_control.c | 4 ++-- onchaind/onchaind.c | 22 ++++++++++++---------- onchaind/onchaind_wire.csv | 3 ++- onchaind/onchaind_wiregen.c | 12 +++++++----- onchaind/onchaind_wiregen.h | 6 +++--- onchaind/test/onchainstress-data.gz | Bin 25268 -> 26866 bytes onchaind/test/run-grind_feerate-bug.c | 2 +- onchaind/test/run-grind_feerate.c | 2 +- 8 files changed, 28 insertions(+), 23 deletions(-) diff --git a/lightningd/onchain_control.c b/lightningd/onchain_control.c index 3c0ce0b73f2d..759ae4180333 100644 --- a/lightningd/onchain_control.c +++ b/lightningd/onchain_control.c @@ -697,8 +697,8 @@ enum watch_result onchaind_funding_spent(struct channel *channel, channel->future_per_commitment_point, &channel->local_funding_pubkey, &channel->channel_info.remote_fundingkey, - /* FIXME! onchaind needs start numbers! */ - channel->static_remotekey_start[LOCAL] == 0, + channel->static_remotekey_start[LOCAL], + channel->static_remotekey_start[REMOTE], channel->option_anchor_outputs, is_replay, feerate_min(ld, NULL)); diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index e35a694faa60..22b6413ce780 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -84,8 +84,8 @@ static struct amount_msat our_msat; /* Needed for anchor outputs */ static struct pubkey funding_pubkey[NUM_SIDES]; -/* Does option_static_remotekey apply to this commitment tx? */ -static bool option_static_remotekey; +/* At what commit number does option_static_remotekey apply? */ +static u64 static_remotekey_start[NUM_SIDES]; /* Does option_anchor_outputs apply to this commitment tx? */ static bool option_anchor_outputs; @@ -2615,7 +2615,7 @@ static void handle_our_unilateral(const struct tx_parts *tx, if (!derive_keyset(&local_per_commitment_point, &basepoints[LOCAL], &basepoints[REMOTE], - option_static_remotekey, + commit_num >= static_remotekey_start[LOCAL], ks)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Deriving keyset for %"PRIu64, commit_num); @@ -3050,7 +3050,7 @@ static void handle_their_cheat(const struct tx_parts *tx, if (!derive_keyset(remote_per_commitment_point, &basepoints[REMOTE], &basepoints[LOCAL], - option_static_remotekey, + commit_num >= static_remotekey_start[REMOTE], ks)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Deriving keyset for %"PRIu64, commit_num); @@ -3063,7 +3063,7 @@ static void handle_their_cheat(const struct tx_parts *tx, " other_payment_key: %s" " self_htlc_key: %s" " other_htlc_key: %s" - " (option_static_remotekey = %i)", + " (static_remotekey = %"PRIu64"/%"PRIu64")", commit_num, type_to_string(tmpctx, struct pubkey, &keyset->self_revocation_key), @@ -3077,7 +3077,8 @@ static void handle_their_cheat(const struct tx_parts *tx, &keyset->self_htlc_key), type_to_string(tmpctx, struct pubkey, &keyset->other_htlc_key), - option_static_remotekey); + static_remotekey_start[LOCAL], + static_remotekey_start[REMOTE]); remote_wscript = to_self_wscript(tmpctx, to_self_delay[REMOTE], keyset); @@ -3154,7 +3155,7 @@ static void handle_their_cheat(const struct tx_parts *tx, tx_blockheight, script[LOCAL], remote_per_commitment_point, - option_static_remotekey); + commit_num >= static_remotekey_start[REMOTE]); script[LOCAL] = NULL; add_amt(&total_outs, amt); continue; @@ -3334,7 +3335,7 @@ static void handle_their_unilateral(const struct tx_parts *tx, if (!derive_keyset(remote_per_commitment_point, &basepoints[REMOTE], &basepoints[LOCAL], - option_static_remotekey, + commit_num >= static_remotekey_start[REMOTE], ks)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Deriving keyset for %"PRIu64, commit_num); @@ -3434,7 +3435,7 @@ static void handle_their_unilateral(const struct tx_parts *tx, tx_blockheight, script[LOCAL], remote_per_commitment_point, - option_static_remotekey); + commit_num >= static_remotekey_start[REMOTE]); script[LOCAL] = NULL; add_amt(&our_outs, amt); continue; @@ -3775,7 +3776,8 @@ int main(int argc, char *argv[]) &possible_remote_per_commitment_point, &funding_pubkey[LOCAL], &funding_pubkey[REMOTE], - &option_static_remotekey, + &static_remotekey_start[LOCAL], + &static_remotekey_start[REMOTE], &option_anchor_outputs, &open_is_replay, &min_relay_feerate)) { diff --git a/onchaind/onchaind_wire.csv b/onchaind/onchaind_wire.csv index d0e88eef2889..926ffb3924de 100644 --- a/onchaind/onchaind_wire.csv +++ b/onchaind/onchaind_wire.csv @@ -46,7 +46,8 @@ msgdata,onchaind_init,max_possible_feerate,u32, msgdata,onchaind_init,possible_remote_per_commit_point,?pubkey, msgdata,onchaind_init,local_funding_pubkey,pubkey, msgdata,onchaind_init,remote_funding_pubkey,pubkey, -msgdata,onchaind_init,option_static_remotekey,bool, +msgdata,onchaind_init,local_static_remotekey_start,u64, +msgdata,onchaind_init,remote_static_remotekey_start,u64, msgdata,onchaind_init,option_anchor_outputs,bool, msgdata,onchaind_init,is_replay,bool, # We need this for BIP125 rule 4 diff --git a/onchaind/onchaind_wiregen.c b/onchaind/onchaind_wiregen.c index 27797ad01bc7..381c0376cdd6 100644 --- a/onchaind/onchaind_wiregen.c +++ b/onchaind/onchaind_wiregen.c @@ -76,7 +76,7 @@ bool onchaind_wire_is_defined(u16 type) /* WIRE: ONCHAIND_INIT */ /* Begin! Here's the onchain tx which spends funding tx */ -u8 *towire_onchaind_init(const tal_t *ctx, const struct shachain *shachain, const struct chainparams *chainparams, struct amount_sat funding_amount_satoshi, struct amount_msat our_msat, const struct pubkey *old_remote_per_commitment_point, const struct pubkey *remote_per_commitment_point, u32 local_to_self_delay, u32 remote_to_self_delay, u32 delayed_to_us_feerate, u32 htlc_feerate, u32 penalty_feerate, struct amount_sat local_dust_limit_satoshi, const struct bitcoin_txid *our_broadcast_txid, const u8 *local_scriptpubkey, const u8 *remote_scriptpubkey, const struct pubkey *ourwallet_pubkey, enum side opener, const struct basepoints *local_basepoints, const struct basepoints *remote_basepoints, const struct tx_parts *tx_parts, u32 locktime, u32 tx_blockheight, u32 reasonable_depth, const struct bitcoin_signature *htlc_signature, u64 num_htlcs, u32 min_possible_feerate, u32 max_possible_feerate, const struct pubkey *possible_remote_per_commit_point, const struct pubkey *local_funding_pubkey, const struct pubkey *remote_funding_pubkey, bool option_static_remotekey, bool option_anchor_outputs, bool is_replay, u32 min_relay_feerate) +u8 *towire_onchaind_init(const tal_t *ctx, const struct shachain *shachain, const struct chainparams *chainparams, struct amount_sat funding_amount_satoshi, struct amount_msat our_msat, const struct pubkey *old_remote_per_commitment_point, const struct pubkey *remote_per_commitment_point, u32 local_to_self_delay, u32 remote_to_self_delay, u32 delayed_to_us_feerate, u32 htlc_feerate, u32 penalty_feerate, struct amount_sat local_dust_limit_satoshi, const struct bitcoin_txid *our_broadcast_txid, const u8 *local_scriptpubkey, const u8 *remote_scriptpubkey, const struct pubkey *ourwallet_pubkey, enum side opener, const struct basepoints *local_basepoints, const struct basepoints *remote_basepoints, const struct tx_parts *tx_parts, u32 locktime, u32 tx_blockheight, u32 reasonable_depth, const struct bitcoin_signature *htlc_signature, u64 num_htlcs, u32 min_possible_feerate, u32 max_possible_feerate, const struct pubkey *possible_remote_per_commit_point, const struct pubkey *local_funding_pubkey, const struct pubkey *remote_funding_pubkey, u64 local_static_remotekey_start, u64 remote_static_remotekey_start, bool option_anchor_outputs, bool is_replay, u32 min_relay_feerate) { u16 local_scriptpubkey_len = tal_count(local_scriptpubkey); u16 remote_scriptpubkey_len = tal_count(remote_scriptpubkey); @@ -130,7 +130,8 @@ u8 *towire_onchaind_init(const tal_t *ctx, const struct shachain *shachain, cons } towire_pubkey(&p, local_funding_pubkey); towire_pubkey(&p, remote_funding_pubkey); - towire_bool(&p, option_static_remotekey); + towire_u64(&p, local_static_remotekey_start); + towire_u64(&p, remote_static_remotekey_start); towire_bool(&p, option_anchor_outputs); towire_bool(&p, is_replay); /* We need this for BIP125 rule 4 */ @@ -138,7 +139,7 @@ u8 *towire_onchaind_init(const tal_t *ctx, const struct shachain *shachain, cons return memcheck(p, tal_count(p)); } -bool fromwire_onchaind_init(const tal_t *ctx, const void *p, struct shachain *shachain, const struct chainparams **chainparams, struct amount_sat *funding_amount_satoshi, struct amount_msat *our_msat, struct pubkey *old_remote_per_commitment_point, struct pubkey *remote_per_commitment_point, u32 *local_to_self_delay, u32 *remote_to_self_delay, u32 *delayed_to_us_feerate, u32 *htlc_feerate, u32 *penalty_feerate, struct amount_sat *local_dust_limit_satoshi, struct bitcoin_txid *our_broadcast_txid, u8 **local_scriptpubkey, u8 **remote_scriptpubkey, struct pubkey *ourwallet_pubkey, enum side *opener, struct basepoints *local_basepoints, struct basepoints *remote_basepoints, struct tx_parts **tx_parts, u32 *locktime, u32 *tx_blockheight, u32 *reasonable_depth, struct bitcoin_signature **htlc_signature, u64 *num_htlcs, u32 *min_possible_feerate, u32 *max_possible_feerate, struct pubkey **possible_remote_per_commit_point, struct pubkey *local_funding_pubkey, struct pubkey *remote_funding_pubkey, bool *option_static_remotekey, bool *option_anchor_outputs, bool *is_replay, u32 *min_relay_feerate) +bool fromwire_onchaind_init(const tal_t *ctx, const void *p, struct shachain *shachain, const struct chainparams **chainparams, struct amount_sat *funding_amount_satoshi, struct amount_msat *our_msat, struct pubkey *old_remote_per_commitment_point, struct pubkey *remote_per_commitment_point, u32 *local_to_self_delay, u32 *remote_to_self_delay, u32 *delayed_to_us_feerate, u32 *htlc_feerate, u32 *penalty_feerate, struct amount_sat *local_dust_limit_satoshi, struct bitcoin_txid *our_broadcast_txid, u8 **local_scriptpubkey, u8 **remote_scriptpubkey, struct pubkey *ourwallet_pubkey, enum side *opener, struct basepoints *local_basepoints, struct basepoints *remote_basepoints, struct tx_parts **tx_parts, u32 *locktime, u32 *tx_blockheight, u32 *reasonable_depth, struct bitcoin_signature **htlc_signature, u64 *num_htlcs, u32 *min_possible_feerate, u32 *max_possible_feerate, struct pubkey **possible_remote_per_commit_point, struct pubkey *local_funding_pubkey, struct pubkey *remote_funding_pubkey, u64 *local_static_remotekey_start, u64 *remote_static_remotekey_start, bool *option_anchor_outputs, bool *is_replay, u32 *min_relay_feerate) { u16 local_scriptpubkey_len; u16 remote_scriptpubkey_len; @@ -201,7 +202,8 @@ bool fromwire_onchaind_init(const tal_t *ctx, const void *p, struct shachain *sh } fromwire_pubkey(&cursor, &plen, local_funding_pubkey); fromwire_pubkey(&cursor, &plen, remote_funding_pubkey); - *option_static_remotekey = fromwire_bool(&cursor, &plen); + *local_static_remotekey_start = fromwire_u64(&cursor, &plen); + *remote_static_remotekey_start = fromwire_u64(&cursor, &plen); *option_anchor_outputs = fromwire_bool(&cursor, &plen); *is_replay = fromwire_bool(&cursor, &plen); /* We need this for BIP125 rule 4 */ @@ -635,4 +637,4 @@ bool fromwire_onchaind_notify_coin_mvt(const void *p, struct chain_coin_mvt *mvt fromwire_chain_coin_mvt(&cursor, &plen, mvt); return cursor != NULL; } -// SHA256STAMP:6884d8c13750d6bb08de384fe35050309f8f66037662671c2aad2eaa16f47463 +// SHA256STAMP:66e19538be7f5a9e9076bfe995a9bf0cbb5d303df8f6c383e427c11ef2e85e2e diff --git a/onchaind/onchaind_wiregen.h b/onchaind/onchaind_wiregen.h index 4d53b35f31ea..48692bae739b 100644 --- a/onchaind/onchaind_wiregen.h +++ b/onchaind/onchaind_wiregen.h @@ -69,8 +69,8 @@ bool onchaind_wire_is_defined(u16 type); /* WIRE: ONCHAIND_INIT */ /* Begin! Here's the onchain tx which spends funding tx */ -u8 *towire_onchaind_init(const tal_t *ctx, const struct shachain *shachain, const struct chainparams *chainparams, struct amount_sat funding_amount_satoshi, struct amount_msat our_msat, const struct pubkey *old_remote_per_commitment_point, const struct pubkey *remote_per_commitment_point, u32 local_to_self_delay, u32 remote_to_self_delay, u32 delayed_to_us_feerate, u32 htlc_feerate, u32 penalty_feerate, struct amount_sat local_dust_limit_satoshi, const struct bitcoin_txid *our_broadcast_txid, const u8 *local_scriptpubkey, const u8 *remote_scriptpubkey, const struct pubkey *ourwallet_pubkey, enum side opener, const struct basepoints *local_basepoints, const struct basepoints *remote_basepoints, const struct tx_parts *tx_parts, u32 locktime, u32 tx_blockheight, u32 reasonable_depth, const struct bitcoin_signature *htlc_signature, u64 num_htlcs, u32 min_possible_feerate, u32 max_possible_feerate, const struct pubkey *possible_remote_per_commit_point, const struct pubkey *local_funding_pubkey, const struct pubkey *remote_funding_pubkey, bool option_static_remotekey, bool option_anchor_outputs, bool is_replay, u32 min_relay_feerate); -bool fromwire_onchaind_init(const tal_t *ctx, const void *p, struct shachain *shachain, const struct chainparams **chainparams, struct amount_sat *funding_amount_satoshi, struct amount_msat *our_msat, struct pubkey *old_remote_per_commitment_point, struct pubkey *remote_per_commitment_point, u32 *local_to_self_delay, u32 *remote_to_self_delay, u32 *delayed_to_us_feerate, u32 *htlc_feerate, u32 *penalty_feerate, struct amount_sat *local_dust_limit_satoshi, struct bitcoin_txid *our_broadcast_txid, u8 **local_scriptpubkey, u8 **remote_scriptpubkey, struct pubkey *ourwallet_pubkey, enum side *opener, struct basepoints *local_basepoints, struct basepoints *remote_basepoints, struct tx_parts **tx_parts, u32 *locktime, u32 *tx_blockheight, u32 *reasonable_depth, struct bitcoin_signature **htlc_signature, u64 *num_htlcs, u32 *min_possible_feerate, u32 *max_possible_feerate, struct pubkey **possible_remote_per_commit_point, struct pubkey *local_funding_pubkey, struct pubkey *remote_funding_pubkey, bool *option_static_remotekey, bool *option_anchor_outputs, bool *is_replay, u32 *min_relay_feerate); +u8 *towire_onchaind_init(const tal_t *ctx, const struct shachain *shachain, const struct chainparams *chainparams, struct amount_sat funding_amount_satoshi, struct amount_msat our_msat, const struct pubkey *old_remote_per_commitment_point, const struct pubkey *remote_per_commitment_point, u32 local_to_self_delay, u32 remote_to_self_delay, u32 delayed_to_us_feerate, u32 htlc_feerate, u32 penalty_feerate, struct amount_sat local_dust_limit_satoshi, const struct bitcoin_txid *our_broadcast_txid, const u8 *local_scriptpubkey, const u8 *remote_scriptpubkey, const struct pubkey *ourwallet_pubkey, enum side opener, const struct basepoints *local_basepoints, const struct basepoints *remote_basepoints, const struct tx_parts *tx_parts, u32 locktime, u32 tx_blockheight, u32 reasonable_depth, const struct bitcoin_signature *htlc_signature, u64 num_htlcs, u32 min_possible_feerate, u32 max_possible_feerate, const struct pubkey *possible_remote_per_commit_point, const struct pubkey *local_funding_pubkey, const struct pubkey *remote_funding_pubkey, u64 local_static_remotekey_start, u64 remote_static_remotekey_start, bool option_anchor_outputs, bool is_replay, u32 min_relay_feerate); +bool fromwire_onchaind_init(const tal_t *ctx, const void *p, struct shachain *shachain, const struct chainparams **chainparams, struct amount_sat *funding_amount_satoshi, struct amount_msat *our_msat, struct pubkey *old_remote_per_commitment_point, struct pubkey *remote_per_commitment_point, u32 *local_to_self_delay, u32 *remote_to_self_delay, u32 *delayed_to_us_feerate, u32 *htlc_feerate, u32 *penalty_feerate, struct amount_sat *local_dust_limit_satoshi, struct bitcoin_txid *our_broadcast_txid, u8 **local_scriptpubkey, u8 **remote_scriptpubkey, struct pubkey *ourwallet_pubkey, enum side *opener, struct basepoints *local_basepoints, struct basepoints *remote_basepoints, struct tx_parts **tx_parts, u32 *locktime, u32 *tx_blockheight, u32 *reasonable_depth, struct bitcoin_signature **htlc_signature, u64 *num_htlcs, u32 *min_possible_feerate, u32 *max_possible_feerate, struct pubkey **possible_remote_per_commit_point, struct pubkey *local_funding_pubkey, struct pubkey *remote_funding_pubkey, u64 *local_static_remotekey_start, u64 *remote_static_remotekey_start, bool *option_anchor_outputs, bool *is_replay, u32 *min_relay_feerate); /* WIRE: ONCHAIND_HTLC */ /* This is all the HTLCs: one per message */ @@ -161,4 +161,4 @@ bool fromwire_onchaind_notify_coin_mvt(const void *p, struct chain_coin_mvt *mvt #endif /* LIGHTNING_ONCHAIND_ONCHAIND_WIREGEN_H */ -// SHA256STAMP:6884d8c13750d6bb08de384fe35050309f8f66037662671c2aad2eaa16f47463 +// SHA256STAMP:66e19538be7f5a9e9076bfe995a9bf0cbb5d303df8f6c383e427c11ef2e85e2e diff --git a/onchaind/test/onchainstress-data.gz b/onchaind/test/onchainstress-data.gz index fa43fb21a13ec2194885a59fc4ad988ef6f2a7db..cdf57c1a1b2544b0975613a4b6719a1aa089cba4 100644 GIT binary patch literal 26866 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 Qq49J!E)LKY_R7xsKVfNBVE_OC literal 25268 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 Date: Fri, 4 Jun 2021 14:43:47 +0930 Subject: [PATCH 13/16] channeld: handle upgrade match. We don't actually set desired_type yet, but this handles it. Changelog-EXPERIMENTAL: Protocol: we can now upgrade old channels to `option_static_remotekey` from https://github.com/lightningnetwork/lightning-rfc/pull/868 Signed-off-by: Rusty Russell --- channeld/channeld.c | 113 ++++++++++++++++++++++++++++++++++- channeld/channeld_wire.csv | 4 ++ channeld/channeld_wiregen.c | 26 +++++++- channeld/channeld_wiregen.h | 9 ++- common/features.c | 14 +++++ common/features.h | 4 ++ lightningd/channel_control.c | 30 ++++++++++ 7 files changed, 197 insertions(+), 3 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index f3ba9e201893..6b6494c1d2f7 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -368,6 +368,50 @@ static bool handle_master_request_later(struct peer *peer, const u8 *msg) } return false; } + +static bool channel_type_eq(const struct channel_type *a, + const struct channel_type *b) +{ + return featurebits_eq(a->features, b->features); +} + +static bool match_type(const struct channel_type *desired, + const struct channel_type *current, + struct channel_type **upgradable) +{ + /* Missing fields are possible. */ + if (!desired || !current) + return false; + + if (channel_type_eq(desired, current)) + return true; + + for (size_t i = 0; i < tal_count(upgradable); i++) { + if (channel_type_eq(desired, upgradable[i])) + return true; + } + + return false; +} + +static void set_channel_type(struct channel *channel, + const struct channel_type *type) +{ + const struct channel_type *cur = channel_type(tmpctx, channel); + + if (channel_type_eq(cur, type)) + return; + + /* We only allow one upgrade at the moment, so that's it. */ + assert(!channel->option_static_remotekey); + assert(feature_offered(type->features, OPT_STATIC_REMOTEKEY)); + + /* Do upgrade, tell master. */ + channel->option_static_remotekey = true; + status_unusual("Upgraded channel to [%s]", + fmt_featurebits(tmpctx, type->features)); + wire_sync_write(MASTER_FD, take(towire_channeld_upgraded(NULL, true))); +} #else /* !EXPERIMENTAL_FEATURES */ static bool handle_master_request_later(struct peer *peer, const u8 *msg) { @@ -2499,7 +2543,8 @@ static void peer_reconnect(struct peer *peer, &my_current_per_commitment_point, NULL); #if EXPERIMENTAL_FEATURES - send_tlvs = tlv_channel_reestablish_tlvs_new(tmpctx); + /* Subtle: we free tmpctx below as we loop, so tal off peer */ + send_tlvs = tlv_channel_reestablish_tlvs_new(peer); /* BOLT-upgrade_protocol #2: * A node sending `channel_reestablish`, if it supports upgrading channels: * - MUST set `next_to_send` the commitment number of the next @@ -2797,6 +2842,71 @@ static void peer_reconnect(struct peer *peer, fmt_featurebits(tmpctx, recv_tlvs->upgradable[i]->features)); } + + /* BOLT-upgrade_protocol #2: + * + * A node receiving `channel_reestablish`: + * - if it has to retransmit `commitment_signed` or `revoke_and_ack`: + * - MUST consider the channel feature change failed. + */ + if (retransmit_commitment_signed || retransmit_revoke_and_ack) { + status_debug("No upgrade: we retransmitted"); + /* BOLT-upgrade_protocol #2: + * + * - if `next_to_send` is missing, or not equal to the + * `next_commitment_number` it sent: + * - MUST consider the channel feature change failed. + */ + } else if (!recv_tlvs->next_to_send) { + status_debug("No upgrade: no next_to_send received"); + } else if (*recv_tlvs->next_to_send != peer->next_index[LOCAL]) { + status_debug("No upgrade: they're retransmitting"); + /* BOLT-upgrade_protocol #2: + * + * - if updates are pending on either sides' commitment transaction: + * - MUST consider the channel feature change failed. + */ + /* Note that we can have HTLCs we *want* to add or remove + * but haven't yet: thats OK! */ + } else if (pending_updates(peer->channel, LOCAL, true) + || pending_updates(peer->channel, REMOTE, true)) { + status_debug("No upgrade: pending changes"); + } else { + const struct tlv_channel_reestablish_tlvs *initr, *ninitr; + const struct channel_type *type; + + if (peer->channel->opener == LOCAL) { + initr = send_tlvs; + ninitr = recv_tlvs; + } else { + initr = recv_tlvs; + ninitr = send_tlvs; + } + + /* BOLT-upgrade_protocol #2: + * + * - if `desired_type` matches `current_type` or any + * `upgradable` `upgrades`: + * - MUST consider the channel type to be `desired_type`. + * - otherwise: + * - MUST consider the channel feature change failed. + * - if there is a `current_type` field: + * - MUST consider the channel type to be `current_type`. + */ + /* Note: returns NULL on missing fields, aka NULL */ + if (match_type(initr->desired_type, + ninitr->current_type, ninitr->upgradable)) + type = initr->desired_type; + else if (ninitr->current_type) + type = ninitr->current_type; + else + type = NULL; + + if (type) + set_channel_type(peer->channel, type); + } + tal_free(send_tlvs); + #endif /* EXPERIMENTAL_FEATURES */ /* Corner case: we didn't send shutdown before because update_add_htlc @@ -3246,6 +3356,7 @@ static void req_in(struct peer *peer, const u8 *msg) case WIRE_CHANNELD_DEV_MEMLEAK_REPLY: case WIRE_CHANNELD_SEND_ERROR_REPLY: case WIRE_CHANNELD_DEV_QUIESCE_REPLY: + case WIRE_CHANNELD_UPGRADED: break; } diff --git a/channeld/channeld_wire.csv b/channeld/channeld_wire.csv index a376f5a6536f..8af0756a34a1 100644 --- a/channeld/channeld_wire.csv +++ b/channeld/channeld_wire.csv @@ -221,3 +221,7 @@ msgtype,channeld_send_error_reply,1108 # Ask channeld to quiesce. msgtype,channeld_dev_quiesce,1009 msgtype,channeld_dev_quiesce_reply,1109 + +# Tell master we're upgrading the commitment tx. +msgtype,channeld_upgraded,1011 +msgdata,channeld_upgraded,option_static_remotekey,bool, diff --git a/channeld/channeld_wiregen.c b/channeld/channeld_wiregen.c index ebf2efcae2f2..0a4d375bc327 100644 --- a/channeld/channeld_wiregen.c +++ b/channeld/channeld_wiregen.c @@ -48,6 +48,7 @@ const char *channeld_wire_name(int e) case WIRE_CHANNELD_SEND_ERROR_REPLY: return "WIRE_CHANNELD_SEND_ERROR_REPLY"; case WIRE_CHANNELD_DEV_QUIESCE: return "WIRE_CHANNELD_DEV_QUIESCE"; case WIRE_CHANNELD_DEV_QUIESCE_REPLY: return "WIRE_CHANNELD_DEV_QUIESCE_REPLY"; + case WIRE_CHANNELD_UPGRADED: return "WIRE_CHANNELD_UPGRADED"; } snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e); @@ -85,6 +86,7 @@ bool channeld_wire_is_defined(u16 type) case WIRE_CHANNELD_SEND_ERROR_REPLY:; case WIRE_CHANNELD_DEV_QUIESCE:; case WIRE_CHANNELD_DEV_QUIESCE_REPLY:; + case WIRE_CHANNELD_UPGRADED:; return true; } return false; @@ -1113,4 +1115,26 @@ bool fromwire_channeld_dev_quiesce_reply(const void *p) return false; return cursor != NULL; } -// SHA256STAMP:fa8ee25e2f6082e9889962218e6e345dcb4430840b8f831b40cbb0c415b690b5 + +/* WIRE: CHANNELD_UPGRADED */ +/* Tell master we're upgrading the commitment tx. */ +u8 *towire_channeld_upgraded(const tal_t *ctx, bool option_static_remotekey) +{ + u8 *p = tal_arr(ctx, u8, 0); + + towire_u16(&p, WIRE_CHANNELD_UPGRADED); + towire_bool(&p, option_static_remotekey); + + return memcheck(p, tal_count(p)); +} +bool fromwire_channeld_upgraded(const void *p, bool *option_static_remotekey) +{ + const u8 *cursor = p; + size_t plen = tal_count(p); + + if (fromwire_u16(&cursor, &plen) != WIRE_CHANNELD_UPGRADED) + return false; + *option_static_remotekey = fromwire_bool(&cursor, &plen); + return cursor != NULL; +} +// SHA256STAMP:2d7b763e89512ad8c5921b90c13f37ac83ab0016384c38e8c8e831683d668651 diff --git a/channeld/channeld_wiregen.h b/channeld/channeld_wiregen.h index 1b4293a30853..3dde409668f6 100644 --- a/channeld/channeld_wiregen.h +++ b/channeld/channeld_wiregen.h @@ -73,6 +73,8 @@ enum channeld_wire { /* Ask channeld to quiesce. */ WIRE_CHANNELD_DEV_QUIESCE = 1009, WIRE_CHANNELD_DEV_QUIESCE_REPLY = 1109, + /* Tell master we're upgrading the commitment tx. */ + WIRE_CHANNELD_UPGRADED = 1011, }; const char *channeld_wire_name(int e); @@ -223,6 +225,11 @@ bool fromwire_channeld_dev_quiesce(const void *p); u8 *towire_channeld_dev_quiesce_reply(const tal_t *ctx); bool fromwire_channeld_dev_quiesce_reply(const void *p); +/* WIRE: CHANNELD_UPGRADED */ +/* Tell master we're upgrading the commitment tx. */ +u8 *towire_channeld_upgraded(const tal_t *ctx, bool option_static_remotekey); +bool fromwire_channeld_upgraded(const void *p, bool *option_static_remotekey); + #endif /* LIGHTNING_CHANNELD_CHANNELD_WIREGEN_H */ -// SHA256STAMP:fa8ee25e2f6082e9889962218e6e345dcb4430840b8f831b40cbb0c415b690b5 +// SHA256STAMP:2d7b763e89512ad8c5921b90c13f37ac83ab0016384c38e8c8e831683d668651 diff --git a/common/features.c b/common/features.c index a0e6fe7bc357..d77f514666e3 100644 --- a/common/features.c +++ b/common/features.c @@ -476,6 +476,20 @@ u8 *featurebits_or(const tal_t *ctx, const u8 *f1 TAKES, const u8 *f2 TAKES) return result; } +bool featurebits_eq(const u8 *f1, const u8 *f2) +{ + size_t len = tal_bytelen(f1); + + if (tal_bytelen(f2) > len) + len = tal_bytelen(f2); + + for (size_t i = 0; i < len * 8; i++) { + if (feature_is_set(f1, i) != feature_is_set(f2, i)) + return false; + } + return true; +} + struct feature_set *fromwire_feature_set(const tal_t *ctx, const u8 **cursor, size_t *max) { diff --git a/common/features.h b/common/features.h index 485262acef6d..0de7c31c9571 100644 --- a/common/features.h +++ b/common/features.h @@ -71,6 +71,10 @@ void set_feature_bit(u8 **ptr, u32 bit); /* Given two featurebit vectors, combine them by applying a logical OR. */ u8 *featurebits_or(const tal_t *ctx, const u8 *f1 TAKES, const u8 *f2 TAKES); +/* Are these two feature bitsets functionally equal (one may have + * trailing zeroes)? */ +bool featurebits_eq(const u8 *f1, const u8 *f2); + /* Good for debugging: returns comma-separated string of bits. */ const char *fmt_featurebits(const tal_t *ctx, const u8 *featurebits); diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 51107817b6bf..e8c87401af1d 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -370,6 +370,29 @@ void forget_channel(struct channel *channel, const char *why) forget(channel); } +#if EXPERIMENTAL_FEATURES +static void handle_channel_upgrade(struct channel *channel, + const u8 *msg) +{ + bool option_static_remotekey; + + if (!fromwire_channeld_upgraded(msg, &option_static_remotekey)) { + channel_internal_error(channel, "bad handle_channel_upgrade: %s", + tal_hex(tmpctx, msg)); + return; + } + + channel->static_remotekey_start[LOCAL] = channel->next_index[LOCAL]; + channel->static_remotekey_start[REMOTE] = channel->next_index[REMOTE]; + log_debug(channel->log, + "option_static_remotekey enabled at %"PRIu64"/%"PRIu64, + channel->static_remotekey_start[LOCAL], + channel->static_remotekey_start[REMOTE]); + + wallet_channel_save(channel->peer->ld->wallet, channel); +} +#endif /* EXPERIMENTAL_FEATURES */ + static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) { enum channeld_wire t = fromwire_peektype(msg); @@ -405,6 +428,13 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) case WIRE_CHANNELD_SEND_ERROR_REPLY: handle_error_channel(sd->channel, msg); break; +#if EXPERIMENTAL_FEATURES + case WIRE_CHANNELD_UPGRADED: + handle_channel_upgrade(sd->channel, msg); + break; +#else + case WIRE_CHANNELD_UPGRADED: +#endif /* And we never get these from channeld. */ case WIRE_CHANNELD_INIT: case WIRE_CHANNELD_FUNDING_DEPTH: From 0fd620d0e214b810d8143ac021e802eb2d353cf6 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 4 Jun 2021 14:43:47 +0930 Subject: [PATCH 14/16] channeld: set desired_type to upgrade `option_static_remotekey` if not already. Signed-off-by: Rusty Russell --- channeld/channeld.c | 3 ++- common/initial_channel.c | 7 +++++++ common/initial_channel.h | 4 ++++ tests/test_connection.py | 16 +++++++++++++++- 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index 6b6494c1d2f7..305de7e9eb34 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -2558,7 +2558,8 @@ static void peer_reconnect(struct peer *peer, * channel. */ if (peer->channel->opener == LOCAL) - send_tlvs->desired_type = channel_type(send_tlvs, peer->channel); + send_tlvs->desired_type = channel_desired_type(send_tlvs, + peer->channel); else { /* BOLT-upgrade_protocol #2: * - otherwise: diff --git a/common/initial_channel.c b/common/initial_channel.c index e62f49d93b9a..8270f4a1bf16 100644 --- a/common/initial_channel.c +++ b/common/initial_channel.c @@ -197,6 +197,13 @@ struct channel_type **channel_upgradable_types(const tal_t *ctx, return arr; } + +struct channel_type *channel_desired_type(const tal_t *ctx, + const struct channel *channel) +{ + /* For now, we just want option_static_remotekey */ + return type_static_remotekey(ctx); +} #endif /* EXPERIMENTAL_FEATURES */ static char *fmt_channel_view(const tal_t *ctx, const struct channel_view *view) diff --git a/common/initial_channel.h b/common/initial_channel.h index f756cd0b0a21..09f2e86a16b2 100644 --- a/common/initial_channel.h +++ b/common/initial_channel.h @@ -151,6 +151,10 @@ struct channel_type *channel_type(const tal_t *ctx, /* What features can we upgrade? (Returns NULL if none). */ struct channel_type **channel_upgradable_types(const tal_t *ctx, const struct channel *channel); + +/* What features do we want? */ +struct channel_type *channel_desired_type(const tal_t *ctx, + const struct channel *channel); #endif /* EXPERIMENTAL_FEATURES */ #endif /* LIGHTNING_COMMON_INITIAL_CHANNEL_H */ diff --git a/tests/test_connection.py b/tests/test_connection.py index 89920f59dfc6..fb9677baa1bd 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -3491,7 +3491,21 @@ def test_upgrade_statickey(node_factory, executor): l1.daemon.wait_for_logs([r"They sent current_type \[\]", r"They offered upgrade to \[13\]"]) - l2.daemon.wait_for_log(r"They sent desired_type \[\]") + l2.daemon.wait_for_log(r"They sent desired_type \[13\]") + + l1.daemon.wait_for_log('option_static_remotekey enabled at 1/1') + l2.daemon.wait_for_log('option_static_remotekey enabled at 1/1') + + # Make sure it's committed to db! + wait_for(lambda: l1.db_query('SELECT local_static_remotekey_start, remote_static_remotekey_start FROM channels;') == [{'local_static_remotekey_start': 1, 'remote_static_remotekey_start': 1}]) + + # They will consider themselves upgraded. + l1.rpc.disconnect(l2.info['id'], force=True) + # They won't offer upgrade! + assert not l1.daemon.is_in_log("They offered upgrade", + start=l1.daemon.logsearch_start) + l1.daemon.wait_for_log(r"They sent current_type \[13\]") + l2.daemon.wait_for_log(r"They sent desired_type \[13\]") @unittest.skipIf(not EXPERIMENTAL_FEATURES, "quiescence is experimental") From b6784931cc6d52d4d689d66f07bbe27fd2e987c1 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 4 Jun 2021 14:43:47 +0930 Subject: [PATCH 15/16] pytest: test onchaind handles unilateral and penalty txs on either side of upgrade. Signed-off-by: Rusty Russell --- tests/test_connection.py | 102 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/tests/test_connection.py b/tests/test_connection.py index fb9677baa1bd..fdae90c1d241 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -3508,6 +3508,108 @@ def test_upgrade_statickey(node_factory, executor): l2.daemon.wait_for_log(r"They sent desired_type \[13\]") +@unittest.skipIf(not EXPERIMENTAL_FEATURES, "upgrade protocol not available") +@pytest.mark.developer("dev-force-features required") +def test_upgrade_statickey_onchaind(node_factory, executor, bitcoind): + """We test penalty before/after, and unilateral before/after""" + l1, l2 = node_factory.line_graph(2, opts=[{'may_reconnect': True, + 'dev-force-features': ["-13", "-21"], + # We try to cheat! + 'allow_broken_log': True}, + {'may_reconnect': True}]) + + # TEST 1: Cheat from pre-upgrade. + tx = l1.rpc.dev_sign_last_tx(l2.info['id'])['tx'] + + l1.rpc.disconnect(l2.info['id'], force=True) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + l1.daemon.wait_for_log('option_static_remotekey enabled at 1/1') + + # Pre-statickey penalty works. + bitcoind.rpc.sendrawtransaction(tx) + bitcoind.generate_block(1) + + l2.wait_for_onchaind_broadcast('OUR_PENALTY_TX', + 'THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM') + bitcoind.generate_block(100) + wait_for(lambda: len(l2.rpc.listpeers()['peers']) == 0) + + # TEST 2: Cheat from post-upgrade. + node_factory.join_nodes([l1, l2]) + l1.rpc.disconnect(l2.info['id'], force=True) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + + l1.daemon.wait_for_log('option_static_remotekey enabled at 1/1') + l2.daemon.wait_for_log('option_static_remotekey enabled at 1/1') + + l1.pay(l2, 1000000) + + # We will try to cheat later. + tx = l1.rpc.dev_sign_last_tx(l2.info['id'])['tx'] + + l1.pay(l2, 1000000) + + # Pre-statickey penalty works. + bitcoind.rpc.sendrawtransaction(tx) + bitcoind.generate_block(1) + + l2.wait_for_onchaind_broadcast('OUR_PENALTY_TX', + 'THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM') + bitcoind.generate_block(100) + wait_for(lambda: len(l2.rpc.listpeers()['peers']) == 0) + + # TEST 3: Unilateral close from pre-upgrade + node_factory.join_nodes([l1, l2]) + + # Give them both something for onchain close. + l1.pay(l2, 1000000) + + # Make sure it's completely quiescent. + l1.daemon.wait_for_log("chan#3: Removing out HTLC 0 state RCVD_REMOVE_ACK_REVOCATION FULFILLED") + + l1.rpc.disconnect(l2.info['id'], force=True) + l1.daemon.wait_for_log('option_static_remotekey enabled at 3/3') + + # But this is the *pre*-update commit tx! + l2.stop() + l1.rpc.close(l2.info['id'], unilateraltimeout=1) + bitcoind.generate_block(1, wait_for_mempool=1) + l2.start() + + # They should both handle it fine. + l1.daemon.wait_for_log('Propose handling OUR_UNILATERAL/DELAYED_OUTPUT_TO_US by OUR_DELAYED_RETURN_TO_WALLET .* after 5 blocks') + l2.daemon.wait_for_logs(['Ignoring output .*: THEIR_UNILATERAL/OUTPUT_TO_US', + 'Ignoring output .*: THEIR_UNILATERAL/DELAYED_OUTPUT_TO_THEM']) + bitcoind.generate_block(5) + bitcoind.generate_block(100, wait_for_mempool=1) + + wait_for(lambda: len(l2.rpc.listpeers()['peers']) == 0) + + # TEST 4: Unilateral close from post-upgrade + node_factory.join_nodes([l1, l2]) + + l1.rpc.disconnect(l2.info['id'], force=True) + l1.daemon.wait_for_log('option_static_remotekey enabled at 1/1') + + # Move to static_remotekey. + l1.pay(l2, 1000000) + + l2.stop() + l1.rpc.close(l2.info['id'], unilateraltimeout=1) + bitcoind.generate_block(1, wait_for_mempool=1) + l2.start() + + # They should both handle it fine. + l1.daemon.wait_for_log('Propose handling OUR_UNILATERAL/DELAYED_OUTPUT_TO_US by OUR_DELAYED_RETURN_TO_WALLET .* after 5 blocks') + l2.daemon.wait_for_logs(['Ignoring output .*: THEIR_UNILATERAL/OUTPUT_TO_US', + 'Ignoring output .*: THEIR_UNILATERAL/DELAYED_OUTPUT_TO_THEM']) + + bitcoind.generate_block(5) + bitcoind.generate_block(100, wait_for_mempool=1) + + wait_for(lambda: len(l2.rpc.listpeers()['peers']) == 0) + + @unittest.skipIf(not EXPERIMENTAL_FEATURES, "quiescence is experimental") @pytest.mark.developer("quiescence triggering is dev only") def test_quiescence(node_factory, executor): From 519adf773c13708698776c53818960d3d1839404 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 4 Jun 2021 14:43:48 +0930 Subject: [PATCH 16/16] pytest: test that both sides refuse upgrade if not quiescent. Signed-off-by: Rusty Russell --- tests/test_connection.py | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tests/test_connection.py b/tests/test_connection.py index fdae90c1d241..ecadb4b208a5 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -3610,6 +3610,49 @@ def test_upgrade_statickey_onchaind(node_factory, executor, bitcoind): wait_for(lambda: len(l2.rpc.listpeers()['peers']) == 0) +@unittest.skipIf(not EXPERIMENTAL_FEATURES, "upgrade protocol not available") +@pytest.mark.developer("dev-force-features, dev-disconnect required") +def test_upgrade_statickey_fail(node_factory, executor, bitcoind): + """We reconnect at all points during retransmit, and we won't upgrade.""" + l1_disconnects = ['-WIRE_COMMITMENT_SIGNED', + '-WIRE_REVOKE_AND_ACK'] + l2_disconnects = ['-WIRE_REVOKE_AND_ACK', + '-WIRE_COMMITMENT_SIGNED', + '=WIRE_UPDATE_FAIL_HTLC-nocommit'] + + l1, l2 = node_factory.line_graph(2, opts=[{'may_reconnect': True, + 'dev-no-reconnect': None, + 'disconnect': l1_disconnects, + 'dev-force-features': ["-13", "-21"], + # Don't have feerate changes! + 'feerates': (7500, 7500, 7500, 7500)}, + {'may_reconnect': True, + 'dev-no-reconnect': None, + 'disconnect': l2_disconnects}]) + + # This HTLC will fail + l1.rpc.sendpay([{'msatoshi': 1000, 'id': l2.info['id'], 'delay': 5, 'channel': '1x1x1'}], '00' * 32) + + # Each one should cause one disconnection, no upgrade. + for d in l1_disconnects + l2_disconnects[:-1]: + l1.daemon.wait_for_log('Peer connection lost') + l2.daemon.wait_for_log('Peer connection lost') + assert not l1.daemon.is_in_log('option_static_remotekey enabled') + assert not l2.daemon.is_in_log('option_static_remotekey enabled') + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + + # On the last reconnect, it retransmitted revoke_and_ack. + l1.daemon.wait_for_log('No upgrade: we retransmitted') + l2.daemon.wait_for_log('No upgrade: pending changes') + + # Now when we reconnect, despite having an HTLC, we're quiescent. + l1.rpc.disconnect(l2.info['id'], force=True) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + + l1.daemon.wait_for_log('option_static_remotekey enabled at 2/2') + l2.daemon.wait_for_log('option_static_remotekey enabled at 2/2') + + @unittest.skipIf(not EXPERIMENTAL_FEATURES, "quiescence is experimental") @pytest.mark.developer("quiescence triggering is dev only") def test_quiescence(node_factory, executor):